Skip to content

Commit

Permalink
feat: add the ability to edit a pick list inside a quote
Browse files Browse the repository at this point in the history
  • Loading branch information
CarlLiu2023 authored and kris-liu-smile committed Jun 27, 2023
1 parent 27645e4 commit e0908db
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 29 deletions.
1 change: 1 addition & 0 deletions apps/storefront/src/pages/quote/QuoteDraft.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@ function QuoteDraft({ setOpenPage }: QuoteDraftProps) {
>
<QuoteTable
ref={quoteTableRef}
updateList={updateList}
updateSummary={updateSummary}
total={total}
getQuoteTableDetails={getQuoteTableDetails}
Expand Down
6 changes: 4 additions & 2 deletions apps/storefront/src/pages/quote/components/QuoteTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ interface ShoppingDetailTableProps {
idEdit?: boolean
isB2BUser: boolean
updateSummary: () => void
updateList: () => void
}

interface SearchProps {
Expand Down Expand Up @@ -111,6 +112,7 @@ function QuoteTable(props: ShoppingDetailTableProps, ref: Ref<unknown>) {
idEdit = true,
isB2BUser,
updateSummary,
updateList,
} = props
const quoteProductQtyMaxLimit = 1000000

Expand Down Expand Up @@ -154,7 +156,7 @@ function QuoteTable(props: ShoppingDetailTableProps, ref: Ref<unknown>) {
B3LStorage.set('b2bQuoteDraftList', quoteDraftAllList)

paginationTableRef.current?.setList([...newListItems])
updateSummary()
updateList()
}

const handleCheckProductQty = async (row: any, value: number | string) => {
Expand Down Expand Up @@ -296,7 +298,7 @@ function QuoteTable(props: ShoppingDetailTableProps, ref: Ref<unknown>) {

B3LStorage.set('b2bQuoteDraftList', b2bQuoteDraftList)

updateSummary()
updateList()

setSearch({
offset: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,26 @@ import {
useEffect,
useState,
} from 'react'
import { useForm } from 'react-hook-form'
import { FieldValues, useForm } from 'react-hook-form'
import styled from '@emotion/styled'
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 { B3SStorage, currencyFormat, snackbar } from '@/utils'
import {
B3SStorage,
calculateProductListPrice,
currencyFormat,
snackbar,
} from '@/utils'

import { ShoppingListProductItem, SimpleObject, Variant } from '../../../types'
import {
AllOptionProps,
ShoppingListProductItem,
SimpleObject,
Variant,
} from '../../../types'
import {
Base64,
getOptionRequestData,
Expand Down Expand Up @@ -79,6 +89,17 @@ interface ChooseOptionsDialogProps {
isB2BUser: boolean
}

interface ChooseOptionsProductProps extends ShoppingListProductItem {
newSelectOptionList: {
optionId: string
optionValue: any
}[]
productId: number
quantity: number
variantId: number
additionalProducts: CustomFieldItems
}

export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) {
const {
isOpen,
Expand All @@ -98,6 +119,14 @@ export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) {
const [variantSku, setVariantSku] = useState('')
const [additionalProducts, setAdditionalProducts] =
useState<CustomFieldItems>({})
const [productPriceChangeOptions, setProductPriceChangeOptions] = useState<
Partial<AllOptionProps>[]
>([])
const [newPrice, setNewPrice] = useState<number>(0)
const [chooseOptionsProduct, setChooseOptionsProduct] = useState<
ChooseOptionsProductProps[]
>([])
const [isRequestLoading, setIsRequestLoading] = useState<boolean>(false)

const setChooseOptionsForm = async (product: ShoppingListProductItem) => {
try {
Expand Down Expand Up @@ -158,9 +187,34 @@ export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) {
}
}

const getProductPriceOptions = (product: ShoppingListProductItem) => {
const newProductPriceChangeOptionLists: Partial<AllOptionProps>[] = []
product.allOptions?.forEach((item) => {
if (
item.type === 'product_list_with_images' ||
item.type === 'product_list' ||
item.type === 'checkbox' ||
item.type === 'rectangles' ||
item.type === 'swatch' ||
item.type === 'radio_buttons' ||
item.type === 'dropdown'
) {
newProductPriceChangeOptionLists.push(item)
}
})

setProductPriceChangeOptions(newProductPriceChangeOptionLists)
}

useEffect(() => {
if (product) {
setChooseOptionsForm(product)
setChooseOptionsProduct([])
setNewPrice(0)
setFormFields([])
if (product?.allOptions?.length) {
getProductPriceOptions(product)
}
} else {
setQuantity(1)
setFormFields([])
Expand All @@ -170,17 +224,19 @@ export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) {
const getProductPrice = (product: ShoppingListProductItem) => {
const { variants = [] } = product

let priceNumber = 0
if (variantSku) {
const priceNumber =
priceNumber =
variants.find((variant) => variant.sku === variantSku)
?.bc_calculated_price?.tax_inclusive || 0
return `${currencyFormat(priceNumber)}`
} else {
priceNumber =
parseFloat(
variants[0]?.bc_calculated_price?.tax_inclusive?.toString()
) || 0
}

const priceNumber =
parseFloat(variants[0]?.bc_calculated_price?.tax_inclusive?.toString()) ||
0
return `${currencyFormat(priceNumber)}`
return priceNumber
}

const handleProductQuantityChange = (e: ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -217,6 +273,8 @@ export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) {
mode: 'all',
})

const formValues = watch()

const getProductVariantId = async (
value: CustomFieldItems,
changeName = ''
Expand Down Expand Up @@ -284,13 +342,86 @@ export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) {
return true
}

const getOptionList = (value: FieldValues) => {
const optionsData = getOptionRequestData(formFields, {}, value)
return Object.keys(optionsData).map((optionId) => ({
optionId,
optionValue: optionsData[optionId]?.toString(),
}))
}

useEffect(() => {
if (
Object.keys(formValues).length &&
formFields.length &&
productPriceChangeOptions.length
) {
const optionList = getOptionList(formValues)
const { variant_id: variantId = '' } = variantInfo || {}
if (!product || !product.id || !variantId || !validateQuantityNumber()) {
return
}

const newChooseOptionsProduct = [
{
...product,
newSelectOptionList: optionList,
productId: product?.id,
quantity: parseInt(quantity.toString(), 10) || 1,
variantId: parseInt(variantId.toString(), 10) || 1,
additionalProducts,
},
]

if (chooseOptionsProduct.length) {
let optionChangeFlag = false
const { newSelectOptionList } = chooseOptionsProduct[0]
newSelectOptionList.forEach((option) => {
const findAttributeId = productPriceChangeOptions.findIndex((item) =>
option.optionId.includes(String(item.id))
)
optionList.forEach((newOption) => {
if (
option.optionId === newOption.optionId &&
option.optionValue !== newOption.optionValue &&
findAttributeId !== -1
) {
optionChangeFlag = true
}
})
})
if (optionChangeFlag) {
setChooseOptionsProduct(newChooseOptionsProduct)
}
} else {
setChooseOptionsProduct(newChooseOptionsProduct)
}
}
}, [formValues, productPriceChangeOptions])

useEffect(() => {
const getProductPrice = async () => {
try {
if (chooseOptionsProduct.length) {
setIsRequestLoading(true)
const products = await calculateProductListPrice(chooseOptionsProduct)
if (products.length && products[0].basePrice) {
setNewPrice(+products[0].basePrice)
}
}
} catch (err) {
console.error(err)
} finally {
setIsRequestLoading(false)
}
}

getProductPrice()
}, [chooseOptionsProduct])

const handleConfirmClicked = () => {
handleSubmit((value) => {
const optionsData = getOptionRequestData(formFields, {}, value)
const optionList = Object.keys(optionsData).map((optionId) => ({
optionId,
optionValue: optionsData[optionId].toString(),
}))
const optionList = getOptionList(value)

const { variant_id: variantId = '' } = variantInfo || {}

Expand Down Expand Up @@ -329,7 +460,7 @@ export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) {
handleLeftClick={handleCancelClicked}
handRightClick={handleConfirmClicked}
title="Choose options"
loading={isLoading}
loading={isLoading || isRequestLoading}
>
<B3Sping isSpinning={isLoading}>
{product && (
Expand Down Expand Up @@ -369,7 +500,9 @@ export default function ChooseOptionsDialog(props: ChooseOptionsDialogProps) {

<FlexItem>
<span>Price:</span>
{getProductPrice(product)}
{currencyFormat(
newPrice * +quantity || getProductPrice(product)
)}
</FlexItem>

<FlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ function ShoppingDetailTable(
snackbar.success('Product updated successfully')
initSearch()
} finally {
setIsRequestLoading(false)
// setIsRequestLoading(false)
}
}

Expand Down
4 changes: 3 additions & 1 deletion apps/storefront/src/shared/global/context/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Dispatch, ReactNode } from 'react'

import { TipMessagesProps } from '@/shared/dynamicallyVariable/context/config'
import { B3SStorage } from '@/utils'

export interface CustomerInfo {
Expand Down Expand Up @@ -81,7 +82,7 @@ export interface GlobalState {
salesRepCompanyId: string
salesRepCompanyName: string
B3UserId: number | string
// tipMessage: TipMessagesProps,
tipMessage: TipMessagesProps
addressConfig?: {
key: string
isEnabled: string
Expand Down Expand Up @@ -171,6 +172,7 @@ export const initState = {
B3SStorage.get('blockPendingAccountOrderCreation') || true,
quoteDetailHasNewMessages: false,
shoppingListClickNode: null,
tipMessage: {},
}

export interface GlobalAction {
Expand Down
20 changes: 11 additions & 9 deletions apps/storefront/src/utils/b3Tip.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
import { ReactElement } from 'react'
import { v1 as uuid } from 'uuid'

import {
AlertTip,
MsgsProps,
} from '@/shared/dynamicallyVariable/context/config'

interface SnackbarItemProps {
duration?: number
jsx?: () => ReactElement
isClose?: boolean
}

interface SnackbarMessageProps extends SnackbarItemProps {
message: string
}
// interface SnackbarMessageProps extends SnackbarItemProps {
// message: string
// }

interface SnackbarProps {
[key: string]: (
message: string | SnackbarMessageProps[],
options?: SnackbarItemProps
) => void
[key: string]: (message: string, options?: SnackbarItemProps) => void
}

const snackbar: SnackbarProps = {}
const globalSnackbar: SnackbarProps = {}

const variants = ['error', 'success', 'info', 'warning']
const variants: AlertTip[] = ['error', 'success', 'info', 'warning']

variants.forEach((variant) => {
snackbar[variant] = (message, options) => {
const msgs = [
const msgs: Array<MsgsProps> = [
{
isClose: options?.isClose || false,
id: uuid(),
Expand Down

0 comments on commit e0908db

Please sign in to comment.