From 5ad183db66ae42fe67521d4618deb4aad648b0c4 Mon Sep 17 00:00:00 2001 From: BrianJiang2021 <80307788+BrianJiang2021@users.noreply.github.com> Date: Wed, 15 Nov 2023 23:53:53 +0800 Subject: [PATCH] Revert "Sprint/41" (#849) Revert "Sprint/41 (#847)" This reverts commit dd61634aabeed6d41531adbc37e51ecfdd65e0d4. --- README.md | 106 +++++++----------- apps/storefront/src/App.tsx | 44 +++----- .../src/components/HeadlessController.tsx | 13 ++- apps/storefront/src/index.d.ts | 4 +- .../src/pages/accountSetting/utils.ts | 11 +- apps/storefront/src/pages/login/Login.tsx | 34 +++--- apps/storefront/src/pages/login/config.ts | 4 +- .../pages/shoppingLists/ShoppingListsCard.tsx | 2 +- .../customStyleButtton/context/config.ts | 11 +- apps/storefront/src/shared/routes/routes.ts | 20 +--- .../service/b2b/graphql/accountSetting.ts | 4 +- .../src/shared/service/b2b/graphql/address.ts | 8 +- .../src/shared/service/b2b/graphql/orders.ts | 6 +- .../src/shared/service/b2b/graphql/product.ts | 4 +- .../shared/service/b2b/graphql/quickorder.ts | 2 +- .../src/shared/service/b2b/graphql/quote.ts | 8 +- .../shared/service/b2b/graphql/register.ts | 6 + .../service/b2b/graphql/shoppingList.ts | 18 +-- .../src/shared/service/bc/api/login.ts | 5 +- .../src/shared/service/bc/graphql/login.ts | 34 ------ .../src/shared/service/bc/graphql/user.ts | 9 +- .../storefront/src/shared/service/bc/index.ts | 2 +- .../src/shared/service/request/b3Fetch.ts | 6 +- .../src/shared/service/request/fetch.ts | 30 ++++- apps/storefront/src/utils/b3logout.ts | 55 --------- apps/storefront/src/utils/index.ts | 3 +- apps/storefront/src/utils/loginInfo.ts | 93 ++++++++++----- packages/lang/locales/en.json | 3 - 28 files changed, 222 insertions(+), 323 deletions(-) delete mode 100644 apps/storefront/src/utils/b3logout.ts diff --git a/README.md b/README.md index 63a25cd1..b8f7403c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ +# B2B Buyer Portal A monorepo frontend application designed for the BigCommerce B2B Edition Buyer portal. It's built using Turborepo, TypeScript, and React. ## Index -- [Prerequisites](#-prerequisites) - [Core Technologies](#-core-technologies) - [Workspaces](#-workspaces) - [Tools and Libraries](#-tools-and-libraries) @@ -13,23 +13,6 @@ A monorepo frontend application designed for the BigCommerce B2B Edition Buyer p - [Contribution](#-contribution) - [Contact & Support](#-contact--support) -## ☑ Prerequisites - -Before you begin, ensure you have the BigCommerce B2B Edition App installed. To set up your storefront with B2B capabilities, follow the steps below: - -### Step 1: Access the Storefronts Manager -After installing the B2B Edition App, go to the app's dashboard and select the 'Storefronts' section. - -image - -### Step 2: Enable B2B on Your Channel -Choose the channel where you wish to enable B2B functionality. Initially, B2B features can be activated on a single channel only. - -image - -### Step 3: Contact Us for Additional Support -For assistance with activating the remote buyer portal or to inquire about multi-storefront support, which allows you to utilize B2B features across multiple channels, please reach out to our team at b2b@bigcommerce.com, or raise an issue right here in this repository. - ## 🚀 Core Technologies - **Monorepo Management:** Turborepo @@ -41,6 +24,7 @@ For assistance with activating the remote buyer portal or to inquire about multi - **Application:** `/apps/storefront` - A next-gen B2B Edition storefront application. - You can run multiple apps concurrently via turborepo [tasks](https://turbo.build/repo/docs/core-concepts/monorepos/running-tasks). + - **Packages:** - `/packages/eslint-config-b3` - Shared ESLint configurations. - `/packages/tsconfig` - Shared TypeScript configurations. @@ -61,25 +45,23 @@ For assistance with activating the remote buyer portal or to inquire about multi - **Node:** Ensure you have Node.js version >=18.0.0. - **Package Manager:** This project uses Yarn v1.22.17. -## ⚙ Local Development +## ⚙ Local Development -1. Installation of Node and Yarn. +1. Installation of Node and Yarn. - For Node, we recommend using [nvm](https://github.com/nvm-sh/nvm). - Once Node is installed, you can install Yarn by using `npm i -g yarn`. If you'd rather use `pnpm`, visit this [guide](https://dev.to/andreychernykh/yarn-npm-to-pnpm-migration-guide-2n04). 2. Clone the repository. 3. Install dependencies using `yarn`. 4. Copy environment variables: `cp apps/storefront/.env-example apps/storefront/.env`. 5. Update the following values in `.env`: - -- `VITE_B2B_URL`: The URL of the B2B Edition API. -- `VITE_B2B_SOCKET_URL`: The URL of the B2B Edition WebSocket API. -- `VITE_TRANSLATION_SERVICE_URL`: The URL of the translation service API. -- `VITE_CHANNEL_ID`: The ID of the channel to use for the storefront. -- `VITE_STORE_HASH`: The hash of the store to use for the storefront. -- `VITE_CATPCHA_SETKEY`: The reCAPTCHA site key (optional). -- `VITE_B2B_CLIENT_ID`: The client ID of the BigCommerce App from the [developer portal](https://devtools.bigcommerce.com/). -- `VITE_LOCAL_DEBUG`: Set to "FALSE". This is for connecting our local development with the B2B Edition GraphQL API. - + - `VITE_B2B_URL`: The URL of the B2B Edition API. + - `VITE_B2B_SOCKET_URL`: The URL of the B2B Edition WebSocket API. + - `VITE_TRANSLATION_SERVICE_URL`: The URL of the translation service API. + - `VITE_CHANNEL_ID`: The ID of the channel to use for the storefront. + - `VITE_STORE_HASH`: The hash of the store to use for the storefront. + - `VITE_CATPCHA_SETKEY`: The reCAPTCHA site key (optional). + - `VITE_B2B_CLIENT_ID`: The client ID of the BigCommerce App from the [developer portal](https://devtools.bigcommerce.com/). + - `VITE_LOCAL_DEBUG`: Set to "FALSE". This is for connecting our local development with the B2B Edition GraphQL API. 6. Start the development server: `yarn RUN dev`. ## Running Project Locally @@ -87,40 +69,36 @@ For assistance with activating the remote buyer portal or to inquire about multi 1. Activate store channel in the Channels Manager. 2. Configure header and footer scripts: -- Navigate to Channels Manager -> Scripts. -- Add two scripts (e.g., B2BEdition-header, B2BEdition-footer). Ensure you set the correct port for your localhost in the script URLs. -- Edit the header script: - -```html - - - - -``` - -- Edit the footer script: - -```html - -``` + - Navigate to Channels Manager -> Scripts. + - Add two scripts (e.g., B2BEdition-header, B2BEdition-footer). Ensure you set the correct port for your localhost in the script URLs. + - Edit the header script: + + ```html + + + + + ``` + - Edit the footer script: + + ```html + + ``` 3. Verify correct values in the .env file, especially the client_id for the draft app. diff --git a/apps/storefront/src/App.tsx b/apps/storefront/src/App.tsx index e3fde942..8fa0ab84 100644 --- a/apps/storefront/src/App.tsx +++ b/apps/storefront/src/App.tsx @@ -21,7 +21,6 @@ import { getStoreTaxZoneRates, getTemPlateConfig, handleHideRegisterPage, - isUserGotoLogin, loginInfo, openPageByClick, removeBCMenus, @@ -196,7 +195,6 @@ export default function App() { role: +role, isAgenting, } - if (!customerId || isRelogin) { const info = await getCurrentCustomerInfo(dispatch) if (info) { @@ -209,7 +207,7 @@ export default function App() { !href.includes('checkout') && !(customerId && !window.location.hash) ) { - await gotoAllowedAppPage(+userInfo.role, gotoPage) + gotoAllowedAppPage(+userInfo.role, gotoPage) } if (customerId) { @@ -262,34 +260,26 @@ export default function App() { }, [isOpen]) useEffect(() => { - const init = async () => { - if (isClickEnterBtn && isPageComplete && currentClickedUrl) { - // graphql bc - - const gotoUrl = openPageByClick({ - href: currentClickedUrl, - role, - isRegisterAndLogin, - isAgenting, - }) + if (isClickEnterBtn && isPageComplete && currentClickedUrl) { + const gotoUrl = openPageByClick({ + href: currentClickedUrl, + role, + isRegisterAndLogin, + isAgenting, + }) - const isGotoLogin = await isUserGotoLogin(gotoUrl) + setOpenPage({ + isOpen: true, + openUrl: gotoUrl, + }) - setOpenPage({ - isOpen: true, - openUrl: isGotoLogin ? '/login' : gotoUrl + showPageMask(dispatch, false) + storeDispatch( + setGlabolCommonState({ + isClickEnterBtn: false, }) - - showPageMask(dispatch, false) - storeDispatch( - setGlabolCommonState({ - isClickEnterBtn: false, - }) - ) - } + ) } - - init() }, [isPageComplete, currentClickedUrl, clickTimeTarget]) useEffect(() => { diff --git a/apps/storefront/src/components/HeadlessController.tsx b/apps/storefront/src/components/HeadlessController.tsx index 79fe9a0f..d7ca4a97 100644 --- a/apps/storefront/src/components/HeadlessController.tsx +++ b/apps/storefront/src/components/HeadlessController.tsx @@ -12,7 +12,6 @@ import { addProductsToDraftQuote, } from '@/hooks/dom/utils' import { addProductsToShoppingList } from '@/pages/pdp/PDP' -import { CustomStyleContext } from '@/shared/customStyleButtton' import { GlobaledContext } from '@/shared/global' import { superAdminCompanies } from '@/shared/service/b2b' import B3Request from '@/shared/service/request/b3Fetch' @@ -133,9 +132,6 @@ export default function HeadlessController({ registerEnabled, }, } = useContext(GlobaledContext) - const { - state: { addQuoteBtn }, - } = useContext(CustomStyleContext) const { addToQuote: addProductFromPageToQuote } = addProductFromProductPageToQuote(setOpenPage) const { addToQuote: addProductsFromCart } = @@ -193,7 +189,6 @@ export default function HeadlessController({ addProductsFromCart: () => addProductsFromCart(), addProducts: (items) => addProductsToDraftQuote(items, setOpenPage), getCurrent: getDraftQuote, - getButtonInfo: () => addQuoteBtn, }, user: { getProfile: () => ({ ...customerRef.current, role }), @@ -227,12 +222,18 @@ export default function HeadlessController({ salesRepCompanyId: salesRepCompanyIdRef.current, B3UserId: B3UserIdRef.current, }), + logInWithStorefrontToken: (customerJWTToken: string) => + getCurrentCustomerInfo(dispatch, customerJWTToken), graphqlBCProxy: B3Request.graphqlBCProxy, loginWithB2BStorefrontToken: async ( b2bStorefrontJWTToken: string ) => { B3SStorage.set('B2BToken', b2bStorefrontJWTToken) - await getCurrentCustomerInfo(dispatch, b2bStorefrontJWTToken) + await getCurrentCustomerInfo( + dispatch, + undefined, + b2bStorefrontJWTToken + ) }, }, shoppingList: { diff --git a/apps/storefront/src/index.d.ts b/apps/storefront/src/index.d.ts index 91603210..34b7d3d6 100644 --- a/apps/storefront/src/index.d.ts +++ b/apps/storefront/src/index.d.ts @@ -22,7 +22,6 @@ declare interface Window { getCurrent: () => { productList: import('@/components').FormatedQuoteItem[] } - getButtonInfo: () => import('@/shared/customStyleButtton/context/config').AddQuoteBtnProperties } user: { getProfile: () => Record @@ -33,6 +32,9 @@ declare interface Window { getB2BToken: () => string setMasqueradeCompany: (companyId: number) => Promise endMasquerade: () => Promise + logInWithStorefrontToken: ( + customerJWTToken: string + ) => Promise<{ role: number; userType: string } | undefined> graphqlBCProxy: typeof import('@/shared/service/request/b3Fetch').default.graphqlBCProxy loginWithB2BStorefrontToken: ( b2bStorefrontJWTToken: string diff --git a/apps/storefront/src/pages/accountSetting/utils.ts b/apps/storefront/src/pages/accountSetting/utils.ts index 29eb6377..697ebc8d 100644 --- a/apps/storefront/src/pages/accountSetting/utils.ts +++ b/apps/storefront/src/pages/accountSetting/utils.ts @@ -70,16 +70,7 @@ function sendEmail(data: any, extraFields: any) { const val = formFields.find( (field: Partial) => field.name === item.bcLabel ).value - if (item.type === 'date') { - const time = val.split('-') - if (!val && time.length !== 3) return - const [year, month, day] = time - formData.append(`FormFieldYear[1][${key}]`, year) - formData.append(`FormFieldMonth[1][${key}]`, month) - formData.append(`FormFieldDay[1][${key}]`, day) - } else { - formData.append(`FormField[1][${key}]`, val) - } + formData.append(`FormField[1][${key}]`, val) } }) } diff --git a/apps/storefront/src/pages/login/Login.tsx b/apps/storefront/src/pages/login/Login.tsx index 99fb6b12..15936de1 100644 --- a/apps/storefront/src/pages/login/Login.tsx +++ b/apps/storefront/src/pages/login/Login.tsx @@ -19,8 +19,8 @@ import { getBCForcePasswordReset, superAdminEndMasquerade, } from '@/shared/service/b2b' -import { b2bLogin, customerLoginAPI } from '@/shared/service/bc' -import { B3SStorage, getCurrentCustomerInfo, storeHash } from '@/utils' +import { bcLogin } from '@/shared/service/bc' +import { B3SStorage, getCurrentCustomerInfo } from '@/utils' import LoginWidget from './component/LoginWidget' import { @@ -64,7 +64,6 @@ export default function Login(props: RegisteredProps) { const [flag, setLoginFlag] = useState('') const [loginAccount, setLoginAccount] = useState({ emailAddress: '', - password: '', }) const location = useLocation() @@ -196,9 +195,6 @@ export default function Login(props: RegisteredProps) { case '5': str = b3Lang('login.loginTipInfo.accountPrelaunch') break - case '6': - str = b3Lang('login.loginText.deviceCrowdingLogIn') - break default: str = '' } @@ -253,23 +249,21 @@ export default function Login(props: RegisteredProps) { } } else { try { - const loginData = { + const getBCFieldsValue = { email: data.emailAddress, - password: data.password, - storeHash: storeHash as string, - channelId: B3SStorage.get('B3channelId'), + pass: data.password, } - const { - login: { - result: { token, storefrontLoginToken }, - errors, - }, - } = await b2bLogin({ loginData }) + const { data: bcData, errors } = await bcLogin(getBCFieldsValue) - B3SStorage.set('B2BToken', token) - customerLoginAPI(storefrontLoginToken) + if (bcData?.login?.customer) { + B3SStorage.set('loginCustomer', { + emailAddress: bcData.login.customer.email, + phoneNumber: bcData.login.customer.phone, + ...bcData.login.customer, + }) + } - if (errors?.length || !token) { + if (errors?.length || !bcData) { if (errors?.length) { const { message } = errors[0] if ( @@ -283,7 +277,7 @@ export default function Login(props: RegisteredProps) { } getforcePasswordReset(data.emailAddress) } else { - const info = await getCurrentCustomerInfo(dispatch, token) + const info = await getCurrentCustomerInfo(dispatch) if (info?.userType === 3 && info?.role === 3) { navigate('/dashboard') diff --git a/apps/storefront/src/pages/login/config.ts b/apps/storefront/src/pages/login/config.ts index d5b44a8e..b8073716 100644 --- a/apps/storefront/src/pages/login/config.ts +++ b/apps/storefront/src/pages/login/config.ts @@ -9,7 +9,7 @@ export interface QuoteConfig { export type LoginConfig = { emailAddress: string - password: string + password?: string } export interface LoginInfoInit { @@ -182,4 +182,4 @@ export const logout = () => new Promise((resolve, reject) => { }).catch(e => { reject(e) }) -}) +}) \ No newline at end of file diff --git a/apps/storefront/src/pages/shoppingLists/ShoppingListsCard.tsx b/apps/storefront/src/pages/shoppingLists/ShoppingListsCard.tsx index a2ecbd2b..c217ab8d 100644 --- a/apps/storefront/src/pages/shoppingLists/ShoppingListsCard.tsx +++ b/apps/storefront/src/pages/shoppingLists/ShoppingListsCard.tsx @@ -183,7 +183,7 @@ function ShoppingListsCard(props: OrderItemCardProps) { )} > { - addQuoteBtn: AddQuoteBtnProperties globalButtonBackgroundColor: string } diff --git a/apps/storefront/src/shared/routes/routes.ts b/apps/storefront/src/shared/routes/routes.ts index 6b405518..7ff088ae 100644 --- a/apps/storefront/src/shared/routes/routes.ts +++ b/apps/storefront/src/shared/routes/routes.ts @@ -2,8 +2,7 @@ import { lazy } from 'react' import { matchPath } from 'react-router-dom' import { GlobalState, QuoteConfigProps } from '@/shared/global/context/config' -import { customerExists } from '@/shared/service/bc' -import { B3SStorage, isB2bTokenPage, logoutSession } from '@/utils' +import { B3SStorage } from '@/utils' const OrderList = lazy(() => import('../../pages/order/MyOrder')) @@ -379,7 +378,7 @@ const getAllowedRoutes = (globalState: GlobalState): RouteItem[] => { }) } -const gotoAllowedAppPage = async ( +const gotoAllowedAppPage = ( role: number, gotoPage: (url: string) => void, isAccountEnter?: boolean @@ -388,21 +387,6 @@ const gotoAllowedAppPage = async ( gotoPage('/login?loginFlag=3&&closeIsLogout=1') return } - - try { - const { - data: { customer }, - } = await customerExists() - - if (!customer && isB2bTokenPage()) { - logoutSession() - gotoPage('/login?loginFlag=6') - return - } - } catch (err: unknown) { - console.log(err) - } - const { hash, pathname } = window.location let url = hash.split('#')[1] || '' if ( diff --git a/apps/storefront/src/shared/service/b2b/graphql/accountSetting.ts b/apps/storefront/src/shared/service/b2b/graphql/accountSetting.ts index 158fd0ab..9c178b03 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/accountSetting.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/accountSetting.ts @@ -62,7 +62,7 @@ export const updateB2BAccountSettings = ( export const updateBCAccountSettings = ( data: CustomFieldItems ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: updateCustomerAccountSettings(data), }) @@ -74,6 +74,6 @@ export const getB2BAccountSettings = ( }) export const getBCAccountSettings = (): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: customerAccountSettings(), }) diff --git a/apps/storefront/src/shared/service/b2b/graphql/address.ts b/apps/storefront/src/shared/service/b2b/graphql/address.ts index ab1a7690..3037496a 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/address.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/address.ts @@ -269,7 +269,7 @@ export const getB2BAddressConfig = (): CustomFieldItems => export const getBCCustomerAddress = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: getCustomerAddress(data), }) @@ -283,7 +283,7 @@ export const deleteB2BAddress = ( export const deleteBCCustomerAddress = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: deleteCustomerAddress(data), }) @@ -304,12 +304,12 @@ export const createB2BAddress = ( export const createBcAddress = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: createCustomerAddress(data), }) export const updateBcAddress = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: updateCustomerAddress(data), }) diff --git a/apps/storefront/src/shared/service/b2b/graphql/orders.ts b/apps/storefront/src/shared/service/b2b/graphql/orders.ts index 144c1aac..0a2eca21 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/orders.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/orders.ts @@ -198,7 +198,7 @@ export const getB2BAllOrders = (data: CustomFieldItems): CustomFieldItems => }) export const getBCAllOrders = (data: CustomFieldItems): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: allOrders(data, 'customerOrders'), }) @@ -208,7 +208,7 @@ export const getB2BOrderDetails = (id: number): CustomFieldItems => }) export const getBCOrderDetails = (id: number): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: orderDetail(id, 'customerOrder'), }) @@ -218,7 +218,7 @@ export const getOrderStatusType = (): CustomFieldItems => }) export const getBcOrderStatusType = (): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: getOrderStatusTypeQl('bcOrderStatuses'), }) diff --git a/apps/storefront/src/shared/service/b2b/graphql/product.ts b/apps/storefront/src/shared/service/b2b/graphql/product.ts index 105a8547..4fbae831 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/product.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/product.ts @@ -142,7 +142,7 @@ export const searchBcProducts = ( export const getBcVariantInfoBySkus = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: getVariantInfoBySkus(data), }) @@ -156,7 +156,7 @@ export const B2BProductsBulkUploadCSV = ( export const BcProductsBulkUploadCSV = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: productsBulkUploadCSV(data), }) diff --git a/apps/storefront/src/shared/service/b2b/graphql/quickorder.ts b/apps/storefront/src/shared/service/b2b/graphql/quickorder.ts index d7eb2742..235fa3cb 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/quickorder.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/quickorder.ts @@ -57,6 +57,6 @@ export const getOrderedProducts = (data: CustomFieldItems): CustomFieldItems => export const getBcOrderedProducts = ( data: CustomFieldItems ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: orderedProducts(data), }) diff --git a/apps/storefront/src/shared/service/b2b/graphql/quote.ts b/apps/storefront/src/shared/service/b2b/graphql/quote.ts index 4b0a74cd..7b267576 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/quote.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/quote.ts @@ -345,7 +345,7 @@ const getCreatedByUser = (companyId: number, module: number, fn: string) => `{ }` export const getBCCustomerAddresses = (): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: getCustomerAddresses(), }) @@ -360,7 +360,7 @@ export const getB2BQuotesList = (data: CustomFieldItems): CustomFieldItems => }) export const getBCQuotesList = (data: CustomFieldItems): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: getQuotesList(data, 'bc'), }) @@ -373,7 +373,7 @@ export const createQuote = (data: CustomFieldItems): CustomFieldItems => ) export const createBCQuote = (data: CustomFieldItems): CustomFieldItems => - B3Request.graphqlB2B( + B3Request.graphqlB2BWithBCCustomerToken( { query: quoteCreate(data), }, @@ -386,7 +386,7 @@ export const updateB2BQuote = (data: CustomFieldItems): CustomFieldItems => }) export const updateBCQuote = (data: CustomFieldItems): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: quoteUpdate(data), }) diff --git a/apps/storefront/src/shared/service/b2b/graphql/register.ts b/apps/storefront/src/shared/service/b2b/graphql/register.ts index 24683132..ccefe569 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/register.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/register.ts @@ -175,6 +175,12 @@ query getStoreBasicInfo($storeHash: String!, $bcChannelId: Int) { } }` +// const getB2bLogin = () => `mutation Login() { +// login(email: $email, password: $pass) { +// result +// } +// }` + export const getB2BAccountFormFields = (type: number): CustomFieldItems => B3Request.graphqlB2B({ query: getAccountFormFields(type), diff --git a/apps/storefront/src/shared/service/b2b/graphql/shoppingList.ts b/apps/storefront/src/shared/service/b2b/graphql/shoppingList.ts index 33bf7468..d8646f71 100644 --- a/apps/storefront/src/shared/service/b2b/graphql/shoppingList.ts +++ b/apps/storefront/src/shared/service/b2b/graphql/shoppingList.ts @@ -482,14 +482,14 @@ export const deleteB2BShoppingListItem = ( export const getBcShoppingList = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: getCustomerShoppingLists(data), }) export const createBcShoppingList = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: createOrUpdateCustomerShoppingList( 'customerShoppingListsCreate', data @@ -499,7 +499,7 @@ export const createBcShoppingList = ( export const updateBcShoppingList = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: createOrUpdateCustomerShoppingList( 'customerShoppingListsUpdate', data @@ -509,7 +509,7 @@ export const updateBcShoppingList = ( export const duplicateBcShoppingList = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: createOrUpdateCustomerShoppingList( 'customerShoppingListsDuplicate', data @@ -517,35 +517,35 @@ export const duplicateBcShoppingList = ( }) export const deleteBcShoppingList = (id: number): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: deleteCustomerShoppingList(id), }) export const getBcShoppingListDetails = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: getCustomerShoppingListDetails(data), }) export const addProductToBcShoppingList = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: addItemsToBcShoppingList(data), }) export const updateBcShoppingListsItem = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: updateCustomerShoppingListsItem(data), }) export const deleteBcShoppingListItem = ( data: CustomFieldItems = {} ): CustomFieldItems => - B3Request.graphqlB2B({ + B3Request.graphqlB2BWithBCCustomerToken({ query: deleteCustomerShoppingListItem(data), }) diff --git a/apps/storefront/src/shared/service/bc/api/login.ts b/apps/storefront/src/shared/service/bc/api/login.ts index 44aa9c50..79496bd8 100644 --- a/apps/storefront/src/shared/service/bc/api/login.ts +++ b/apps/storefront/src/shared/service/bc/api/login.ts @@ -9,8 +9,5 @@ export const getBCForgotPassword = (data: CustomFieldItems): CustomFieldItems => data ) -export const getCurrentCustomerJWT = (data: CustomFieldItems) => +export const getBcCurrentJWT = (data: CustomFieldItems) => B3Request.get(`${bcBaseUrl()}/customer/current.jwt`, RequestType.BCRest, data) - -export const customerLoginAPI = (storefrontLoginToken: string) => - fetch(`${bcBaseUrl()}/login/token/${storefrontLoginToken}`, { method: 'GET' }) diff --git a/apps/storefront/src/shared/service/bc/graphql/login.ts b/apps/storefront/src/shared/service/bc/graphql/login.ts index e6a85f1d..a68cdc19 100644 --- a/apps/storefront/src/shared/service/bc/graphql/login.ts +++ b/apps/storefront/src/shared/service/bc/graphql/login.ts @@ -1,24 +1,5 @@ import B3Request from '../../request/b3Fetch' -interface LoginData { - loginData: { - storeHash: string - email: string - password: string - channelId: number - } -} - -interface UserLoginResult { - login: { - result: { - token: string - storefrontLoginToken: string - } - errors?: { message: string }[] - } -} - const getbcLogin = () => `mutation Login($email: String!, $pass: String!) { login(email: $email, password: $pass) { result, @@ -39,21 +20,6 @@ const logoutLogin = () => `mutation Logout { } }` -const getB2bLogin = `mutation Login($loginData: UserLoginType!) { - login(loginData: $loginData) { - result{ - storefrontLoginToken - token - } - } -}` - -export const b2bLogin = (variables: LoginData): Promise => - B3Request.graphqlB2B({ - query: getB2bLogin, - variables, - }) - export const bcLogin = (data: CustomFieldItems): CustomFieldItems => B3Request.graphqlBC({ query: getbcLogin(), diff --git a/apps/storefront/src/shared/service/bc/graphql/user.ts b/apps/storefront/src/shared/service/bc/graphql/user.ts index 4300e243..7b64ba18 100644 --- a/apps/storefront/src/shared/service/bc/graphql/user.ts +++ b/apps/storefront/src/shared/service/bc/graphql/user.ts @@ -12,15 +12,8 @@ const getCustomer = () => `query customer { }` const getCustomerInfo = (): CustomFieldItems => - B3Request.graphqlBCProxy({ - query: getCustomer(), - }) - -const customerExists = (): CustomFieldItems => B3Request.graphqlBC({ query: getCustomer(), }) -export { customerExists, getCustomerInfo } - -// export default getCustomerInfo +export default getCustomerInfo diff --git a/apps/storefront/src/shared/service/bc/index.ts b/apps/storefront/src/shared/service/bc/index.ts index b0110f54..e353d73b 100644 --- a/apps/storefront/src/shared/service/bc/index.ts +++ b/apps/storefront/src/shared/service/bc/index.ts @@ -4,4 +4,4 @@ export { default as getBCProductVariantId } from './api/product' export { default as getBCRegisterCustomFields } from './api/register' export { default as getActiveBcCurrency } from './graphql/currency' export * from './graphql/login' -export * from './graphql/user' +export { default as getCustomerInfo } from './graphql/user' diff --git a/apps/storefront/src/shared/service/request/b3Fetch.ts b/apps/storefront/src/shared/service/request/b3Fetch.ts index 86fc400d..ff4eadcb 100644 --- a/apps/storefront/src/shared/service/request/b3Fetch.ts +++ b/apps/storefront/src/shared/service/request/b3Fetch.ts @@ -71,7 +71,11 @@ const B3Request = { */ graphqlB2B: function post(data: T, customMessage = false): Promise { const config = { - Authorization: `Bearer ${B3SStorage.get('B2BToken') || ''}`, + Authorization: `Bearer ${ + B3SStorage.get('B2BToken') || + B3SStorage.get('currentCustomerJWTToken') || + '' + }`, } return graphqlRequest(RequestType.B2BGraphql, data, config, customMessage) }, diff --git a/apps/storefront/src/shared/service/request/fetch.ts b/apps/storefront/src/shared/service/request/fetch.ts index 2c021581..1f68d58a 100644 --- a/apps/storefront/src/shared/service/request/fetch.ts +++ b/apps/storefront/src/shared/service/request/fetch.ts @@ -1,4 +1,4 @@ -import { snackbar } from '@/utils' +import { B3SStorage, getCurrentJwt, snackbar } from '@/utils' import { RequestType } from './base' @@ -29,6 +29,34 @@ function b3Fetch( reject(message) return } + // jwt 15 minutes expected + if ( + res?.errors?.length && + res.errors[0].message === 'JWT token is expired' + ) { + try { + await getCurrentJwt() + const config = { + Authorization: `Bearer ${ + B3SStorage.get('currentCustomerJWTToken') || '' + }`, + } + const headers = { + 'content-type': 'application/json', + ...config, + } + + const reInit = { + headers, + method: 'POST', + body: init.body, + } + const newRes = await b3Fetch(path, reInit, type) + resolve(newRes) + } catch (e) { + console.error(e) + } + } if ( type === RequestType.BCRest && path.includes('api/storefront/carts') diff --git a/apps/storefront/src/utils/b3logout.ts b/apps/storefront/src/utils/b3logout.ts deleted file mode 100644 index 4ef0a111..00000000 --- a/apps/storefront/src/utils/b3logout.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { customerExists } from '@/shared/service/bc' - -import { B3SStorage } from './b3Storage' - -export const logoutSession = () => { - B3SStorage.delete('B3UserId') - B3SStorage.delete('companyStatus') - B3SStorage.delete('B3Role') - B3SStorage.delete('B3CustomerInfo') - B3SStorage.delete('realRole') - B3SStorage.delete('B3CustomerInfo') - B3SStorage.delete('B3CustomerId') - B3SStorage.delete('nextPath') - B3SStorage.delete('B3EmailAddress') -} - -export const isB2bTokenPage = (gotoUrl?: string) => { - - const noB2bTokenPages = ['quoteDraft', 'quoteDetail', 'register', 'login'] - - if (gotoUrl) { - return !noB2bTokenPages.some((item: string) => gotoUrl.includes(item)) - } - - const { hash = '' } = window.location - - if (!hash.includes('#/')) { - return false - } - - return !noB2bTokenPages.some((item: string) => hash.includes(item)) -} - -export const isUserGotoLogin = async (gotoUrl: string) => { - const isB2bPage = isB2bTokenPage(gotoUrl) - let isGotoLogin = false - try { - const { - data: { - customer - } - } = await customerExists() - - if (!customer && isB2bPage) { - logoutSession() - isGotoLogin = true - } - } catch (err: unknown) { - console.log(err) - } - - return isGotoLogin -} - -export default {} diff --git a/apps/storefront/src/utils/index.ts b/apps/storefront/src/utils/index.ts index a9d04003..83c39634 100644 --- a/apps/storefront/src/utils/index.ts +++ b/apps/storefront/src/utils/index.ts @@ -45,12 +45,12 @@ import { clearCurrentCustomerInfo, getCompanyUserInfo, getCurrentCustomerInfo, + getCurrentJwt, getSearchVal, loginInfo, } from './loginInfo' import { validatorRules } from './validatorRules' -export { isB2bTokenPage, isUserGotoLogin,logoutSession } from './b3logout' export * from './b3Product/b3Product' export * from './basicConfig' export * from './masquerade' @@ -81,6 +81,7 @@ export { getCompanyUserInfo, getCookie, getCurrentCustomerInfo, + getCurrentJwt, getDefaultCurrencyInfo, getLineNumber, getLogo, diff --git a/apps/storefront/src/utils/loginInfo.ts b/apps/storefront/src/utils/loginInfo.ts index 9fc3e1ad..b1408da6 100644 --- a/apps/storefront/src/utils/loginInfo.ts +++ b/apps/storefront/src/utils/loginInfo.ts @@ -6,7 +6,7 @@ import { getBCGraphqlToken, getUserCompany, } from '@/shared/service/b2b' -import { getCurrentCustomerJWT, getCustomerInfo } from '@/shared/service/bc' +import { getBcCurrentJWT, getCustomerInfo } from '@/shared/service/bc' import { B3LStorage, B3SStorage, storeHash } from '@/utils' const { VITE_B2B_CLIENT_ID, VITE_LOCAL_DEBUG } = import.meta.env @@ -23,6 +23,15 @@ interface ChannelIdProps { translationVersion: number } +type B2BToken = { + authorization: { + result: { + token: string + loginType: null | string + } + } +} + // B3Role = { // ADMIN: '0', // SENIOR: '1', @@ -113,6 +122,7 @@ export const clearCurrentCustomerInfo = async (dispatch: DispatchProps) => { B3SStorage.set('B3EmailAddress', '') B3SStorage.set('B3Role', '') B3SStorage.set('isB2BUser', false) + B3SStorage.set('currentCustomerJWTToken', '') B3SStorage.set('B2BToken', false) B3SStorage.set('B3UserId', '') @@ -156,6 +166,39 @@ export const clearCurrentCustomerInfo = async (dispatch: DispatchProps) => { }) } +export const getCurrentJwt = async () => { + try { + const res = await getBcCurrentJWT({ + app_client_id: VITE_B2B_CLIENT_ID, + }) + + B3SStorage.set('currentCustomerJWTToken', res) + return res + } catch (error) { + console.log(error) + } + return undefined +} + +const getB2BTokenWithJWTToken = async (userType: number, jwtToken: string) => { + try { + const channelId = B3SStorage.get('B3channelId') || 1 + + if (userType === 3) { + const data = await getB2BToken(jwtToken, channelId) + if (data) { + const B2BToken = (data as B2BToken).authorization.result.token + B3SStorage.set('B2BToken', B2BToken) + const { loginType } = (data as B2BToken).authorization.result + + sessionStorage.setItem('loginType', JSON.stringify(loginType || null)) + } + } + } catch (error) { + console.log(error) + } +} + // companyStatus // 99: default, Distinguish between bc and b2b // 0: pending @@ -253,7 +296,7 @@ export const getCompanyUserInfo = async ( isB2BUser = false ) => { try { - if (!emailAddress || !customerId) return undefined + if (!emailAddress) return undefined const { companyUserInfo: { @@ -292,42 +335,23 @@ export const getCompanyUserInfo = async ( return undefined } -const loginWithCurrentCustomerJWT = async () => { - const channelId = B3SStorage.get('B3channelId') - const prevCurrentCustomerJWT = B3SStorage.get('currentCustomerJWT') - const currentCustomerJWT = await getCurrentCustomerJWT({ - app_client_id: VITE_B2B_CLIENT_ID, - }) - - if ( - currentCustomerJWT.includes('errors') || - prevCurrentCustomerJWT === currentCustomerJWT - ) - return undefined - - B3SStorage.set('currentCustomerJWT', currentCustomerJWT) - const data = await getB2BToken(currentCustomerJWT, channelId) - const B2BToken = data.authorization.result.token - B3SStorage.set('B2BToken', B2BToken) - - return B2BToken -} - export const getCurrentCustomerInfo = async ( dispatch: DispatchProps, + jwtToken?: string, b2bToken?: string ) => { - if (!(b2bToken || B3LStorage.get('B2BToken'))) { - if (!(await loginWithCurrentCustomerJWT())) { - return undefined - } - } try { - const data = await getCustomerInfo() + let loginCustomer = B3SStorage.get('loginCustomer') - if (data?.detail) return undefined + if (!loginCustomer) { + const { + data: { customer }, + } = await getCustomerInfo() - const loginCustomer = data.data.customer + loginCustomer = customer + + if (!customer) return undefined + } const { entityId: customerId = '', @@ -347,6 +371,13 @@ export const getCurrentCustomerInfo = async ( if (companyUserInfo && customerId) { const { userType, role, id } = companyUserInfo + if (!b2bToken) { + await getB2BTokenWithJWTToken( + userType, + jwtToken || (await getCurrentJwt()) + ) + } + const [companyInfo] = await Promise.all([ getCompanyInfo(id, role, userType), agentInfo(customerId, role, id, dispatch), diff --git a/packages/lang/locales/en.json b/packages/lang/locales/en.json index f963cb3a..47ee82d5 100644 --- a/packages/lang/locales/en.json +++ b/packages/lang/locales/en.json @@ -167,8 +167,6 @@ "shoppingLists.duplicateShoppingList": "Duplicate shopping list", "shoppingLists.save": "Save", "shoppingLists.name": "Name", - "shoppingLists.title": "Add to list", - "shoppingLists.addButtonText": "Add to list", "shoppingLists.description": "Description", "shoppingLists.card.createdBy": "Created by:", "shoppingLists.card.products": "Products:", @@ -507,7 +505,6 @@ "login.loginTipInfo.accountincorrect": "Your email address or password is incorrect. Please try again. If you've forgotten your sign in details, just click the 'Forgot your password?' link below.", "login.loginTipInfo.accountPrelaunch": "You can not login to the Buyer Portal while the store is in prelaunch or maintenance mode. Please set the store live, or login inside the customer admin panel.", "login.loginText.forgotPasswordText": "Forgot your password?", - "login.loginText.deviceCrowdingLogIn": "The user has logged out, please log in again", "login.loginText.password": "Password", "login.registerLogo": "register Logo",