diff --git a/.eslintrc.json b/.eslintrc.json index 8e999412..0c30d3c8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,9 @@ { "root": true, "extends": ["b2b"], + "ignorePatterns": [ + "/apps/storefront/src/utils/b3DateFormat/php-date-format.ts" + ], "settings": { "import/resolver": { "typescript": { diff --git a/apps/storefront/src/components/B3ProductList.tsx b/apps/storefront/src/components/B3ProductList.tsx index 5dee74f9..7b38990e 100644 --- a/apps/storefront/src/components/B3ProductList.tsx +++ b/apps/storefront/src/components/B3ProductList.tsx @@ -17,6 +17,7 @@ import { noop } from 'lodash' import { PRODUCT_DEFAULT_IMAGE } from '@/constants' import { useMobile } from '@/hooks' +import { currencyFormat } from '@/utils' import { ProductItem } from '../types' @@ -133,7 +134,6 @@ interface ProductProps { export default function B3ProductList(props: ProductProps) { const { products, - currency = '$', renderAction, quantityKey = 'quantity', actionWidth = '100px', @@ -151,19 +151,13 @@ export default function B3ProductList(props: ProductProps) { const [isMobile] = useMobile() - const getProductPrice = (price: string | number) => { - const priceNumber = parseFloat(price.toString()) || 0 - - return priceNumber.toFixed(2) - } - const getQuantity = (product: any) => parseInt(product[quantityKey]?.toString() || '', 10) || '' const getProductTotals = (quantity: number, price: string | number) => { const priceNumber = parseFloat(price.toString()) || 0 - return (quantity * priceNumber).toFixed(2) + return quantity * priceNumber } const handleProductQuantityChange = @@ -333,7 +327,7 @@ export default function B3ProductList(props: ProductProps) { {...itemStyle.default} > {isMobile && Price:} - {`${currency} ${getProductPrice(productPrice)}`} + {`${currencyFormat(productPrice)}`} @@ -372,9 +366,8 @@ export default function B3ProductList(props: ProductProps) { textAlignLocation={textAlign} > {isMobile && {totalText}:} - {`${currency} ${getProductTotals( - getQuantity(product) || 0, - productPrice + {`${currencyFormat( + getProductTotals(getQuantity(product) || 0, productPrice) )}`} diff --git a/apps/storefront/src/components/B3StoreContainer.tsx b/apps/storefront/src/components/B3StoreContainer.tsx index 3fc207d6..63fc277b 100644 --- a/apps/storefront/src/components/B3StoreContainer.tsx +++ b/apps/storefront/src/components/B3StoreContainer.tsx @@ -42,6 +42,7 @@ export function B3StoreContainer(props: B3StoreContainerProps) { try { const { storeBasicInfo }: CustomFieldItems = await getBCStoreChannelId() + B3SStorage.set('timeFormat', storeBasicInfo.timeFormat) const { channelId, b3ChannelId: b2bChannelId, @@ -57,6 +58,7 @@ export function B3StoreContainer(props: B3StoreContainerProps) { currentChannelId: channelId, b2bChannelId, storeName: storeBasicInfo.storeName, + timeFormat: storeBasicInfo.timeFormat, }, }) diff --git a/apps/storefront/src/components/outSideComponents/B3HoverButton.tsx b/apps/storefront/src/components/outSideComponents/B3HoverButton.tsx index 593a82d0..64ee7ae4 100644 --- a/apps/storefront/src/components/outSideComponents/B3HoverButton.tsx +++ b/apps/storefront/src/components/outSideComponents/B3HoverButton.tsx @@ -46,7 +46,7 @@ export default function B3HoverButton(props: B3HoverButtonProps) { text = '', color = '', customCss = '', - location = '', + location = 'bottomRight', horizontalPadding = '', verticalPadding = '', enabled = false, diff --git a/apps/storefront/src/components/outSideComponents/B3MasquradeGobalTip.tsx b/apps/storefront/src/components/outSideComponents/B3MasquradeGobalTip.tsx index f8d16d4e..3a8b301d 100644 --- a/apps/storefront/src/components/outSideComponents/B3MasquradeGobalTip.tsx +++ b/apps/storefront/src/components/outSideComponents/B3MasquradeGobalTip.tsx @@ -89,7 +89,7 @@ export default function B3MasquradeGobalTip(props: B3MasquradeGobalTipProps) { text = '', color = '', customCss = '', - location = '', + location = 'bottomLeft', horizontalPadding = '', verticalPadding = '', } = masqueradeButton diff --git a/apps/storefront/src/pages/order/Order.tsx b/apps/storefront/src/pages/order/Order.tsx index 4c9b7cde..b5beb80c 100644 --- a/apps/storefront/src/pages/order/Order.tsx +++ b/apps/storefront/src/pages/order/Order.tsx @@ -1,7 +1,6 @@ import { useContext, useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' import { Box } from '@mui/material' -import { format } from 'date-fns' import { B3Sping } from '@/components' import { B3PaginationTable } from '@/components/table/B3PaginationTable' @@ -14,12 +13,12 @@ import { getOrdersCreatedByUser, getOrderStatusType, } from '@/shared/service/b2b' +import { currencyFormat, displayFormat } from '@/utils' import B3Filter from '../../components/filter/B3Filter' import OrderStatus from './components/OrderStatus' import { - currencySymbol, FilterSearchProps, getFilterMoreData, getInitFilter, @@ -178,8 +177,7 @@ function Order({ isCompanyOrder = false }: OrderProps) { { key: 'totalIncTax', title: 'Grand total', - render: (item: ListItem) => - `${currencySymbol(item.money)}${item.totalIncTax}`, + render: (item: ListItem) => `${currencyFormat(item.totalIncTax)}`, width: '8%', style: { textAlign: 'right', @@ -205,7 +203,7 @@ function Order({ isCompanyOrder = false }: OrderProps) { { key: 'createdAt', title: 'Created on', - render: (item: ListItem) => format(+item.createdAt * 1000, 'dd MMM yyyy'), + render: (item: ListItem) => `${displayFormat(+item.createdAt)}`, width: '10%', }, { diff --git a/apps/storefront/src/pages/order/OrderItemCard.tsx b/apps/storefront/src/pages/order/OrderItemCard.tsx index f2e22bab..c511804d 100644 --- a/apps/storefront/src/pages/order/OrderItemCard.tsx +++ b/apps/storefront/src/pages/order/OrderItemCard.tsx @@ -6,12 +6,11 @@ import Box from '@mui/material/Box' import Card from '@mui/material/Card' import CardContent from '@mui/material/CardContent' import Typography from '@mui/material/Typography' -import { format } from 'date-fns' import { GlobaledContext } from '@/shared/global' +import { currencyFormat, displayFormat } from '@/utils' import OrderStatus from './components/OrderStatus' -import { currencySymbol } from './config' interface ListItem { [key: string]: string @@ -107,8 +106,7 @@ export function OrderItemCard(props: OrderItemCardProps) { minHeight: '1.43em', }} > - {currencySymbol(item.money)} - {item.totalIncTax} + {currencyFormat(item.totalIncTax)} {getName(item)} - - {format(+item.createdAt * 1000, 'dd MMM yyyy')} - + {`${displayFormat(item.createdAt)}`} diff --git a/apps/storefront/src/pages/orderDetail/components/OrderAction.tsx b/apps/storefront/src/pages/orderDetail/components/OrderAction.tsx index 5fab6627..bc984583 100644 --- a/apps/storefront/src/pages/orderDetail/components/OrderAction.tsx +++ b/apps/storefront/src/pages/orderDetail/components/OrderAction.tsx @@ -1,12 +1,11 @@ import { Fragment, ReactNode, useContext, useState } from 'react' import styled from '@emotion/styled' import { Box, Card, CardContent, Divider, Typography } from '@mui/material' -import { format } from 'date-fns' import { throttle } from 'lodash' import { CustomButton } from '@/components' import { GlobaledContext } from '@/shared/global' -import { b2bPrintInvoice, snackbar } from '@/utils' +import { b2bPrintInvoice, displayFormat, snackbar } from '@/utils' import { Address, OrderCurrency, OrderProductItem } from '../../../types' import { @@ -78,7 +77,6 @@ interface OrderCardProps { products: OrderProductItem[] itemKey: string orderId: string - currencyInfo: OrderCurrency role: number | string } @@ -90,17 +88,8 @@ interface DialogData { } function OrderCard(props: OrderCardProps) { - const { - header, - subtitle, - buttons, - infos, - products, - itemKey, - orderId, - currencyInfo, - role, - } = props + const { header, subtitle, buttons, infos, products, itemKey, orderId, role } = + props const { state: { isAgenting }, @@ -236,7 +225,6 @@ function OrderCard(props: OrderCardProps) { type={type} setOpen={setOpen} itemKey={itemKey} - currencyInfo={currencyInfo} /> ) @@ -364,10 +352,7 @@ export default function OrderAction(props: OrderActionProps) { key: 'order-summary', subtitle: updatedAt && name - ? `Purchased by ${name} on ${format( - +updatedAt * 1000, - 'dd MMM yyyy' - )}.` + ? `Purchased by ${name} on ${displayFormat(+updatedAt)}.` : '', buttons, infos: { @@ -379,7 +364,7 @@ export default function OrderAction(props: OrderActionProps) { header: 'Payment', key: 'payment', subtitle: createAt - ? `Paid in full on ${format(Date.parse(createAt), 'dd MMM yyyy')}.` + ? `Paid in full on ${displayFormat(createAt, true)}.` : '', buttons: [ { @@ -413,7 +398,6 @@ export default function OrderAction(props: OrderActionProps) { number onProductChange?: (products: EditableProductItem[]) => void setCheckedArr?: (items: number[]) => void @@ -127,7 +123,6 @@ const mobileItemStyle = { export default function OrderCheckboxProduct(props: OrderCheckboxProductProps) { const { products, - currencyInfo, getProductQuantity = (item) => item.editQuantity, onProductChange = () => {}, setCheckedArr = () => {}, @@ -138,12 +133,6 @@ export default function OrderCheckboxProduct(props: OrderCheckboxProductProps) { const [list, setList] = useState([]) - const getProductPrice = (price: string | number) => { - const priceNumber = parseFloat(price.toString()) || 0 - - return priceNumber.toFixed(2) - } - const getProductTotals = ( quantity: string | number, price: string | number @@ -151,7 +140,7 @@ export default function OrderCheckboxProduct(props: OrderCheckboxProductProps) { const priceNumber = parseFloat(price.toString()) || 0 const quantityNumber = parseInt(quantity.toString(), 10) || 0 - return (quantityNumber * priceNumber).toFixed(2) + return quantityNumber * priceNumber } const itemStyle = isMobile ? mobileItemStyle : defaultItemStyle @@ -276,9 +265,7 @@ export default function OrderCheckboxProduct(props: OrderCheckboxProductProps) { {...itemStyle.default} > {isMobile && Price: } - {`${currencyInfo.currency_token} ${getProductPrice( - product.base_price - )}`} + {`${currencyFormat(product.base_price)}`} {isMobile && Total: } - {`${currencyInfo.currency_token} ${getProductTotals( - getProductQuantity(product), - product.base_price + {`${currencyFormat( + getProductTotals(getProductQuantity(product), product.base_price) )}`} diff --git a/apps/storefront/src/pages/orderDetail/components/OrderDialog.tsx b/apps/storefront/src/pages/orderDetail/components/OrderDialog.tsx index f743274d..01b4073d 100644 --- a/apps/storefront/src/pages/orderDetail/components/OrderDialog.tsx +++ b/apps/storefront/src/pages/orderDetail/components/OrderDialog.tsx @@ -16,7 +16,6 @@ import { snackbar } from '@/utils' import { EditableProductItem, - OrderCurrency, OrderProductItem, } from '../../../types' import getReturnFormFields from '../shared/config' @@ -39,7 +38,6 @@ interface OrderDialogProps { type?: string currentDialogData?: DialogData itemKey: string - currencyInfo: OrderCurrency } export default function OrderDialog({ @@ -49,7 +47,6 @@ export default function OrderDialog({ currentDialogData = undefined, setOpen, itemKey, - currencyInfo, }: OrderDialogProps) { const { state: { isB2BUser }, @@ -351,7 +348,6 @@ export default function OrderDialog({ diff --git a/apps/storefront/src/pages/quickorder/components/QuickOrderCard.tsx b/apps/storefront/src/pages/quickorder/components/QuickOrderCard.tsx index 917a0a57..a1be0210 100644 --- a/apps/storefront/src/pages/quickorder/components/QuickOrderCard.tsx +++ b/apps/storefront/src/pages/quickorder/components/QuickOrderCard.tsx @@ -1,12 +1,11 @@ import { ReactElement } from 'react' import { Box, CardContent, styled, TextField, Typography } from '@mui/material' -import { format } from 'date-fns' import { PRODUCT_DEFAULT_IMAGE } from '@/constants' +import { currencyFormat, displayFormat } from '@/utils' interface QuickOrderCardProps { item: any - currencyToken: string checkBox?: () => ReactElement handleUpdateProductQty: (id: number, val: string) => void } @@ -18,12 +17,7 @@ const StyledImage = styled('img')(() => ({ })) function QuickOrderCard(props: QuickOrderCardProps) { - const { - item: shoppingDetail, - checkBox, - handleUpdateProductQty, - currencyToken = '$', - } = props + const { item: shoppingDetail, checkBox, handleUpdateProductQty } = props const { quantity, @@ -92,10 +86,7 @@ function QuickOrderCard(props: QuickOrderCardProps) { )} - {`Price: ${currencyToken}${price.toFixed( - 2 - )}`} - + {`Price: ${currencyFormat(price)}`} - {`Last ordered: ${format( - lastOrderedAt * 1000, - 'dd MMM yyyy' + {`Last ordered: ${displayFormat( + lastOrderedAt )}`} diff --git a/apps/storefront/src/pages/quickorder/components/QuickOrderFooter.tsx b/apps/storefront/src/pages/quickorder/components/QuickOrderFooter.tsx index efb53b46..e36e35c5 100644 --- a/apps/storefront/src/pages/quickorder/components/QuickOrderFooter.tsx +++ b/apps/storefront/src/pages/quickorder/components/QuickOrderFooter.tsx @@ -26,7 +26,7 @@ import { import { addProductToCart, createCart, getCartInfo } from '@/shared/service/bc' import { addQuoteDraftProduce, - getDefaultCurrencyInfo, + currencyFormat, getProductPriceIncTax, snackbar, } from '@/utils' @@ -137,8 +137,6 @@ function QuickOrderFooter(props: QuickOrderFooterProps) { setOpen(false) } - const { token: currencyToken } = getDefaultCurrencyInfo() - // Add selected to cart const handleSetCartLineItems = (inventoryInfos: ProductsProps[]) => { const lineItems: CustomFieldItems = [] @@ -579,7 +577,7 @@ function QuickOrderFooter(props: QuickOrderFooterProps) { color: '#000000', }} > - {`Subtotal: ${currencyToken}${selectedSubTotal.toFixed(2)}`} + {`Subtotal: ${currencyFormat(selectedSubTotal)}`} { if (listProducts.length > 0) { @@ -191,7 +191,7 @@ function QuickorderTable({ orderedProducts: { edges, totalCount }, } = await fn(params) - const listProducts = handleGetProductsById(edges) + const listProducts = await handleGetProductsById(edges) setTotalCount(totalCount) @@ -340,7 +340,7 @@ function QuickorderTable({ padding: '12px 0', }} > - {`${currencyToken}${price.toFixed(2)}`} + {`${currencyFormat(price)}`} ) }, @@ -382,7 +382,7 @@ function QuickorderTable({ padding: '12px 0', }} > - {format(+row.lastOrderedAt * 1000, 'dd MMM yyyy')} + {`${displayFormat(+row.lastOrderedAt)}`} ), @@ -501,7 +501,6 @@ function QuickorderTable({ )} diff --git a/apps/storefront/src/pages/quote/QuoteDetail.tsx b/apps/storefront/src/pages/quote/QuoteDetail.tsx index dfc522c2..4d9a9428 100644 --- a/apps/storefront/src/pages/quote/QuoteDetail.tsx +++ b/apps/storefront/src/pages/quote/QuoteDetail.tsx @@ -45,7 +45,6 @@ function QuoteDetail() { const [quoteDetail, setQuoteDetail] = useState({}) const [productList, setProductList] = useState([]) - const [currency, setCurrency] = useState({}) const [fileList, setFileList] = useState([]) const [quoteSummary, setQuoteSummary] = useState({ @@ -127,7 +126,6 @@ function QuoteDetail() { shipping: quote.shippingTotal, grandTotal: quote.totalAmount, }) - setCurrency(quote.currency) setProductList(productsWithMoreInfo) const { backendAttachFiles = [], storefrontAttachFiles = [] } = quote @@ -383,7 +381,6 @@ function QuoteDetail() { } > @@ -411,7 +408,6 @@ function QuoteDetail() { > diff --git a/apps/storefront/src/pages/quote/QuoteDraft.tsx b/apps/storefront/src/pages/quote/QuoteDraft.tsx index 5015c977..e7536286 100644 --- a/apps/storefront/src/pages/quote/QuoteDraft.tsx +++ b/apps/storefront/src/pages/quote/QuoteDraft.tsx @@ -293,7 +293,7 @@ function QuoteDraft({ setOpenPage }: QuoteDraftProps) { setEdit(true) } - const { token: currencyToken, currency_code: currencyCode } = + const { currency_code: currencyCode } = getDefaultCurrencyInfo() const handleGetProductsById = async (listProducts: ListItemProps[]) => { @@ -792,7 +792,6 @@ function QuoteDraft({ setOpenPage }: QuoteDraftProps) { ref={quoteTableRef} updateSummary={updateSummary} total={total} - currencyToken={currencyToken} getQuoteTableDetails={getQuoteTableDetails} isB2BUser={isB2BUser} /> @@ -816,7 +815,6 @@ function QuoteDraft({ setOpenPage }: QuoteDraftProps) { > ) => { const fn = isB2BUser ? getB2BQuotesList : getBCQuotesList const key = isB2BUser ? 'quotes' : 'customerQuotes' @@ -237,9 +234,6 @@ function QuotesList() { createdBy: `${customer.firstName} ${customer.lastName}`, updatedAt: '—', expiredAt: '—', - currency: { - token: currencyToken, - }, totalAmount: summaryPrice?.subtotal, status: 0, taxTotal: summaryPrice?.tax, @@ -299,9 +293,7 @@ function QuotesList() { title: 'Date created', render: (item: ListItem) => `${ - +item.status !== 0 - ? format(+item.createdAt * 1000, 'dd MMM yyyy') - : item.createdAt + +item.status !== 0 ? displayFormat(+item.createdAt) : item.createdAt }`, }, { @@ -309,9 +301,7 @@ function QuotesList() { title: 'Last update', render: (item: ListItem) => `${ - +item.status !== 0 - ? format(+item.updatedAt * 1000, 'dd MMM yyyy') - : item.updatedAt + +item.status !== 0 ? displayFormat(+item.updatedAt) : item.updatedAt }`, }, { @@ -319,22 +309,16 @@ function QuotesList() { title: 'Expiration date', render: (item: ListItem) => `${ - +item.status !== 0 - ? format(+item.expiredAt * 1000, 'dd MMM yyyy') - : item.expiredAt + +item.status !== 0 ? displayFormat(+item.expiredAt) : item.expiredAt }`, }, { key: 'totalAmount', title: 'Subtotal', render: (item: ListItem) => { - const { - currency: { token }, - totalAmount, - taxTotal, - } = item + const { totalAmount, taxTotal } = item - return `${token}${(+totalAmount + +taxTotal).toFixed(2)}` + return `${currencyFormat(+totalAmount + +taxTotal)}` }, style: { textAlign: 'right', diff --git a/apps/storefront/src/pages/quote/components/Message.tsx b/apps/storefront/src/pages/quote/components/Message.tsx index a5ccbd32..8b089e32 100644 --- a/apps/storefront/src/pages/quote/components/Message.tsx +++ b/apps/storefront/src/pages/quote/components/Message.tsx @@ -11,7 +11,7 @@ import { format, formatDistanceStrict } from 'date-fns' import { B3CollapseContainer, B3Sping } from '@/components' import { updateB2BQuote, updateBCQuote } from '@/shared/service/b2b' -import { storeHash } from '@/utils' +import { displayExtendedFormat, storeHash } from '@/utils' interface MessageProps { date?: number @@ -121,7 +121,7 @@ function DateMessage({ msg }: DateMessageProps) { mb: '5px', }} > - {format((msg?.date || 0) * 1000, 'MMMM dd uuuu, K:m aa')} + {`${displayExtendedFormat(msg?.date || 0)}`} ) } diff --git a/apps/storefront/src/pages/quote/components/QuoteDetailHeader.tsx b/apps/storefront/src/pages/quote/components/QuoteDetailHeader.tsx index 6e2cad19..9b4fd811 100644 --- a/apps/storefront/src/pages/quote/components/QuoteDetailHeader.tsx +++ b/apps/storefront/src/pages/quote/components/QuoteDetailHeader.tsx @@ -1,10 +1,10 @@ import { useNavigate } from 'react-router-dom' import { ArrowBackIosNew } from '@mui/icons-material' import { Box, Grid, styled, Typography, useTheme } from '@mui/material' -import { format } from 'date-fns' import { CustomButton } from '@/components' import { useMobile } from '@/hooks' +import { displayFormat } from '@/utils' import QuoteStatus from './QuoteStatus' @@ -130,9 +130,7 @@ function QuoteDetailHeader(props: QuoteDetailHeaderProps) { > Issued on: - {`${ - issuedAt ? format(+issuedAt * 1000, 'dd MMM yyyy') : '' - }`} + {`${issuedAt ? displayFormat(+issuedAt) : ''}`} {`${ - expirationDate - ? format(+expirationDate * 1000, 'dd MMM yyyy') - : '' + expirationDate ? displayFormat(+expirationDate) : '' }`} diff --git a/apps/storefront/src/pages/quote/components/QuoteDetailSummary.tsx b/apps/storefront/src/pages/quote/components/QuoteDetailSummary.tsx index bb479824..d0bc0c13 100644 --- a/apps/storefront/src/pages/quote/components/QuoteDetailSummary.tsx +++ b/apps/storefront/src/pages/quote/components/QuoteDetailSummary.tsx @@ -1,5 +1,7 @@ import { Box, Card, CardContent, Grid, Typography } from '@mui/material' +import { currencyFormat } from '@/utils' + interface Summary { originalSubtotal: string | number discount: string | number @@ -8,23 +10,17 @@ interface Summary { grandTotal: string | number } -interface Currency { - token: string -} - interface QuoteDetailSummaryProps { quoteSummary: Summary - currency: Currency } export default function QuoteDetailSummary(props: QuoteDetailSummaryProps) { const { quoteSummary: { originalSubtotal, discount, tax, shipping, grandTotal }, - currency, } = props const priceFormat = (price: number) => - `${currency?.token || '$'} ${price.toFixed(2)}` + `${currencyFormat(price)}` const quotedSubtotal = +originalSubtotal - +discount return ( diff --git a/apps/storefront/src/pages/quote/components/QuoteDetailTable.tsx b/apps/storefront/src/pages/quote/components/QuoteDetailTable.tsx index 0f330fb2..b599f15a 100644 --- a/apps/storefront/src/pages/quote/components/QuoteDetailTable.tsx +++ b/apps/storefront/src/pages/quote/components/QuoteDetailTable.tsx @@ -4,7 +4,7 @@ import { Box, styled, Typography } from '@mui/material' import { B3PaginationTable } from '@/components/table/B3PaginationTable' import { TableColumnItem } from '@/components/table/B3Table' import { PRODUCT_DEFAULT_IMAGE } from '@/constants' -import { getProductPriceIncTax } from '@/utils' +import { currencyFormat, getProductPriceIncTax } from '@/utils' import QuoteDetailTableCard from './QuoteDetailTableCard' @@ -40,7 +40,6 @@ interface ListItemProps { interface ShoppingDetailTableProps { total: number - currencyToken?: string getQuoteTableDetails: any } @@ -91,7 +90,7 @@ const StyledImage = styled('img')(() => ({ })) function QuoteDetailTable(props: ShoppingDetailTableProps, ref: Ref) { - const { total, currencyToken, getQuoteTableDetails } = props + const { total, getQuoteTableDetails } = props const paginationTableRef = useRef(null) @@ -203,7 +202,7 @@ function QuoteDetailTable(props: ShoppingDetailTableProps, ref: Ref) { textDecoration: 'line-through', }} > - {`${currencyToken}${withTaxPrice.toFixed(2)}`} + {`${currencyFormat(withTaxPrice)}`} )} @@ -213,7 +212,7 @@ function QuoteDetailTable(props: ShoppingDetailTableProps, ref: Ref) { color: isDiscount ? '#2E7D32' : '#212121', }} > - {`${currencyToken}${(+withTaxPrice - +isDiscount).toFixed(2)}`} + {`${currencyFormat((+withTaxPrice - +isDiscount))}`} ) @@ -274,7 +273,7 @@ function QuoteDetailTable(props: ShoppingDetailTableProps, ref: Ref) { textDecoration: 'line-through', }} > - {`${currencyToken}${total.toFixed(2)}`} + {`${currencyFormat(total)}`} )} ) { color: isDiscount ? '#2E7D32' : '#212121', }} > - {`${currencyToken}${totalWithDiscount.toFixed(2)}`} + {`${currencyFormat(totalWithDiscount)}`} ) @@ -332,7 +331,6 @@ function QuoteDetailTable(props: ShoppingDetailTableProps, ref: Ref) { len={total || 0} item={row} itemIndex={index} - currencyToken={currencyToken || '$'} /> )} /> diff --git a/apps/storefront/src/pages/quote/components/QuoteDetailTableCard.tsx b/apps/storefront/src/pages/quote/components/QuoteDetailTableCard.tsx index bf21d0c4..41d59d6a 100644 --- a/apps/storefront/src/pages/quote/components/QuoteDetailTableCard.tsx +++ b/apps/storefront/src/pages/quote/components/QuoteDetailTableCard.tsx @@ -1,11 +1,10 @@ import { Box, CardContent, styled, Typography } from '@mui/material' import { PRODUCT_DEFAULT_IMAGE } from '@/constants' -import { getProductPriceIncTax } from '@/utils' +import { currencyFormat, getProductPriceIncTax } from '@/utils' interface QuoteTableCardProps { item: any - currencyToken?: string len: number itemIndex?: number } @@ -17,7 +16,7 @@ const StyledImage = styled('img')(() => ({ })) function QuoteDetailTableCard(props: QuoteTableCardProps) { - const { item: quoteTableItem, currencyToken = '$', len, itemIndex } = props + const { item: quoteTableItem, len, itemIndex } = props const { basePrice, @@ -114,7 +113,7 @@ function QuoteDetailTableCard(props: QuoteTableCardProps) { textDecoration: 'line-through', }} > - {`${currencyToken}${withTaxPrice.toFixed(2)}`} + {`${currencyFormat(withTaxPrice)}`} )} - {`${currencyToken}${(+withTaxPrice - +isDiscount).toFixed(2)}`} + {`${currencyFormat((+withTaxPrice - +isDiscount))}`} @@ -144,7 +143,7 @@ function QuoteDetailTableCard(props: QuoteTableCardProps) { textDecoration: 'line-through', }} > - {`${currencyToken}${total.toFixed(2)}`} + {`${currencyFormat(total)}`} )} - {`${currencyToken}${totalWithDiscount.toFixed(2)}`} + {`${currencyFormat(totalWithDiscount)}`} diff --git a/apps/storefront/src/pages/quote/components/QuoteItemCard.tsx b/apps/storefront/src/pages/quote/components/QuoteItemCard.tsx index 09f161d5..723fabd5 100644 --- a/apps/storefront/src/pages/quote/components/QuoteItemCard.tsx +++ b/apps/storefront/src/pages/quote/components/QuoteItemCard.tsx @@ -3,9 +3,9 @@ import Box from '@mui/material/Box' import Card from '@mui/material/Card' import CardContent from '@mui/material/CardContent' import Typography from '@mui/material/Typography' -import { format } from 'date-fns' import { TableColumnItem } from '@/components/table/B3Table' +import { currencyFormat, displayFormat } from '@/utils' import QuoteStatus from './QuoteStatus' @@ -13,9 +13,6 @@ interface ListItem { [key: string]: string | Object status: string quoteNumber: string - currency: { - token: string - } } export interface QuoteItemCardProps { @@ -51,9 +48,7 @@ export function QuoteItemCard(props: QuoteItemCardProps) { title: 'Date created', render: () => `${ - +item.status !== 0 - ? format(+item.createdAt * 1000, 'dd MMM yyyy') - : item.createdAt + +item.status !== 0 ? displayFormat(+item.createdAt) : item.createdAt }`, }, { @@ -61,9 +56,7 @@ export function QuoteItemCard(props: QuoteItemCardProps) { title: 'Last update', render: () => `${ - +item.status !== 0 - ? format(+item.updatedAt * 1000, 'dd MMM yyyy') - : item.updatedAt + +item.status !== 0 ? displayFormat(+item.updatedAt) : item.updatedAt }`, }, { @@ -71,21 +64,16 @@ export function QuoteItemCard(props: QuoteItemCardProps) { title: 'Expiration date', render: () => `${ - +item.status !== 0 - ? format(+item.expiredAt * 1000, 'dd MMM yyyy') - : item.expiredAt + +item.status !== 0 ? displayFormat(+item.expiredAt) : item.expiredAt }`, }, { key: 'totalAmount', title: 'Subtotal', render: () => { - const { - currency: { token }, - totalAmount, - } = item + const { totalAmount } = item - return `${token}${(+totalAmount).toFixed(2)}` + return `${currencyFormat(+totalAmount)}` }, }, ] diff --git a/apps/storefront/src/pages/quote/components/QuoteSummary.tsx b/apps/storefront/src/pages/quote/components/QuoteSummary.tsx index 84a9f4cf..5e7bc829 100644 --- a/apps/storefront/src/pages/quote/components/QuoteSummary.tsx +++ b/apps/storefront/src/pages/quote/components/QuoteSummary.tsx @@ -7,11 +7,7 @@ import { } from 'react' import { Box, Card, CardContent, Grid, Typography } from '@mui/material' -import { B3LStorage } from '@/utils' - -interface QuoteSummaryProps { - currencyToken?: string -} +import { B3LStorage, currencyFormat } from '@/utils' interface Summary { subtotal: number @@ -27,149 +23,144 @@ const defaultSummary: Summary = { grandTotal: 0, } -const QuoteSummary = forwardRef( - (props: QuoteSummaryProps, ref: Ref) => { - const { currencyToken = '$' } = props +const QuoteSummary = forwardRef((_, ref: Ref) => { + const [quoteSummary, setQuoteSummary] = useState({ + ...defaultSummary, + }) - const [quoteSummary, setQuoteSummary] = useState({ - ...defaultSummary, - }) + const priceCalc = (price: number) => parseFloat(price.toFixed(2)) - const priceCalc = (price: number) => parseFloat(price.toFixed(2)) + const getSummary = () => { + const productList = B3LStorage.get('b2bQuoteDraftList') || [] - const getSummary = () => { - const productList = B3LStorage.get('b2bQuoteDraftList') || [] + const newQuoteSummary = productList.reduce( + (summary: Summary, product: CustomFieldItems) => { + const { + basePrice, + tax: productTax, + quantity, + additionalCalculatedPrices = [], + } = product.node - const newQuoteSummary = productList.reduce( - (summary: Summary, product: CustomFieldItems) => { - const { - basePrice, - tax: productTax, - quantity, - additionalCalculatedPrices = [], - } = product.node + let { subtotal, grandTotal, tax } = summary - let { subtotal, grandTotal, tax } = summary + const { shipping } = summary - const { shipping } = summary + let additionalCalculatedPriceTax = 0 - let additionalCalculatedPriceTax = 0 + let additionalCalculatedPrice = 0 - let additionalCalculatedPrice = 0 + additionalCalculatedPrices.forEach((item: CustomFieldItems) => { + additionalCalculatedPriceTax += item.additionalCalculatedPriceTax + additionalCalculatedPrice += item.additionalCalculatedPrice + }) - additionalCalculatedPrices.forEach((item: CustomFieldItems) => { - additionalCalculatedPriceTax += item.additionalCalculatedPriceTax - additionalCalculatedPrice += item.additionalCalculatedPrice - }) + subtotal += priceCalc( + (+basePrice + additionalCalculatedPrice) * quantity + ) + tax += priceCalc( + (+productTax + additionalCalculatedPriceTax) * quantity + ) - subtotal += priceCalc( - (+basePrice + additionalCalculatedPrice) * quantity - ) - tax += priceCalc( - (+productTax + additionalCalculatedPriceTax) * quantity - ) + grandTotal = subtotal + shipping - grandTotal = subtotal + shipping - - return { - grandTotal, - shipping, - tax, - subtotal, - } - }, - { - ...defaultSummary, + return { + grandTotal, + shipping, + tax, + subtotal, } - ) - - setQuoteSummary(newQuoteSummary) - } - - useEffect(() => { - getSummary() - }, []) + }, + { + ...defaultSummary, + } + ) - useImperativeHandle(ref, () => ({ - refreshSummary: () => getSummary(), - })) + setQuoteSummary(newQuoteSummary) + } - const priceFormat = (price: number) => - `${currencyToken} ${price.toFixed(2)}` + useEffect(() => { + getSummary() + }, []) + + useImperativeHandle(ref, () => ({ + refreshSummary: () => getSummary(), + })) + + const priceFormat = (price: number) => `${currencyFormat(price)}` + + return ( + + + + Quote summary + + + Sub total + + {priceFormat(quoteSummary.subtotal + +quoteSummary.tax)} + + + + + Shipping + {priceFormat(quoteSummary.shipping)} + - return ( - - - - Quote summary - - - Sub total - - {priceFormat(quoteSummary.subtotal + +quoteSummary.tax)} - - - - - Shipping - {priceFormat(quoteSummary.shipping)} - + Tax + {priceFormat(quoteSummary.tax)} + - + - Tax - {priceFormat(quoteSummary.tax)} - - - + - - Grand total - - - {priceFormat(quoteSummary.grandTotal + +quoteSummary.tax)} - - - + {priceFormat(quoteSummary.grandTotal + +quoteSummary.tax)} + + - - - ) - } -) + + + + ) +}) export default QuoteSummary diff --git a/apps/storefront/src/pages/quote/components/QuoteTable.tsx b/apps/storefront/src/pages/quote/components/QuoteTable.tsx index 8fd2753b..3d57e31d 100644 --- a/apps/storefront/src/pages/quote/components/QuoteTable.tsx +++ b/apps/storefront/src/pages/quote/components/QuoteTable.tsx @@ -7,6 +7,7 @@ import { TableColumnItem } from '@/components/table/B3Table' import { PRODUCT_DEFAULT_IMAGE } from '@/constants' import { B3LStorage, + currencyFormat, getModifiersPrice, getProductPriceIncTax, getQuickAddProductExtraPrice, @@ -49,7 +50,6 @@ interface ListItemProps { interface ShoppingDetailTableProps { total: number - currencyToken?: string getQuoteTableDetails: any idEdit?: boolean isB2BUser: boolean @@ -105,7 +105,6 @@ const StyledTextField = styled(TextField)(() => ({ function QuoteTable(props: ShoppingDetailTableProps, ref: Ref) { const { total, - currencyToken, getQuoteTableDetails, idEdit = true, isB2BUser, @@ -380,7 +379,7 @@ function QuoteTable(props: ShoppingDetailTableProps, ref: Ref) { padding: '12px 0', }} > - {`${currencyToken}${withTaxPrice.toFixed(2)}`} + {`${currencyFormat(withTaxPrice)}`} ) }, @@ -440,7 +439,7 @@ function QuoteTable(props: ShoppingDetailTableProps, ref: Ref) { padding: '12px 0', }} > - {`${currencyToken}${total.toFixed(2)}`} + {`${currencyFormat(total)}`} ) { itemIndex={index} onEdit={handleOpenProductEdit} onDelete={handleDeleteClick} - currencyToken={currencyToken || '$'} handleUpdateProductQty={handleUpdateProductQty} idEdit={idEdit} /> @@ -546,7 +544,6 @@ function QuoteTable(props: ShoppingDetailTableProps, ref: Ref) { product={optionsProduct} onCancel={handleChooseOptionsDialogCancel} onConfirm={handleChooseOptionsDialogConfirm} - currency={currencyToken} isEdit isB2BUser={isB2BUser} /> diff --git a/apps/storefront/src/pages/quote/components/QuoteTableCard.tsx b/apps/storefront/src/pages/quote/components/QuoteTableCard.tsx index e09c4466..6854edb1 100644 --- a/apps/storefront/src/pages/quote/components/QuoteTableCard.tsx +++ b/apps/storefront/src/pages/quote/components/QuoteTableCard.tsx @@ -2,7 +2,7 @@ import { Delete, Edit } from '@mui/icons-material' import { Box, CardContent, styled, TextField, Typography } from '@mui/material' import { PRODUCT_DEFAULT_IMAGE } from '@/constants' -import { getProductPriceIncTax } from '@/utils' +import { currencyFormat, getProductPriceIncTax } from '@/utils' import { getProductOptionsFields } from '../../../utils/b3Product/shared/config' @@ -10,7 +10,6 @@ interface QuoteTableCardProps { item: any onEdit: (item: any, itemId: number | string) => void onDelete: (id: string) => void - currencyToken?: string handleUpdateProductQty: (id: number | string, value: number | string) => void idEdit: boolean len: number @@ -28,7 +27,6 @@ function QuoteTableCard(props: QuoteTableCardProps) { item: quoteTableItem, onEdit, onDelete, - currencyToken = '$', handleUpdateProductQty, idEdit, len, @@ -125,9 +123,7 @@ function QuoteTableCard(props: QuoteTableCardProps) { )} - {`Price: ${currencyToken}${price.toFixed( - 2 - )}`} + {`Price: ${currencyFormat(price)}`} - {`Total: ${currencyToken}${total.toFixed( - 2 - )}`} + {`Total: ${currencyFormat(total)}`} { navigate('/shoppingLists') } @@ -360,7 +358,6 @@ function ShoppingListDetails({ setOpenPage }: ShoppingListDetailsProps) { allowJuniorPlaceOrder={allowJuniorPlaceOrder} setCheckedArr={setCheckedArr} shoppingListInfo={shoppingListInfo} - currencyToken={currencyToken} isRequestLoading={isRequestLoading} setIsRequestLoading={setIsRequestLoading} shoppingListId={id} @@ -400,7 +397,6 @@ function ShoppingListDetails({ setOpenPage }: ShoppingListDetailsProps) { role={role} allowJuniorPlaceOrder={allowJuniorPlaceOrder} checkedArr={checkedArr} - currencyToken={currencyToken} selectedSubTotal={selectedSubTotal} setLoading={setIsRequestLoading} setDeleteOpen={setDeleteOpen} @@ -418,7 +414,6 @@ function ShoppingListDetails({ setOpenPage }: ShoppingListDetailsProps) { products={validateFailureProducts} successProducts={validateSuccessProducts.length} allowJuniorPlaceOrder={allowJuniorPlaceOrder} - currencyToken={currencyToken} setValidateFailureProducts={setValidateFailureProducts} setValidateSuccessProducts={setValidateSuccessProducts} textAlign={isMobile ? 'left' : 'right'} diff --git a/apps/storefront/src/pages/shoppingListDetails/components/ChooseOptionsDialog.tsx b/apps/storefront/src/pages/shoppingListDetails/components/ChooseOptionsDialog.tsx index 892a55c6..51765959 100644 --- a/apps/storefront/src/pages/shoppingListDetails/components/ChooseOptionsDialog.tsx +++ b/apps/storefront/src/pages/shoppingListDetails/components/ChooseOptionsDialog.tsx @@ -13,7 +13,7 @@ import { Box, Divider, TextField, Typography } from '@mui/material' import { B3CustomForm, B3Dialog, B3Sping } from '@/components' import { PRODUCT_DEFAULT_IMAGE } from '@/constants' import { searchB2BProducts, searchBcProducts } from '@/shared/service/b2b' -import { snackbar } from '@/utils' +import { currencyFormat, snackbar } from '@/utils' import { ShoppingListProductItem, SimpleObject, Variant } from '../../../types' import { @@ -72,7 +72,6 @@ interface ChooseOptionsDialogProps { product?: ShoppingListProductItem onCancel: () => void onConfirm: (products: CustomFieldItems[]) => void - currency?: string isEdit?: boolean isLoading: boolean setIsLoading: Dispatch> @@ -86,7 +85,6 @@ export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) { onCancel, onConfirm, product, - currency = '$', isEdit = false, isLoading, setIsLoading, @@ -169,13 +167,13 @@ export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) { const priceNumber = variants.find((variant) => variant.sku === variantSku) ?.bc_calculated_price?.tax_inclusive || 0 - return `${currency} ${priceNumber.toFixed(2)}` + return `${currencyFormat(priceNumber)}` } const priceNumber = parseFloat(variants[0]?.bc_calculated_price?.tax_inclusive?.toString()) || 0 - return `${currency} ${priceNumber.toFixed(2)}` + return `${currencyFormat(priceNumber)}` } const handleProductQuantityChange = (e: ChangeEvent) => { diff --git a/apps/storefront/src/pages/shoppingListDetails/components/ReAddToCart.tsx b/apps/storefront/src/pages/shoppingListDetails/components/ReAddToCart.tsx index 2811955e..5d1b91d5 100644 --- a/apps/storefront/src/pages/shoppingListDetails/components/ReAddToCart.tsx +++ b/apps/storefront/src/pages/shoppingListDetails/components/ReAddToCart.tsx @@ -13,7 +13,7 @@ import { import { PRODUCT_DEFAULT_IMAGE } from '@/constants' import { useMobile } from '@/hooks' import { addProductToCart, createCart, getCartInfo } from '@/shared/service/bc' -import { snackbar } from '@/utils' +import { currencyFormat, snackbar } from '@/utils' import { addlineItems, getProductOptionsFields, @@ -24,7 +24,6 @@ interface ShoppingProductsProps { shoppingListInfo: any role: string | number products: ProductsProps[] - currencyToken: string successProducts: number allowJuniorPlaceOrder: boolean getProductQuantity?: (item: ProductsProps) => number @@ -158,7 +157,6 @@ export default function ReAddToCart(props: ShoppingProductsProps) { shoppingListInfo, role, products, - currencyToken, successProducts, allowJuniorPlaceOrder, setValidateFailureProducts, @@ -443,7 +441,7 @@ export default function ReAddToCart(props: ShoppingProductsProps) { textAlignLocation={textAlign} > {isMobile && Price: } - {`${currencyToken}${price.toFixed(2)}`} + {`${currencyFormat(price)}`} {isMobile &&
Total:
} - {`${currencyToken}${total}`} + {`${currencyFormat(total)}`}
diff --git a/apps/storefront/src/pages/shoppingListDetails/components/ShoppingDetailCard.tsx b/apps/storefront/src/pages/shoppingListDetails/components/ShoppingDetailCard.tsx index 8531dbd7..e6af7127 100644 --- a/apps/storefront/src/pages/shoppingListDetails/components/ShoppingDetailCard.tsx +++ b/apps/storefront/src/pages/shoppingListDetails/components/ShoppingDetailCard.tsx @@ -3,7 +3,7 @@ import { Delete, Edit } from '@mui/icons-material' import { Box, CardContent, styled, TextField, Typography } from '@mui/material' import { PRODUCT_DEFAULT_IMAGE } from '@/constants' -import { getProductPriceIncTax } from '@/utils' +import { currencyFormat, getProductPriceIncTax } from '@/utils' import { getProductOptionsFields } from '../../../utils/b3Product/shared/config' @@ -15,7 +15,6 @@ interface ShoppingDetailCardProps { itemId: number | string ) => void onDelete: (itemId: number) => void - currencyToken: string handleUpdateProductQty: (id: number | string, value: number | string) => void handleUpdateShoppingListItem: (itemId: number | string) => void checkBox?: () => ReactElement @@ -37,7 +36,6 @@ function ShoppingDetailCard(props: ShoppingDetailCardProps) { onEdit, onDelete, checkBox, - currencyToken = '$', handleUpdateProductQty, handleUpdateShoppingListItem, isReadForApprove, @@ -156,7 +154,7 @@ function ShoppingDetailCard(props: ShoppingDetailCardProps) { color: '#212121', }} > - {`Price: ${currencyToken}${price.toFixed(2)}`} + {`Price: ${currencyFormat(price)}`} - {`Total: ${currencyToken}${total.toFixed(2)}`} + {`Total: ${currencyFormat(total)}`} void setDeleteOpen: (val: boolean) => void @@ -54,7 +53,6 @@ function ShoppingDetailFooter(props: ShoppingDetailFooterProps) { role, allowJuniorPlaceOrder, checkedArr, - currencyToken, selectedSubTotal, setLoading, setDeleteOpen, @@ -296,7 +294,7 @@ function ShoppingDetailFooter(props: ShoppingDetailFooterProps) { color: '#000000', }} > - {`Subtotal: ${currencyToken}${selectedSubTotal.toFixed(2)}`} + {`Subtotal: ${currencyFormat(selectedSubTotal)}`} > shoppingListId: number | string @@ -132,7 +131,6 @@ function ShoppingDetailTable( const { shoppingListInfo, - currencyToken, isRequestLoading, setIsRequestLoading, shoppingListId, @@ -415,9 +413,9 @@ function ShoppingDetailTable( padding: '12px 0', }} > - {`${currencyToken}${ + {currencyFormat( +baseAllPrice !== 0 ? baseAllPrice : basePrice - }`} + )} ) }, @@ -477,9 +475,9 @@ function ShoppingDetailTable( padding: '12px 0', }} > - {`${currencyToken}${( + {currencyFormat( +(+baseAllPrice !== 0 ? baseAllPrice : basePrice) * +quantity - ).toFixed(2)}`} + )} - {`${currencyToken}${shoppingListTotalPrice.toFixed(2) || 0.0}`} + {`${currencyFormat(shoppingListTotalPrice || 0.00)}`} diff --git a/apps/storefront/src/pages/shoppingLists/ShoppingListsCard.tsx b/apps/storefront/src/pages/shoppingLists/ShoppingListsCard.tsx index 3182da98..c9166874 100644 --- a/apps/storefront/src/pages/shoppingLists/ShoppingListsCard.tsx +++ b/apps/storefront/src/pages/shoppingLists/ShoppingListsCard.tsx @@ -8,9 +8,9 @@ import Card from '@mui/material/Card' import CardContent from '@mui/material/CardContent' import IconButton from '@mui/material/IconButton' import Typography from '@mui/material/Typography' -import { format } from 'date-fns' import { CustomButton } from '@/components' +import { displayFormat } from '@/utils' import { ShoppingListsItemsProps } from './config' import { ShoppingStatus } from './ShoppingStatus' @@ -146,7 +146,7 @@ function ShoppingListsCard(props: OrderItemCardProps) { Last activity: - {format(+shoppingList.updatedAt * 1000, 'dd MMM yyyy')} + {displayFormat(shoppingList.updatedAt)}
diff --git a/apps/storefront/src/shared/global/context/config.ts b/apps/storefront/src/shared/global/context/config.ts index 48fc1095..08b6f5dd 100644 --- a/apps/storefront/src/shared/global/context/config.ts +++ b/apps/storefront/src/shared/global/context/config.ts @@ -44,7 +44,7 @@ export interface CurrencyProps { name: string thousands_token: string token: string - token_location: string + token_location: 'left' | 'right' } export interface OpenAPPParamsProps { @@ -52,6 +52,13 @@ export interface OpenAPPParamsProps { shoppingListBtn: string } +export interface TimeFormatProps { + display: string + export: string + extendedDisplay: string + offset: number +} + export interface GlobalState { isCheckout: boolean isCloseGotoBCHome: boolean @@ -101,6 +108,7 @@ export interface GlobalState { } openAPPParams: OpenAPPParamsProps showPageMask: boolean + timeFormat: TimeFormatProps } export const initState = { @@ -149,6 +157,7 @@ export const initState = { shoppingListBtn: '', }, showPageMask: false, + timeFormat: B3SStorage.get('timeFormat') || {}, } export interface GlobalAction { diff --git a/apps/storefront/src/shared/service/b2b/graphql/register.ts b/apps/storefront/src/shared/service/b2b/graphql/register.ts index 31122e35..2a535e38 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/register.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/register.ts @@ -155,6 +155,12 @@ const getStoreChannelId = () => `{ b2bEnabled b3ChannelId } + timeFormat{ + display + export + extendedDisplay + offset + } } }` diff --git a/apps/storefront/src/utils/b3CurrencyFormat.ts b/apps/storefront/src/utils/b3CurrencyFormat.ts new file mode 100644 index 00000000..3741456f --- /dev/null +++ b/apps/storefront/src/utils/b3CurrencyFormat.ts @@ -0,0 +1,46 @@ +import getDefaultCurrencyInfo from './currencyUtils' + +interface MoneyFormat { + currency_location: 'left' | 'right' + currency_token: string + decimal_token: string + decimal_places: number + thousands_token: string + currency_exchange_rate: string +} + +const currencyFormat = (price: string | number, showCurrencyToken = true) => { + const currentCurrency = getDefaultCurrencyInfo() + + const moneyFormat: MoneyFormat = { + currency_location: currentCurrency?.token_location || 'left', + currency_token: currentCurrency?.token || '$', + decimal_token: currentCurrency?.decimal_token || '.', + decimal_places: currentCurrency?.decimal_places || 2, + thousands_token: currentCurrency?.thousands_token || ',', + currency_exchange_rate: + currentCurrency?.currency_exchange_rate || '1.0000000000', + } + + try { + if (moneyFormat.currency_location === 'left') { + const priceStr = `${ + showCurrencyToken ? moneyFormat.currency_token : '' + }${(+price * +moneyFormat.currency_exchange_rate) + .toFixed(moneyFormat.decimal_places) + .replace(/\B(?=(\d{3})+(?!\d))/g, moneyFormat.thousands_token)}` + return priceStr + } + const priceStr = `${(+price * +moneyFormat.currency_exchange_rate) + .toFixed(moneyFormat.decimal_places) + .replace(/\B(?=(\d{3})+(?!\d))/g, moneyFormat.thousands_token)}${ + showCurrencyToken ? moneyFormat.currency_token : '' + }` + return priceStr + } catch (e) { + console.error(e) + return '' + } +} + +export default currencyFormat diff --git a/apps/storefront/src/utils/b3DateFormat/index.ts b/apps/storefront/src/utils/b3DateFormat/index.ts index e8bd9f53..59f45517 100644 --- a/apps/storefront/src/utils/b3DateFormat/index.ts +++ b/apps/storefront/src/utils/b3DateFormat/index.ts @@ -1,34 +1,46 @@ import { merge } from 'lodash' -import { B3SStorage } from '@/utils' +import { B3SStorage } from '../b3Storage.js' + +import DateFormatter from './php-date-format.js' + +const fmt = new DateFormatter() const formatCreator = - (useOffset = true) => - (timestamp: any, isDateStr = false) => { + (displayType: string, handler: string, useOffset = true) => + (timestamp: string | number, isDateStr = false) => { const dateFormat = merge( { - display: 'Y M jS', - export: 'M jS Y', - extendedDisplay: 'M jS Y @ g:i A', + display: 'j M Y', + export: 'M j Y', + extendedDisplay: 'M j Y @ g:i A', offset: 0, }, - B3SStorage.get('dateFormat') || {} + B3SStorage.get('timeFormat') ) + const display = dateFormat[displayType] - if (!timestamp) return 0 - - const dateTime = isDateStr - ? timestamp - : Number.parseInt(timestamp, 10) * 1000 + if (!timestamp) return '' + const dateTime = isDateStr ? timestamp : parseInt(timestamp, 10) * 1000 const localDate = new Date(dateTime) const localTime = localDate.getTime() const offset = useOffset ? localDate.getTimezoneOffset() * 60000 + dateFormat.offset * 1000 : 0 const utcTime = localTime + offset - return utcTime + + const dateObject = new Date(utcTime) + switch (handler) { + case 'formatDate': + return fmt.formatDate(dateObject, display) || '' + case 'parseDate': + return fmt.parseDate(dateObject, display) || '' + default: + return null + } } -const displayFormat = formatCreator() +const displayFormat = formatCreator('display', 'formatDate') +const displayExtendedFormat = formatCreator('extendedDisplay', 'formatDate') -export default displayFormat +export { displayExtendedFormat,displayFormat } diff --git a/apps/storefront/src/utils/b3DateFormat/php-date-format.ts b/apps/storefront/src/utils/b3DateFormat/php-date-format.ts new file mode 100644 index 00000000..d1493271 --- /dev/null +++ b/apps/storefront/src/utils/b3DateFormat/php-date-format.ts @@ -0,0 +1,885 @@ +interface DateSettings { + days: string[] + daysShort: string[] + months: string[] + monthsShort: string[] + meridiem: string[] + ordinal(number: number): string +} + +interface Defaults { + dateSettings: DateSettings + separators: RegExp + validParts: RegExp + intParts: RegExp + tzParts: RegExp + tzClip: RegExp +} + +interface AnyType { + [key: string]: any +} + +interface Helper { + DAY: number + HOUR: number + defaults: Defaults + getInt(str: string | number | null, radix?: number): number + compare(str1: string, str2: string): boolean + lpad(value: any, length: number, chr?: string): string + merge(out: any, ...args: any[]): any + getIndex(val: string, arr: string[]): number +} + +/** + * Global helper object + */ +const $h: Helper = { + DAY: 1000 * 60 * 60 * 24, + HOUR: 3600, + defaults: { + dateSettings: { + days: [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ], + daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + months: [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ], + monthsShort: [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ], + meridiem: ['AM', 'PM'], + ordinal(number: number): string { + const n = number % 10 + const suffixes: AnyType = { + 1: 'st', + 2: 'nd', + 3: 'rd', + } + return Math.floor((number % 100) / 10) === 1 || !suffixes[n] + ? 'th' + : suffixes[n] + }, + }, + separators: /[ \-+\/.:@]/g, + validParts: /[dDjlNSwzWFmMntLoYyaABgGhHisueTIOPZcrU]/g, + intParts: /[djwNzmnyYHgGis]/g, + tzParts: + /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, + tzClip: /[^-+\dA-Z]/g, + }, + getInt(str: string | number | null, radix?: number): number { + return parseInt(String(str), radix || 10) + }, + compare(str1: string, str2: string): boolean { + return ( + typeof str1 === 'string' && + typeof str2 === 'string' && + str1.toLowerCase() === str2.toLowerCase() + ) + }, + lpad(value: any, length: number, chr?: string): string { + const val = value.toString() + chr = chr || '0' + return val.length < length ? $h.lpad(chr + val, length, chr) : val + }, + merge(out: any, ...args: any[]): any { + let i + let obj + out = out || {} + for (i = 1; i < args.length; i++) { + obj = args[i] + if (!obj) { + continue + } + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key] === 'object') { + $h.merge(out[key], obj[key]) + } else { + out[key] = obj[key] + } + } + } + } + return out + }, + getIndex(val: string, arr: string[]): number { + for (let i = 0; i < arr.length; i++) { + if (arr[i].toLowerCase() === val.toLowerCase()) { + return i + } + } + return -1 + }, +} + +/** + * Date Formatter Library Constructor + * @param options + * @constructor + */ +// const DateFormatter = function (options: AnyType) { +// const self = this +// const config = $h.merge($h.defaults, options) +// self.dateSettings = config.dateSettings +// self.separators = config.separators +// self.validParts = config.validParts +// self.intParts = config.intParts +// self.tzParts = config.tzParts +// self.tzClip = config.tzClip +// } + +interface DateFormatterOptions { + dateSettings: { + days: string[] + daysShort: string[] + months: string[] + monthsShort: string[] + meridiem: string[] + ordinal: (number: number) => string + } + separators: RegExp + validParts: RegExp + intParts: RegExp + tzParts: RegExp + tzClip: RegExp + getMonth: (val: string) => number + parseDate: ( + vDate: string | number | Date, + vFormat: string + ) => Date | string | number | null + guessDate: (vDateStr: string, vFormat: string) => Date | string | null + parseFormat: (vChar: string | number, vDate: Date) => string | number | null + formatDate: ( + vDate: string | number | Date | null, + vFormat: string + ) => string | null +} + +class DateFormatter { + dateSettings: DateFormatterOptions['dateSettings'] + + separators: DateFormatterOptions['separators'] + + validParts: DateFormatterOptions['validParts'] + + intParts: DateFormatterOptions['intParts'] + + tzParts: DateFormatterOptions['tzParts'] + + tzClip: DateFormatterOptions['tzClip'] + + getMonth!: DateFormatterOptions['getMonth'] + + parseDate!: DateFormatterOptions['parseDate'] + + guessDate!: DateFormatterOptions['guessDate'] + + parseFormat!: DateFormatterOptions['parseFormat'] + + formatDate!: DateFormatterOptions['formatDate'] + + constructor(options?: Partial) { + const config = $h.merge($h.defaults, options) + this.dateSettings = config.dateSettings + this.separators = config.separators + this.validParts = config.validParts + this.intParts = config.intParts + this.tzParts = config.tzParts + this.tzClip = config.tzClip + } +} + +/** + * DateFormatter Library Prototype + */ +DateFormatter.prototype.getMonth = function ( + this: DateFormatter, + val: string +): number { + const self = this + let i = $h.getIndex(val, self.dateSettings.monthsShort) + 1 + if (i === 0) { + i = $h.getIndex(val, self.dateSettings.months) + 1 + } + return i +} + +DateFormatter.prototype.parseDate = function ( + this: DateFormatter, + vDate: Date | string | number, + vFormat: string +): Date | string | number | null { + const self = this + let vFormatParts: RegExpMatchArray | null + let vDateParts: string[] + let i: number + let vDateFlag = false + let vTimeFlag = false + let vDatePart: string + let iDatePart: number + const vSettings = self.dateSettings + let vMonth: number | undefined + let vMeriIndex: number + let vMeriOffset: number + let len: number + let mer: string + const out: AnyType = { + date: null, + year: null, + month: null, + day: null, + hour: 0, + min: 0, + sec: 0, + } + if (!vDate) { + return null + } + if (vDate instanceof Date) { + return vDate + } + if (vFormat === 'U') { + i = $h.getInt(vDate) + return i ? new Date(i * 1000) : vDate + } + switch (typeof vDate) { + case 'number': + return new Date(vDate) + case 'string': + break + default: + return null + } + vFormatParts = vFormat.match(self.validParts) + if (!vFormatParts || vFormatParts.length === 0) { + throw new Error('Invalid date format definition.') + } + for (i = vFormatParts.length - 1; i >= 0; i--) { + if (vFormatParts[i] === 'S') { + vFormatParts.splice(i, 1) + } + } + vDateParts = vDate.replace(self.separators, '\0').split('\0') + for (i = 0; i < vDateParts.length; i++) { + vDatePart = vDateParts[i] + iDatePart = $h.getInt(vDatePart) + switch (vFormatParts[i]) { + case 'y': + case 'Y': + if (iDatePart) { + len = vDatePart.length + out.year = + len === 2 + ? $h.getInt((iDatePart < 70 ? '20' : '19') + vDatePart) + : iDatePart + } else { + return null + } + vDateFlag = true + break + case 'm': + case 'n': + case 'M': + case 'F': + if (isNaN(iDatePart)) { + vMonth = self.getMonth(vDatePart) + if (vMonth > 0) { + out.month = vMonth + } else { + return null + } + } else if (iDatePart >= 1 && iDatePart <= 12) { + out.month = iDatePart + } else { + return null + } + vDateFlag = true + break + case 'd': + case 'j': + if (iDatePart >= 1 && iDatePart <= 31) { + out.day = iDatePart + } else { + return null + } + vDateFlag = true + break + case 'g': + case 'h': + vMeriIndex = + vFormatParts.indexOf('a') > -1 + ? vFormatParts.indexOf('a') + : vFormatParts.indexOf('A') > -1 + ? vFormatParts.indexOf('A') + : -1 + mer = vDateParts[vMeriIndex] + if (vMeriIndex !== -1) { + vMeriOffset = $h.compare(mer, vSettings.meridiem[0]) + ? 0 + : $h.compare(mer, vSettings.meridiem[1]) + ? 12 + : -1 + if (iDatePart >= 1 && iDatePart <= 12 && vMeriOffset !== -1) { + out.hour = + iDatePart % 12 === 0 ? vMeriOffset : iDatePart + vMeriOffset + } else if (iDatePart >= 0 && iDatePart <= 23) { + out.hour = iDatePart + } + } else if (iDatePart >= 0 && iDatePart <= 23) { + out.hour = iDatePart + } else { + return null + } + vTimeFlag = true + break + case 'G': + case 'H': + if (iDatePart >= 0 && iDatePart <= 23) { + out.hour = iDatePart + } else { + return null + } + vTimeFlag = true + break + case 'i': + if (iDatePart >= 0 && iDatePart <= 59) { + out.min = iDatePart + } else { + return null + } + vTimeFlag = true + break + case 's': + if (iDatePart >= 0 && iDatePart <= 59) { + out.sec = iDatePart + } else { + return null + } + vTimeFlag = true + break + } + } + if (vDateFlag === true) { + const varY = out.year || 0 + const varM = out.month ? out.month - 1 : 0 + const varD = out.day || 1 + out.date = new Date(varY, varM, varD, out.hour, out.min, out.sec, 0) + } else { + if (vTimeFlag !== true) { + return null + } + out.date = new Date(0, 0, 0, out.hour, out.min, out.sec, 0) + } + return out.date +} + +DateFormatter.prototype.guessDate = function ( + this: DateFormatter, + vDateStr: string, + vFormat: string +): Date | string | null { + if (typeof vDateStr !== 'string') { + return vDateStr + } + + const self = this + const vParts = vDateStr.replace(self.separators, '\0').split('\0') + const vPattern = /^[djmn]/g + const vFormatParts = vFormat.match(self.validParts) + const vDate = new Date() + + let vDigit = 0 + let vYear: number | undefined + let i: number + let n: string + let iPart: string + let iSec: number | undefined + let len: number | undefined + + if (vFormatParts?.length && !vPattern.test(vFormatParts[0])) { + return vDateStr + } + + for (i = 0; i < vParts.length; i++) { + vDigit = 2 + iPart = vParts[i] + iSec = parseInt(iPart.substr(0, 2), 10) + + if (isNaN(iSec)) { + return null + } + + switch (i) { + case 0: + if ( + vFormatParts?.length && + (vFormatParts[0] === 'm' || vFormatParts[0] === 'n') + ) { + vDate.setMonth(iSec - 1) + } else { + vDate.setDate(iSec) + } + break + case 1: + if ( + vFormatParts?.length && + (vFormatParts[0] === 'm' || vFormatParts[0] === 'n') + ) { + vDate.setDate(iSec) + } else { + vDate.setMonth(iSec - 1) + } + break + case 2: + vYear = vDate.getFullYear() + len = iPart.length + vDigit = len < 4 ? len : 4 + vYear = parseInt( + len < 4 + ? vYear.toString().substr(0, 4 - len) + iPart + : iPart.substr(0, 4), + 10 + ) + + if (!vYear) { + return null + } + + vDate.setFullYear(vYear) + break + case 3: + vDate.setHours(iSec) + break + case 4: + vDate.setMinutes(iSec) + break + case 5: + vDate.setSeconds(iSec) + break + } + + n = iPart.substr(vDigit) + + if (n.length > 0) { + vParts.splice(i + 1, 0, n) + } + } + + const vFormatYear = vFormatParts?.find((part) => /[yY]/.test(part)) + + if (vFormatYear && vYear && vYear < 100 && vFormatYear.length > 1) { + const century = Math.floor(vDate.getFullYear() / 100) * 100 + const twoDigitYear = + vYear + century - (vYear <= new Date().getFullYear() % 100 ? 0 : 100) + vDate.setFullYear(twoDigitYear) + } + + if (vDate.toString() === 'Invalid Date') { + return null + } + + return vDate +} + +DateFormatter.prototype.parseFormat = function ( + this: DateFormatter, + vChar: string | number, + vDate: Date +): string | number | null { + const self = this + const vSettings = self.dateSettings + let fmt: AnyType + const backslash = /\\?(.?)/gi + const doFormat = function (t: string | number, s: any) { + return fmt[t] ? fmt[t]() : s + } + fmt = { + /// ////// + // DAY // + /// ////// + /** + * Day of month with leading 0: `01..31` + * @return {string} + */ + d() { + return $h.lpad(fmt.j(), 2) + }, + /** + * Shorthand day name: `Mon...Sun` + * @return {string} + */ + D() { + return vSettings.daysShort[fmt.w()] + }, + /** + * Day of month: `1..31` + * @return {number} + */ + j() { + return vDate.getDate() + }, + /** + * Full day name: `Monday...Sunday` + * @return {string} + */ + l() { + return vSettings.days[fmt.w()] + }, + /** + * ISO-8601 day of week: `1[Mon]..7[Sun]` + * @return {number} + */ + N() { + return fmt.w() || 7 + }, + /** + * Day of week: `0[Sun]..6[Sat]` + * @return {number} + */ + w() { + return vDate.getDay() + }, + /** + * Day of year: `0..365` + * @return {number} + */ + z() { + const a = new Date(fmt.Y(), fmt.n() - 1, fmt.j()) + const b = new Date(fmt.Y(), 0, 1) + return Math.round((Number(a) - Number(b)) / $h.DAY) + }, + /// /////// + // WEEK // + /// /////// + /** + * ISO-8601 week number + * @return {number} + */ + W() { + const a = new Date(fmt.Y(), fmt.n() - 1, fmt.j() - fmt.N() + 3) + const b = new Date(a.getFullYear(), 0, 4) + const diffInMs = a.getTime() - b.getTime() + const diffInDays = Math.floor(diffInMs / 86400000) + return $h.lpad(1 + Math.round(diffInDays / $h.DAY / 7), 2) + }, + /// //////// + // MONTH // + /// //////// + /** + * Full month name: `January...December` + * @return {string} + */ + F() { + return vSettings.months[vDate.getMonth()] + }, + /** + * Month w/leading 0: `01..12` + * @return {string} + */ + m() { + return $h.lpad(fmt.n(), 2) + }, + /** + * Shorthand month name; `Jan...Dec` + * @return {string} + */ + M() { + return vSettings.monthsShort[vDate.getMonth()] + }, + /** + * Month: `1...12` + * @return {number} + */ + n() { + return vDate.getMonth() + 1 + }, + /** + * Days in month: `28...31` + * @return {number} + */ + t() { + return new Date(fmt.Y(), fmt.n(), 0).getDate() + }, + /// /////// + // YEAR // + /// /////// + /** + * Is leap year? `0 or 1` + * @return {number} + */ + L() { + const Y = fmt.Y() + return (Y % 4 === 0 && Y % 100 !== 0) || Y % 400 === 0 ? 1 : 0 + }, + /** + * ISO-8601 year + * @return {number} + */ + o() { + const n = fmt.n() + const W = fmt.W() + const Y = fmt.Y() + return Y + (n === 12 && W < 9 ? 1 : n === 1 && W > 9 ? -1 : 0) + }, + /** + * Full year: `e.g. 1980...2010` + * @return {number} + */ + Y() { + return vDate.getFullYear() + }, + /** + * Last two digits of year: `00...99` + * @return {string} + */ + y() { + return fmt.Y().toString().slice(-2) + }, + /// /////// + // TIME // + /// /////// + /** + * Meridian lower: `am or pm` + * @return {string} + */ + a() { + return fmt.A().toLowerCase() + }, + /** + * Meridian upper: `AM or PM` + * @return {string} + */ + A() { + const n = fmt.G() < 12 ? 0 : 1 + return vSettings.meridiem[n] + }, + /** + * Swatch Internet time: `000..999` + * @return {string} + */ + B() { + const H = vDate.getUTCHours() * $h.HOUR + const i = vDate.getUTCMinutes() * 60 + const s = vDate.getUTCSeconds() + return $h.lpad(Math.floor((H + i + s + $h.HOUR) / 86.4) % 1000, 3) + }, + /** + * 12-Hours: `1..12` + * @return {number} + */ + g() { + return fmt.G() % 12 || 12 + }, + /** + * 24-Hours: `0..23` + * @return {number} + */ + G() { + return vDate.getHours() + }, + /** + * 12-Hours with leading 0: `01..12` + * @return {string} + */ + h() { + return $h.lpad(fmt.g(), 2) + }, + /** + * 24-Hours w/leading 0: `00..23` + * @return {string} + */ + H() { + return $h.lpad(fmt.G(), 2) + }, + /** + * Minutes w/leading 0: `00..59` + * @return {string} + */ + i() { + return $h.lpad(vDate.getMinutes(), 2) + }, + /** + * Seconds w/leading 0: `00..59` + * @return {string} + */ + s() { + return $h.lpad(vDate.getSeconds(), 2) + }, + /** + * Microseconds: `000000-999000` + * @return {string} + */ + u() { + return $h.lpad(vDate.getMilliseconds() * 1000, 6) + }, + /** + * Timezone identifier: `e.g. Atlantic/Azores, ...` + * @return {string} + */ + e() { + const strArr = /\((.*)\)/.exec(String(vDate)) + if (strArr?.length) { + const str = strArr[1] + return str + } + return 'Coordinated Universal Time' + }, + /** + * DST observed? `0 or 1` + * @return {number} + */ + I() { + const a = new Date(fmt.Y(), 0) + const c = Date.UTC(fmt.Y(), 0) + const b = new Date(fmt.Y(), 6) + const d = Date.UTC(fmt.Y(), 6) + const diffInMs1 = a.getTime() - c + const diffInMs2 = b.getTime() - d + return diffInMs1 !== diffInMs2 ? 1 : 0 + }, + /** + * Difference to GMT in hour format: `e.g. +0200` + * @return {string} + */ + O() { + const tzo = vDate.getTimezoneOffset() + const a = Math.abs(tzo) + return ( + (tzo > 0 ? '-' : '+') + $h.lpad(Math.floor(a / 60) * 100 + (a % 60), 4) + ) + }, + /** + * Difference to GMT with colon: `e.g. +02:00` + * @return {string} + */ + P() { + const O = fmt.O() + return `${O.substr(0, 3)}:${O.substr(3, 2)}` + }, + /// /////////// + // TIMEZONE // + /// /////////// + /** + * Timezone abbreviation: `e.g. EST, MDT, ...` + * @return {string} + */ + T() { + const date = (String(vDate).match(self.tzParts) || ['']).pop() + if (date) { + const str = date.replace(self.tzClip, '') + return str + } + return 'UTC' + }, + /** + * Timezone offset in seconds: `-43200...50400` + * @return {number} + */ + Z() { + return -vDate.getTimezoneOffset() * 60 + }, + /// ///////////////// + // FULL DATE TIME // + /// ///////////////// + /** + * ISO-8601 date + * @return {string} + */ + c() { + return 'Y-m-d\\TH:i:sP'.replace(backslash, doFormat) + }, + /** + * RFC 2822 date + * @return {string} + */ + r() { + return 'D, d M Y H:i:s O'.replace(backslash, doFormat) + }, + /** + * Seconds since UNIX epoch + * @return {number} + */ + U() { + return vDate.getTime() / 1000 || 0 + }, + } + return doFormat(vChar, vChar) +} + +DateFormatter.prototype.formatDate = function ( + this: DateFormatter, + vDate: string | number | Date | null, + vFormat: string +): string | null { + const self = this + let n + let len + let str + let vChar + let vDateStr = '' + const BACKSLASH = '\\' + if (typeof vDate === 'string') { + vDate = self.parseDate(vDate, vFormat) + if (!vDate) { + return null + } + } + if (vDate instanceof Date) { + len = vFormat.length + for (let i = 0; i < len; i++) { + vChar = vFormat.charAt(i) + if (vChar === 'S' || vChar === BACKSLASH) { + continue + } + if (i > 0 && vFormat.charAt(i - 1) === BACKSLASH) { + vDateStr += vChar + continue + } + str = self.parseFormat(vChar, vDate) + if ( + i !== len - 1 && + self.intParts.test(vChar) && + vFormat.charAt(i + 1) === 'S' + ) { + n = $h.getInt(str) || 0 + str += self.dateSettings.ordinal(n) + } + vDateStr += str + } + return vDateStr + } + return '' +} + +export default DateFormatter diff --git a/apps/storefront/src/utils/currencyUtils.ts b/apps/storefront/src/utils/currencyUtils.ts index 4672b8d3..203efb6d 100644 --- a/apps/storefront/src/utils/currencyUtils.ts +++ b/apps/storefront/src/utils/currencyUtils.ts @@ -16,7 +16,7 @@ interface CurrencyProps { name: string thousands_token: string token: string - token_location: string + token_location: 'left' | 'right' } const getDefaultCurrencyInfo = () => { diff --git a/apps/storefront/src/utils/index.ts b/apps/storefront/src/utils/index.ts index fa92bbc7..0f0bb63a 100644 --- a/apps/storefront/src/utils/index.ts +++ b/apps/storefront/src/utils/index.ts @@ -6,6 +6,8 @@ import { isModifierTextValid, serialize, } from './b3AddToShoppingList' +import currencyFormat from './b3CurrencyFormat' +import { displayExtendedFormat,displayFormat } from './b3DateFormat' import { getLogo, getQuoteEnabled } from './b3Init' import { showPageMask } from './b3PageMask' import distanceDay from './b3Picker' @@ -53,6 +55,9 @@ export { clearCurrentCustomerInfo, convertArrayToGraphql, convertObjectToGraphql, + currencyFormat, + displayExtendedFormat, + displayFormat, distanceDay, getCookie, getCurrenciesInfo,