Skip to content

Commit

Permalink
feat: cart page add all to quote
Browse files Browse the repository at this point in the history
  • Loading branch information
BrianJiang2021 committed Feb 22, 2023
1 parent a8167a0 commit e59e73f
Show file tree
Hide file tree
Showing 12 changed files with 368 additions and 8 deletions.
3 changes: 3 additions & 0 deletions apps/storefront/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,9 @@ <h1>Ugly Cornerstone Store Theme with Weird CSS</h1>

</div>

<div class="cart-actions cart-content-padding-right">
<a class="button button--primary" href="/checkout" title="Click here to proceed to checkout">Check out</a>
</div>
</div>
<style>
body {
Expand Down
5 changes: 5 additions & 0 deletions apps/storefront/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
useSetOpen,
useMyQuote,
useRegisteredbctob2b,
useCartToQuote,
} from '@/hooks'

import {
Expand Down Expand Up @@ -89,6 +90,10 @@ export default function App() {
productQuoteEnabled,
cartQuoteEnabled,
})
useCartToQuote({
setOpenPage,
cartQuoteEnabled,
})
// Button to open storefront
useSetOpen(isOpen, openUrl)

Expand Down
4 changes: 4 additions & 0 deletions apps/storefront/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import {
import {
useMyQuote,
} from './useMyQuote'
import {
useCartToQuote,
} from './useCartToQuote'

import {
useQuoteGlobalTip,
Expand Down Expand Up @@ -44,4 +47,5 @@ export {
useQuoteGlobalTip,
useSetCountry,
useGetCountry,
useCartToQuote,
}
302 changes: 302 additions & 0 deletions apps/storefront/src/hooks/useCartToQuote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
import {
useCallback,
SetStateAction,
Dispatch,
useState,
} from 'react'

import {
useB3CartToQuote,
} from '@b3/hooks'

import globalB3 from '@b3/global-b3'

import type {
OpenPageState,
} from '@b3/hooks'

import {
v1 as uuid,
} from 'uuid'
import {
searchB2BProducts,
} from '@/shared/service/b2b'

import {
getCartInfoWithOptions,
} from '@/shared/service/bc'

import {
addQuoteDraftProduce,
} from '@/utils'

import {
PRODUCT_DEFAULT_IMAGE,
} from '@/constants'

import {
useQuoteGlobalTip,
} from './useQuoteGlobalTip'

import {
conversionProductsList,
} from '../pages/shoppingListDetails/shared/config'

interface MutationObserverProps {
setOpenPage: Dispatch<SetStateAction<OpenPageState>>,
cartQuoteEnabled: boolean,
}

const removeElement = (_element: CustomFieldItems) => {
const _parentElement = _element.parentNode
if (_parentElement) {
_parentElement.removeChild(_element)
}
}

interface OpenTipStateProps {
isOpen: boolean,
message: string,
variant: string,
}

interface DiscountsProps {
discountedAmount: number,
id: string,
}

interface ProductOptionsProps {
name: string,
nameId: number | string,
value: number | string,
valueId: number | string,
}

interface ProductItemProps {
brand: string | number,
couponAmount: number,
discountAmount: number,
discounts: Array<any>,
extendedListPrice: number,
extendedSalePrice: number,
giftWrapping: any,
id: string,
imageUrl: string,
isMutable: boolean,
isShippingRequired: boolean,
isTaxable: boolean,
listPrice: number,
name: string,
options: ProductOptionsProps[],
originalPrice: number,
parentId: string | number | null,
productId: number,
quantity: number,
salePrice: number,
sku: string,
type: string,
url: string,
variantId: number,
}

interface LineItemsProps {
customItems: Array<{}>,
digitalItems: Array<{}>,
giftCertificates: Array<{}>,
physicalItems: ProductItemProps[],
}

interface CartInfoProps {
baseAmount: number,
cartAmount: number,
coupons: any,
createdTime: string,
currency: {
code: string,
decimalPlaces: number,
name: string,
symbol: string,
},
customerId: number,
discountAmount: number,
discounts: DiscountsProps[],
email: string,
id: string,
isTaxIncluded: boolean,
lineItems: LineItemsProps,
locale: string,
updatedTime: string,
}

const productTypes: Array<string> = ['customItems', 'digitalItems', 'giftCertificates', 'physicalItems']

const useCartToQuote = ({
setOpenPage,
cartQuoteEnabled,
}: MutationObserverProps) => {
const [openTipState, setOpenTipState] = useState<OpenTipStateProps>({
isOpen: false,
message: '',
variant: '',
})

const addLoadding = (b3CartToQuote: any) => {
const loadingDiv = document.createElement('div')
loadingDiv.setAttribute('id', 'b2b-div-loading')
const loadingBtn = document.createElement('div')
loadingBtn.setAttribute('class', 'b2b-btn-loading')
loadingDiv.appendChild(loadingBtn)
b3CartToQuote.appendChild(loadingDiv)
}

const removeLoadding = () => {
const b2bLoading = document.querySelector('#b2b-div-loading')
if (b2bLoading) removeElement(b2bLoading)
}

const initTip = () => {
setOpenTipState({
isOpen: false,
message: '',
variant: '',
})
}

const getCartProducts = (lineItems: LineItemsProps) => {
const cartProductsList: ProductItemProps[] = []

productTypes.forEach((type: string) => {
if (lineItems[type].length > 0) {
lineItems[type].forEach((product: ProductItemProps) => {
if (!product.parentId) {
cartProductsList.push(product)
}
})
}
})

return cartProductsList
}

const getOptionsList = (options: ProductOptionsProps[] | []) => {
if (options?.length === 0) return []

const option = options.map(({
nameId,
valueId,
value,
}) => {
let optionValue: number | string = valueId.toString()
if (typeof valueId === 'number' && valueId.toString().length === 10) {
optionValue = value
}

return ({
optionId: `attribute[${nameId}]`,
optionValue,
})
})

return option
}

const addToQuote = async () => {
try {
const cartInfoWithOptions: CartInfoProps | any = await getCartInfoWithOptions()

const {
lineItems,
} = cartInfoWithOptions[0]

const cartProductsList = getCartProducts(lineItems)

if (cartProductsList.length === 0) {
setOpenTipState({
isOpen: true,
message: 'No products being added.',
variant: 'error',
})
}

const productsWithSKU = cartProductsList.filter(({
sku,
}) => sku !== '' && sku !== null && sku !== undefined)

const productIds: number[] = []
productsWithSKU.forEach((product: ProductItemProps) => {
if (!productIds.includes(+product.productId)) {
productIds.push(+product.productId)
}
})

const {
productsSearch,
} = await searchB2BProducts({
productIds,
})

const newProductInfo: CustomFieldItems = conversionProductsList(productsSearch)
productsWithSKU.forEach((product) => {
const {
options,
sku,
productId,
name,
quantity,
variantId,
} = product

const optionsList = getOptionsList(options)
const currentProductSearch = newProductInfo.find((product: any) => +product.id === +productId)

const variantItem = currentProductSearch.variants.find((item: CustomFieldItems) => item.sku === sku)

const quoteListitem = {
node: {
id: uuid(),
variantSku: variantItem.sku,
variantId,
productsSearch: currentProductSearch,
primaryImage: variantItem.image_url || PRODUCT_DEFAULT_IMAGE,
productName: name,
quantity: +quantity || 1,
optionList: JSON.stringify(optionsList),
productId,
basePrice: variantItem.bc_calculated_price.as_entered,
tax: variantItem.bc_calculated_price.tax_inclusive - variantItem.bc_calculated_price.tax_exclusive,
},
}

addQuoteDraftProduce(quoteListitem, quantity, optionsList || [])
})

setOpenTipState({
isOpen: true,
message: 'Products were added to your quote.',
variant: 'success',
})
} catch (e) {
console.log(e)
} finally {
removeLoadding()
}
}

const quoteCallBbck = useCallback(() => {
const b3CartToQuote = document.querySelector('#b3CartToQuote')

const b2bLoading = document.querySelector('#b2b-div-loading')
if (b3CartToQuote && !b2bLoading) {
addLoadding(b3CartToQuote)
addToQuote()
}
}, [])

useB3CartToQuote(globalB3['dom.cartActions.container'], quoteCallBbck, cartQuoteEnabled)

useQuoteGlobalTip(openTipState, setOpenPage, initTip)
}

export {
useCartToQuote,
}
12 changes: 9 additions & 3 deletions apps/storefront/src/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ input[type=number]::-webkit-outer-spin-button
width: 100%;
}

#shoppingListBtn, #b3MyQuote {
#shoppingListBtn, #b3MyQuote, #b3CartToQuote {
padding: 0.85714rem 15px;
position: relative;
display: inline-block;
Expand All @@ -135,7 +135,7 @@ input[type=number]::-webkit-outer-spin-button
margin-right: 11px;
}

#b3MyQuote {
#b3MyQuote, #b3CartToQuote {
margin-bottom: 14px;
padding: 0.85714rem 2.28571rem;
order: 1;
Expand All @@ -144,6 +144,12 @@ input[type=number]::-webkit-outer-spin-button
color: #fff;
}

#b3CartToQuote {
float: right;
align-items: center;
flex-direction: column;
}

#shoppingListBtn {
order: 2;
}
Expand Down Expand Up @@ -310,4 +316,4 @@ input[type=number]::-webkit-outer-spin-button
display: flex;
justify-content: center;
align-items: center;
}
}
1 change: 0 additions & 1 deletion apps/storefront/src/pages/quote/QuoteDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,6 @@ const QuoteDetail = () => {
(+role !== 2 && +quoteDetail.status !== 4) && (
<QuoteDetailFooter
quoteId={quoteDetail.id}
quoteDate={quoteDetail?.createdAt?.toString()}
role={role}
/>
)
Expand Down
Loading

0 comments on commit e59e73f

Please sign in to comment.