From 03f1f0bda5f960f8ee98a9239b85a20f77bb2f02 Mon Sep 17 00:00:00 2001 From: BrianJiang2021 <80307788+BrianJiang2021@users.noreply.github.com> Date: Tue, 25 Apr 2023 16:49:38 +0800 Subject: [PATCH] fix: shoppinglist modifier and default value (#310) * fix: shoppinglist modifier and default value --- .../src/components/upload/B3Upload.tsx | 16 ++- .../components/AddToShoppingList.tsx | 54 +++++++++- .../components/QuickAdd.tsx | 54 +++++++++- .../src/shared/service/b2b/graphql/product.ts | 29 ++++++ .../src/shared/service/b2b/index.ts | 2 + .../src/utils/b3Product/shared/config.ts | 98 ++++++++++++++++++- 6 files changed, 240 insertions(+), 13 deletions(-) diff --git a/apps/storefront/src/components/upload/B3Upload.tsx b/apps/storefront/src/components/upload/B3Upload.tsx index 4af59cee..344a3410 100644 --- a/apps/storefront/src/components/upload/B3Upload.tsx +++ b/apps/storefront/src/components/upload/B3Upload.tsx @@ -19,6 +19,7 @@ import { GlobaledContext } from '@/shared/global' import { B2BProductsBulkUploadCSV, BcProductsBulkUploadCSV, + guestProductsBulkUploadCSV, } from '@/shared/service/b2b' import { getDefaultCurrencyInfo } from '@/utils' @@ -37,6 +38,7 @@ interface B3UploadProps { setProductData?: (product: CustomFieldItems) => void isLoading?: boolean isToCart?: boolean + withModifiers?: boolean } interface BulkUploadCSVProps { @@ -44,6 +46,7 @@ interface BulkUploadCSVProps { productList: CustomFieldItems channelId?: number isToCart: boolean + withModifiers?: boolean } const FileUploadContainer = styled(Box)(() => ({ @@ -69,6 +72,7 @@ export default function B3Upload(props: B3UploadProps) { setProductData = () => {}, isLoading = false, isToCart = false, + withModifiers = false, } = props const [isMobile] = useMobile() @@ -76,7 +80,7 @@ export default function B3Upload(props: B3UploadProps) { const uploadRef = useRef(null) const { - state: { isB2BUser, currentChannelId }, + state: { isB2BUser, currentChannelId, role }, } = useContext(GlobaledContext) const theme = useTheme() @@ -142,14 +146,20 @@ export default function B3Upload(props: B3UploadProps) { currencyCode, productList: parseData, isToCart, + withModifiers, } if (!isB2BUser) params.channelId = currentChannelId - const BulkUploadCSV = isB2BUser + const uploadAction = isB2BUser ? B2BProductsBulkUploadCSV : BcProductsBulkUploadCSV - const { productUpload } = await BulkUploadCSV(params) + const BulkUploadCSV = + role === 100 ? guestProductsBulkUploadCSV : uploadAction + + const resp = await BulkUploadCSV(params) + const productUpload = + role === 100 ? resp.productAnonUpload : resp.productUpload if (productUpload) { const { result } = productUpload diff --git a/apps/storefront/src/pages/shoppingListDetails/components/AddToShoppingList.tsx b/apps/storefront/src/pages/shoppingListDetails/components/AddToShoppingList.tsx index 13d3fe5d..7e59bc4d 100644 --- a/apps/storefront/src/pages/shoppingListDetails/components/AddToShoppingList.tsx +++ b/apps/storefront/src/pages/shoppingListDetails/components/AddToShoppingList.tsx @@ -9,6 +9,7 @@ import { } from '@/shared/service/b2b' import { snackbar } from '@/utils' +import { getAllModifierDefaultValue } from '../../../utils/b3Product/shared/config' import { ShoppingListDetailsContext } from '../context/ShoppingListDetailsContext' import QuickAdd from './QuickAdd' @@ -76,22 +77,58 @@ export default function AddToShoppingList(props: AddToListProps) { const getValidProducts = (products: CustomFieldItems) => { const notPurchaseSku: string[] = [] const productItems: CustomFieldItems[] = [] + const notAddAble: string[] = [] products.forEach((item: CustomFieldItems) => { const { products: currentProduct, qty } = item - const { option, purchasingDisabled, variantSku, variantId, productId } = - currentProduct - + const { + option, + purchasingDisabled, + variantSku, + variantId, + productId, + modifiers, + } = currentProduct + + const defaultModifiers = getAllModifierDefaultValue(modifiers) if (purchasingDisabled) { notPurchaseSku.push(variantSku) return } + const notPassedModifier = defaultModifiers.filter( + (modifier: CustomFieldItems) => !modifier.isVerified + ) + if (notPassedModifier.length > 0) { + notAddAble.push(variantSku) + + return + } + const optionsList = option.map((item: CustomFieldItems) => ({ optionId: `attribute[${item.option_id}]`, optionValue: item.id.toString(), })) + defaultModifiers.forEach((modifier: CustomFieldItems) => { + const { type } = modifier + + if (type === 'date') { + const { defaultValue } = modifier + Object.keys(defaultValue).forEach((key) => { + optionsList.push({ + optionId: `attribute[${modifier.option_id}][${key}]`, + optionValue: `${modifier.defaultValue[key]}`, + }) + }) + } else { + optionsList.push({ + optionId: `attribute[${modifier.option_id}]`, + optionValue: `${modifier.defaultValue}`, + }) + } + }) + productItems.push({ productId: parseInt(productId, 10) || 0, variantId: parseInt(variantId, 10) || 0, @@ -103,6 +140,7 @@ export default function AddToShoppingList(props: AddToListProps) { return { notPurchaseSku, productItems, + notAddAble, } } @@ -111,7 +149,8 @@ export default function AddToShoppingList(props: AddToListProps) { try { const { validProduct } = productsData - const { notPurchaseSku, productItems } = getValidProducts(validProduct) + const { notPurchaseSku, productItems, notAddAble } = + getValidProducts(validProduct) if (productItems.length > 0) { await quickAddToList(productItems) @@ -119,6 +158,12 @@ export default function AddToShoppingList(props: AddToListProps) { updateList() } + if (notAddAble.length > 0) { + snackbar.error(`SKU ${notAddAble} cannot be added quickly`, { + isClose: true, + }) + } + if (notPurchaseSku.length > 0) { snackbar.error( `SKU ${notPurchaseSku} cannot be purchased in online store.`, @@ -180,6 +225,7 @@ export default function AddToShoppingList(props: AddToListProps) { setIsOpen={setIsOpenBulkLoadCSV} handleAddToList={handleCSVAddToList} isLoading={isLoading} + withModifiers /> diff --git a/apps/storefront/src/pages/shoppingListDetails/components/QuickAdd.tsx b/apps/storefront/src/pages/shoppingListDetails/components/QuickAdd.tsx index b8702fa0..b654bb7d 100644 --- a/apps/storefront/src/pages/shoppingListDetails/components/QuickAdd.tsx +++ b/apps/storefront/src/pages/shoppingListDetails/components/QuickAdd.tsx @@ -6,7 +6,10 @@ import { Box, Grid, Typography } from '@mui/material' import { B3CustomForm, B3Sping, CustomButton } from '@/components' import { GlobaledContext } from '@/shared/global' import { snackbar } from '@/utils' -import { getQuickAddRowFields } from '@/utils/b3Product/shared/config' +import { + getAllModifierDefaultValue, + getQuickAddRowFields, +} from '@/utils/b3Product/shared/config' import { getB2BVariantInfoBySkus, @@ -136,6 +139,7 @@ export default function QuickAdd(props: AddToListContentProps) { const notPurchaseSku: string[] = [] const productItems: CustomFieldItems[] = [] const passSku: string[] = [] + const notAddAble: string[] = [] skus.forEach((sku) => { const variantInfo: CustomFieldItems | null = (variantInfoList || []).find( @@ -153,7 +157,9 @@ export default function QuickAdd(props: AddToListContentProps) { variantId, option: options, purchasingDisabled = '1', + modifiers, } = variantInfo + const defaultModifiers = getAllModifierDefaultValue(modifiers) const quantity = (skuValue[sku] as number) || 0 @@ -162,6 +168,15 @@ export default function QuickAdd(props: AddToListContentProps) { return } + const notPassedModifier = defaultModifiers.filter( + (modifier: CustomFieldItems) => !modifier.isVerified + ) + if (notPassedModifier.length > 0) { + notAddAble.push(sku) + + return + } + const optionList = (options || []).reduce( (arr: ShoppingListAddProductOption[], optionStr: string) => { try { @@ -179,6 +194,25 @@ export default function QuickAdd(props: AddToListContentProps) { [] ) + defaultModifiers.forEach((modifier: CustomFieldItems) => { + const { type } = modifier + + if (type === 'date') { + const { defaultValue } = modifier + Object.keys(defaultValue).forEach((key) => { + optionList.push({ + optionId: `attribute[${modifier.option_id}][${key}]`, + optionValue: `${modifier.defaultValue[key]}`, + }) + }) + } else { + optionList.push({ + optionId: `attribute[${modifier.option_id}]`, + optionValue: `${modifier.defaultValue}`, + }) + } + }) + passSku.push(sku) productItems.push({ @@ -195,6 +229,7 @@ export default function QuickAdd(props: AddToListContentProps) { notPurchaseSku, productItems, passSku, + notAddAble, } } @@ -260,9 +295,13 @@ export default function QuickAdd(props: AddToListContentProps) { } const variantInfoList = await getVariantList(skus) - - const { notFoundSku, notPurchaseSku, productItems, passSku } = - getProductItems(variantInfoList, skuValue, skus) + const { + notFoundSku, + notPurchaseSku, + productItems, + notAddAble, + passSku, + } = getProductItems(variantInfoList, skuValue, skus) if (notFoundSku.length > 0) { showErrors(value, notFoundSku, 'sku', '') @@ -281,6 +320,13 @@ export default function QuickAdd(props: AddToListContentProps) { }) } + if (notAddAble.length > 0) { + showErrors(value, notAddAble, 'sku', '') + snackbar.error(`SKU ${notAddAble} cannot be added quickly`, { + isClose: true, + }) + } + if (productItems.length > 0) { await quickAddToList(productItems) clearInputValue(value, passSku) diff --git a/apps/storefront/src/shared/service/b2b/graphql/product.ts b/apps/storefront/src/shared/service/b2b/graphql/product.ts index 489e5c8a..414c1329 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/product.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/product.ts @@ -71,6 +71,28 @@ const productsBulkUploadCSV = (data: CustomFieldItems) => `mutation { productList: ${convertArrayToGraphql(data.productList || [])} ${!data?.channelId ? '' : `channelId: ${data.channelId}`} isToCart: ${data.isToCart || false} + withModifiers: ${data.withModifiers || false} + } + ) { + result { + errorFile, + errorProduct, + validProduct, + stockErrorFile, + stockErrorSkus, + } + } +}` + +const productAnonUploadBulkUploadCSV = (data: CustomFieldItems) => `mutation { + productAnonUpload ( + productListData: { + currencyCode: "${data.currencyCode || ''}" + productList: ${convertArrayToGraphql(data.productList || [])} + ${!data?.channelId ? '' : `channelId: ${data.channelId}`} + isToCart: ${data.isToCart || false} + withModifiers: ${data.withModifiers || false} + storeHash: "${storeHash}" } ) { result { @@ -135,3 +157,10 @@ export const BcProductsBulkUploadCSV = ( B3Request.graphqlProxyBC({ query: productsBulkUploadCSV(data), }) + +export const guestProductsBulkUploadCSV = ( + data: CustomFieldItems = {} +): CustomFieldItems => + B3Request.graphqlB2B({ + query: productAnonUploadBulkUploadCSV(data), + }) diff --git a/apps/storefront/src/shared/service/b2b/index.ts b/apps/storefront/src/shared/service/b2b/index.ts index 7f70c684..5665f63a 100644 --- a/apps/storefront/src/shared/service/b2b/index.ts +++ b/apps/storefront/src/shared/service/b2b/index.ts @@ -45,6 +45,7 @@ import { BcProductsBulkUploadCSV, getB2BVariantInfoBySkus, getBcVariantInfoBySkus, + guestProductsBulkUploadCSV, searchB2BProducts, searchBcProducts, } from './graphql/product' @@ -191,6 +192,7 @@ export { getTaxZoneRates, getUserCompany, getUsers, + guestProductsBulkUploadCSV, quoteDetailAttachFileCreate, quoteDetailAttachFileDelete, searchB2BProducts, diff --git a/apps/storefront/src/utils/b3Product/shared/config.ts b/apps/storefront/src/utils/b3Product/shared/config.ts index 7d53e5f1..45777e47 100644 --- a/apps/storefront/src/utils/b3Product/shared/config.ts +++ b/apps/storefront/src/utils/b3Product/shared/config.ts @@ -1,4 +1,5 @@ import { format } from 'date-fns' +import { isEmpty } from 'lodash' import { AllOptionProps, ALlOptionValue, Product } from '@/types/products' @@ -323,10 +324,12 @@ export const getProductOptionsFields = ( value = optionValue === '1' || optionValue.includes(`${checkedId}`) ? [checkedId] - : [] + : value } else if (fieldType !== 'date') { value = - (selectOptionsJSON[`attribute[${id}]`] || {})[optionValueKey] || '' + (selectOptionsJSON[`attribute[${id}]`] || {})[optionValueKey] || + value || + '' } else { const year = (selectOptionsJSON[`attribute[${id}][year]`] || {})[optionValueKey] || @@ -371,6 +374,97 @@ export const getProductOptionsFields = ( return list } +export const getAllModifierDefaultValue = (modifiers: CustomFieldItems) => { + const modifierDefaultValue: CustomFieldItems = [] + + modifiers.forEach((modifier: CustomFieldItems) => { + const { + id: modifierId, + type, + display_name: displayName, + config, + required, + option_values: optionValues, + } = modifier + + const modifierInfo = { + option_id: modifierId, + type, + displayName, + required, + defaultValue: config?.default_value || '', + isVerified: required + ? (config?.default_value || '').toString().length > 0 + : true, + } + + if ( + [ + 'checkbox', + 'rectangles', + 'swatch', + 'radio-buttons', + 'dropdown', + ].includes(type) + ) { + const defaultInfo = + optionValues.find((values: CustomFieldItems) => values.is_default) || {} + + modifierInfo.defaultValue = defaultInfo?.id || '' + + if (required) { + modifierInfo.isVerified = + modifierInfo.defaultValue.toString().length > 0 + } + } + + if (type.includes('product_list')) { + const defaultInfo = + optionValues.find((values: CustomFieldItems) => values.is_default) || {} + + modifierInfo.defaultValue = defaultInfo?.id || '' + + if (required) { + modifierInfo.isVerified = + modifierInfo.defaultValue.toString().length > 0 + } + } + + if (type === 'file') { + modifierInfo.defaultValue = '' + + if (required) { + modifierInfo.isVerified = false + } + } + + if (type === 'date') { + const { default_value: defaultValue } = config || {} + + if (defaultValue && defaultValue?.length > 0) { + const date = new Date(defaultValue) + const year = date.getFullYear() + const month = date.getMonth() + 1 + const day = date.getDate() + + modifierInfo.defaultValue = { + year, + month, + day, + } + } + + if (required) { + modifierInfo.isVerified = !isEmpty(modifierInfo.defaultValue) + } + } + + modifierDefaultValue.push(modifierInfo) + }) + + return modifierDefaultValue +} + export const conversionProductsList = ( products: ShoppingListProductItem[], listProduct: ListItemProps[] = []