🤖 test cases for home and navbar component

This commit is contained in:
Mian Muhammad 2022-04-20 15:29:34 +05:00
parent a46057c5ef
commit 436e2ed8df
334 changed files with 35721 additions and 8428 deletions

View File

@ -25,6 +25,7 @@ Demo live at: [demo.vercel.store](https://demo.vercel.store/)
yarn # run this comman in root folder of the mono repo
yarn dev
```
> If you encounter any problems while installing and running for the first time, please see the Troubleshoot section
## Features

5
cypress.json Normal file
View File

@ -0,0 +1,5 @@
{
"baseUrl": "http://localhost:3000",
"viewportHeight": 1000,
"viewportWidth": 1280
}

View File

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -0,0 +1,18 @@
describe('Header', () => {
beforeEach(() => {
cy.visit('/')
})
it('links to the correct pages', () => {
cy.getBySel('logo').click()
cy.location('pathname').should('eq', '/')
cy.getBySel('nav-link-search').click()
cy.location('pathname').should('eq', '/search')
cy.getBySel('nav-link-home-page').click({ multiple: true })
cy.location('pathname').should('eq', '/search/featured')
})
it('the search bar returns the correct search results', () => {})
})

View File

@ -0,0 +1,29 @@
describe('Home Page', () => {
it('displays all 3 products on the home page', () => {
cy.visit('/')
cy.getBySel('product-tag')
.eq(0)
.within(() => {
cy.getBySel('product-name').should(
'contain',
'New Short Sleeve T-Shirt'
)
cy.getBySel('product-price').should('contain', '$25.00 USD')
})
cy.getBySel('product-tag')
.eq(1)
.within(() => {
cy.getBySel('product-name').should('contain', 'Lightweight Jacket')
cy.getBySel('product-price').should('contain', '$249.99 USD')
})
cy.getBySel('product-tag')
.eq(2)
.within(() => {
cy.getBySel('product-name').should('contain', 'Shirt')
cy.getBySel('product-price').should('contain', '$25.00 USD')
})
})
})

22
cypress/plugins/index.js Normal file
View File

@ -0,0 +1,22 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

View File

@ -0,0 +1,29 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
Cypress.Commands.add('getBySel', (selector, ...args) => {
return cy.get(`[data-test=${selector}]`, ...args)
})

20
cypress/support/index.js Normal file
View File

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

25442
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,9 +11,12 @@
"dev": "turbo run dev",
"start": "turbo run start",
"types": "turbo run types",
"prettier-fix": "prettier --write ."
"prettier-fix": "prettier --write .",
"cypress:open": "cypress open",
"cypress:run": "cypress run"
},
"devDependencies": {
"cypress": "^9.5.4",
"husky": "^7.0.4",
"prettier": "^2.5.1",
"turbo": "^1.1.2"

View File

@ -42,7 +42,7 @@ const getCheckout: CheckoutEndpoint['handlers']['getCheckout'] = async ({
store_hash: config.storeHash,
customer_id: customerId,
channel_id: config.storeChannelId,
redirect_to: data.checkout_url.replace(config.storeUrl, ""),
redirect_to: data.checkout_url.replace(config.storeUrl, ''),
}
let token = jwt.sign(payload, config.storeApiClientSecret!, {
algorithm: 'HS256',

View File

@ -4,8 +4,14 @@ import type {
HookFetcherContext,
} from '@vercel/commerce/utils/types'
import { ValidationError } from '@vercel/commerce/utils/errors'
import useRemoveItem, { UseRemoveItem } from '@vercel/commerce/cart/use-remove-item'
import type { Cart, LineItem, RemoveItemHook } from '@vercel/commerce/types/cart'
import useRemoveItem, {
UseRemoveItem,
} from '@vercel/commerce/cart/use-remove-item'
import type {
Cart,
LineItem,
RemoveItemHook,
} from '@vercel/commerce/types/cart'
import useCart from './use-cart'
export type RemoveItemFn<T = any> = T extends LineItem

View File

@ -5,7 +5,9 @@ import type {
HookFetcherContext,
} from '@vercel/commerce/utils/types'
import { ValidationError } from '@vercel/commerce/utils/errors'
import useUpdateItem, { UseUpdateItem } from '@vercel/commerce/cart/use-update-item'
import useUpdateItem, {
UseUpdateItem,
} from '@vercel/commerce/cart/use-update-item'
import type { LineItem, UpdateItemHook } from '@vercel/commerce/types/cart'
import { handler as removeItemHandler } from './use-remove-item'
import useCart from './use-cart'

View File

@ -1,5 +1,7 @@
import { SWRHook } from '@vercel/commerce/utils/types'
import useCheckout, { UseCheckout } from '@vercel/commerce/checkout/use-checkout'
import useCheckout, {
UseCheckout,
} from '@vercel/commerce/checkout/use-checkout'
export default useCheckout as UseCheckout<typeof handler>

View File

@ -1,4 +1,6 @@
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/address/use-add-item'
import useAddItem, {
UseAddItem,
} from '@vercel/commerce/customer/address/use-add-item'
import { MutationHook } from '@vercel/commerce/utils/types'
export default useAddItem as UseAddItem<typeof handler>

View File

@ -1,4 +1,6 @@
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/card/use-add-item'
import useAddItem, {
UseAddItem,
} from '@vercel/commerce/customer/card/use-add-item'
import { MutationHook } from '@vercel/commerce/utils/types'
export default useAddItem as UseAddItem<typeof handler>

View File

@ -1,5 +1,7 @@
import { SWRHook } from '@vercel/commerce/utils/types'
import useCustomer, { UseCustomer } from '@vercel/commerce/customer/use-customer'
import useCustomer, {
UseCustomer,
} from '@vercel/commerce/customer/use-customer'
import type { CustomerHook } from '../types/customer'
export default useCustomer as UseCustomer<typeof handler>

View File

@ -1,4 +1,7 @@
import { getCommerceProvider, useCommerce as useCoreCommerce } from '@vercel/commerce'
import {
getCommerceProvider,
useCommerce as useCoreCommerce,
} from '@vercel/commerce'
import { bigcommerceProvider, BigcommerceProvider } from './provider'
export { bigcommerceProvider }

View File

@ -68,7 +68,10 @@ Then, open [/site/.env.template](/site/.env.template) and add the provider name
Using BigCommerce as an example. The first thing to do is export a `CommerceProvider` component that includes a `provider` object with all the handlers that can be used for hooks:
```tsx
import { getCommerceProvider, useCommerce as useCoreCommerce } from '@vercel/commerce'
import {
getCommerceProvider,
useCommerce as useCoreCommerce,
} from '@vercel/commerce'
import { bigcommerceProvider, BigcommerceProvider } from './provider'
export { bigcommerceProvider }
@ -212,25 +215,26 @@ export const handler: MutationHook<AddItemHook> = {
```
## Showing progress and features
When creating a PR for a new provider, include this list in the PR description and mark the progress as you push so we can organize the code review. Not all points are required (but advised) so make sure to keep the list up to date.
**Status**
* [ ] CommerceProvider
* [ ] Schema & TS types
* [ ] API Operations - Get all collections
* [ ] API Operations - Get all pages
* [ ] API Operations - Get all products
* [ ] API Operations - Get page
* [ ] API Operations - Get product
* [ ] API Operations - Get Shop Info (categories and vendors working — `vendors` query still a WIP PR on Reaction)
* [ ] Hook - Add Item
* [ ] Hook - Remove Item
* [ ] Hook - Update Item
* [ ] Hook - Get Cart (account-tied carts working, anonymous carts working, cart reconciliation working)
* [ ] Auth (based on a WIP PR on Reaction - still need to implement refresh tokens)
* [ ] Customer information
* [ ] Product attributes - Size, Colors
* [ ] Custom checkout
* [ ] Typing (in progress)
* [ ] Tests
- [ ] CommerceProvider
- [ ] Schema & TS types
- [ ] API Operations - Get all collections
- [ ] API Operations - Get all pages
- [ ] API Operations - Get all products
- [ ] API Operations - Get page
- [ ] API Operations - Get product
- [ ] API Operations - Get Shop Info (categories and vendors working — `vendors` query still a WIP PR on Reaction)
- [ ] Hook - Add Item
- [ ] Hook - Remove Item
- [ ] Hook - Update Item
- [ ] Hook - Get Cart (account-tied carts working, anonymous carts working, cart reconciliation working)
- [ ] Auth (based on a WIP PR on Reaction - still need to implement refresh tokens)
- [ ] Customer information
- [ ] Product attributes - Size, Colors
- [ ] Custom checkout
- [ ] Typing (in progress)
- [ ] Tests

View File

@ -3,8 +3,10 @@ import { CommerceAPIError } from '../utils/errors'
import isAllowedOperation from '../utils/is-allowed-operation'
import type { GetAPISchema } from '..'
const cartEndpoint: GetAPISchema<any, CartSchema<any>>['endpoint']['handler'] =
async (ctx) => {
const cartEndpoint: GetAPISchema<
any,
CartSchema<any>
>['endpoint']['handler'] = async (ctx) => {
const { req, res, handlers, config } = ctx
if (

View File

@ -3,8 +3,10 @@ import { CommerceAPIError } from '../utils/errors'
import isAllowedOperation from '../utils/is-allowed-operation'
import type { GetAPISchema } from '..'
const logoutEndpoint: GetAPISchema<any, LogoutSchema>['endpoint']['handler'] =
async (ctx) => {
const logoutEndpoint: GetAPISchema<
any,
LogoutSchema
>['endpoint']['handler'] = async (ctx) => {
const { req, res, handlers } = ctx
if (

View File

@ -3,8 +3,10 @@ import { CommerceAPIError } from '../utils/errors'
import isAllowedOperation from '../utils/is-allowed-operation'
import type { GetAPISchema } from '..'
const signupEndpoint: GetAPISchema<any, SignupSchema>['endpoint']['handler'] =
async (ctx) => {
const signupEndpoint: GetAPISchema<
any,
SignupSchema
>['endpoint']['handler'] = async (ctx) => {
const { req, res, handlers, config } = ctx
if (

View File

@ -1,7 +1,9 @@
import { useCallback } from 'react'
import type { MutationHook } from '@vercel/commerce/utils/types'
import type { RemoveItemHook } from '@vercel/commerce/types/cart'
import useRemoveItem, { UseRemoveItem } from '@vercel/commerce/cart/use-remove-item'
import useRemoveItem, {
UseRemoveItem,
} from '@vercel/commerce/cart/use-remove-item'
import type { CommercejsCart } from '../types/cart'
import { normalizeCart } from '../utils/normalize-cart'
import useCart from './use-cart'

View File

@ -6,7 +6,9 @@ import type {
import { ValidationError } from '@vercel/commerce/utils/errors'
import debounce from 'lodash.debounce'
import { useCallback } from 'react'
import useUpdateItem, { UseUpdateItem } from '@vercel/commerce/cart/use-update-item'
import useUpdateItem, {
UseUpdateItem,
} from '@vercel/commerce/cart/use-update-item'
import type { CommercejsCart } from '../types/cart'
import { normalizeCart } from '../utils/normalize-cart'
import useCart from './use-cart'

View File

@ -2,7 +2,9 @@ import type { GetCheckoutHook } from '@vercel/commerce/types/checkout'
import { useMemo } from 'react'
import { SWRHook } from '@vercel/commerce/utils/types'
import useCheckout, { UseCheckout } from '@vercel/commerce/checkout/use-checkout'
import useCheckout, {
UseCheckout,
} from '@vercel/commerce/checkout/use-checkout'
import useSubmitCheckout from './use-submit-checkout'
import { useCheckoutContext } from '@components/checkout/context'

View File

@ -1,7 +1,9 @@
import type { AddItemHook } from '@vercel/commerce/types/customer/address'
import type { MutationHook } from '@vercel/commerce/utils/types'
import { useCallback } from 'react'
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/address/use-add-item'
import useAddItem, {
UseAddItem,
} from '@vercel/commerce/customer/address/use-add-item'
import { useCheckoutContext } from '@components/checkout/context'
export default useAddItem as UseAddItem<typeof handler>

View File

@ -1,7 +1,9 @@
import type { AddItemHook } from '@vercel/commerce/types/customer/card'
import type { MutationHook } from '@vercel/commerce/utils/types'
import { useCallback } from 'react'
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/card/use-add-item'
import useAddItem, {
UseAddItem,
} from '@vercel/commerce/customer/card/use-add-item'
import { useCheckoutContext } from '@components/checkout/context'
export default useAddItem as UseAddItem<typeof handler>

View File

@ -1,7 +1,9 @@
import Cookies from 'js-cookie'
import { decode } from 'jsonwebtoken'
import { SWRHook } from '@vercel/commerce/utils/types'
import useCustomer, { UseCustomer } from '@vercel/commerce/customer/use-customer'
import useCustomer, {
UseCustomer,
} from '@vercel/commerce/customer/use-customer'
import { CUSTOMER_COOKIE, API_URL } from '../constants'
import type { CustomerHook } from '../types/customer'

View File

@ -1,5 +1,8 @@
import { commercejsProvider, CommercejsProvider } from './provider'
import { getCommerceProvider, useCommerce as useCoreCommerce } from '@vercel/commerce'
import {
getCommerceProvider,
useCommerce as useCoreCommerce,
} from '@vercel/commerce'
export { commercejsProvider }
export type { CommercejsProvider }

View File

@ -24,12 +24,12 @@ KIBO_AUTH_URL='https://home.mozu.com'
- `KIBO_CLIENT_ID` - Unique Application (Client) ID of your Application
- `KIBO_SHARED_SECRET` - Secret API key used to authenticate application/client id.
Your Kibo Client ID and Shared Secret can be found from your [Kibo eCommerce Dev Center](https://mozu.com/login)
Visit [Kibo documentation](https://apidocs.kibong-perf.com/?spec=graphql#auth) for more details on API authentication
Based on the config, this integration will handle Authenticating your application against the Kibo API using the Kibo Client ID and Kibo Shared Secret.
## Contribute
Our commitment to Open Source can be found [here](https://vercel.com/oss).

View File

@ -2,10 +2,12 @@ export type Maybe<T> = T | null
export type Exact<T extends { [key: string]: unknown }> = {
[K in keyof T]: T[K]
}
export type MakeOptional<T, K extends keyof T> = Omit<T, K> &
{ [SubKey in K]?: Maybe<T[SubKey]> }
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> &
{ [SubKey in K]: Maybe<T[SubKey]> }
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & {
[SubKey in K]?: Maybe<T[SubKey]>
}
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
[SubKey in K]: Maybe<T[SubKey]>
}
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: string

View File

@ -74,7 +74,7 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
if (!cookieHandler.getAccessToken()) {
let anonymousShopperTokenResponse = await cookieHandler.getAnonymousToken()
accessToken = anonymousShopperTokenResponse.accessToken;
accessToken = anonymousShopperTokenResponse.accessToken
} else {
accessToken = cookieHandler.getAccessToken()
}

View File

@ -16,7 +16,8 @@ const getCart: CartEndpoint['handlers']['getCart'] = async ({
let accessToken = null
if (!cookieHandler.getAccessToken()) {
let anonymousShopperTokenResponse = await cookieHandler.getAnonymousToken()
let anonymousShopperTokenResponse =
await cookieHandler.getAnonymousToken()
const response = anonymousShopperTokenResponse.response
accessToken = anonymousShopperTokenResponse.accessToken
cookieHandler.setAnonymousShopperCookie(response)

View File

@ -1,8 +1,8 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import cartEndpoint from '@vercel/commerce/api/endpoints/cart'
import type { KiboCommerceAPI } from '../..'
import getCart from './get-cart';
import addItem from './add-item';
import getCart from './get-cart'
import addItem from './add-item'
import updateItem from './update-item'
import removeItem from './remove-item'

View File

@ -9,9 +9,9 @@ const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({
body: { search, categoryId, brandId, sort },
config,
}) => {
const pageSize = 100;
const filters = {};
const startIndex = 0;
const pageSize = 100
const filters = {}
const startIndex = 0
const variables = buildProductSearchVars({
categoryCode: categoryId,
pageSize,
@ -20,12 +20,14 @@ const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({
filters,
startIndex,
})
const {data} = await config.fetch(productSearchQuery, { variables });
const found = data?.products?.items?.length > 0 ? true : false;
let productsResponse= data?.products?.items.map((item: any) =>normalizeProduct(item,config));
const products: Product[] = found ? productsResponse : [];
const { data } = await config.fetch(productSearchQuery, { variables })
const found = data?.products?.items?.length > 0 ? true : false
let productsResponse = data?.products?.items.map((item: any) =>
normalizeProduct(item, config)
)
const products: Product[] = found ? productsResponse : []
res.status(200).json({ data: { products, found } });
res.status(200).json({ data: { products, found } })
}
export default getProducts

View File

@ -3,13 +3,10 @@ import type { CustomerEndpoint } from '.'
import { getCustomerAccountQuery } from '../../queries/get-customer-account-query'
import { normalizeCustomer } from '../../../lib/normalize'
const getLoggedInCustomer: CustomerEndpoint['handlers']['getLoggedInCustomer'] = async ({
req,
res,
config,
}) => {
const getLoggedInCustomer: CustomerEndpoint['handlers']['getLoggedInCustomer'] =
async ({ req, res, config }) => {
const cookieHandler = new CookieHandler(config, req, res)
let accessToken = cookieHandler.getAccessToken();
let accessToken = cookieHandler.getAccessToken()
if (!cookieHandler.isShopperCookieAnonymous()) {
const { data } = await config.fetch(getCustomerAccountQuery, undefined, {

View File

@ -15,6 +15,4 @@ const loginApi = createEndpoint<LoginAPI>({
handlers,
})
export default loginApi;
export default loginApi

View File

@ -1,7 +1,7 @@
import { FetcherError } from '@vercel/commerce/utils/errors'
import type { LoginEndpoint } from '.'
import { loginMutation } from '../../mutations/login-mutation'
import { prepareSetCookie } from '../../../lib/prepare-set-cookie';
import { prepareSetCookie } from '../../../lib/prepare-set-cookie'
import { setCookies } from '../../../lib/set-cookie'
import { getCookieExpirationDate } from '../../../lib/get-cookie-expiration-date'
@ -14,7 +14,6 @@ const login: LoginEndpoint['handlers']['login'] = async ({
config,
commerce,
}) => {
if (!(email && password)) {
return res.status(400).json({
data: null,
@ -22,23 +21,23 @@ const login: LoginEndpoint['handlers']['login'] = async ({
})
}
let response;
let response
try {
const variables = { loginInput : { username: email, password }};
const variables = { loginInput: { username: email, password } }
response = await config.fetch(loginMutation, { variables })
const { account: token } = response.data;
const { account: token } = response.data
// Set Cookie
const cookieExpirationDate = getCookieExpirationDate(config.customerCookieMaxAgeInDays)
const cookieExpirationDate = getCookieExpirationDate(
config.customerCookieMaxAgeInDays
)
const authCookie = prepareSetCookie(
config.customerCookie,
JSON.stringify(token),
token.accessTokenExpiration ? { expires: cookieExpirationDate }: {},
token.accessTokenExpiration ? { expires: cookieExpirationDate } : {}
)
setCookies(res, [authCookie])
} catch (error) {
// Check if the email and password didn't match an existing account
if (

View File

@ -1,5 +1,5 @@
import type { LogoutEndpoint } from '.'
import {prepareSetCookie} from '../../../lib/prepare-set-cookie';
import { prepareSetCookie } from '../../../lib/prepare-set-cookie'
import { setCookies } from '../../../lib/set-cookie'
const logout: LogoutEndpoint['handlers']['logout'] = async ({
@ -8,7 +8,10 @@ const logout: LogoutEndpoint['handlers']['logout'] = async ({
config,
}) => {
// Remove the cookie
const authCookie = prepareSetCookie(config.customerCookie,'',{ maxAge: -1, path: '/' })
const authCookie = prepareSetCookie(config.customerCookie, '', {
maxAge: -1,
path: '/',
})
setCookies(res, [authCookie])
// Only allow redirects to a relative URL

View File

@ -1,7 +1,10 @@
import { FetcherError } from '@vercel/commerce/utils/errors'
import type { SignupEndpoint } from '.'
import { registerUserMutation, registerUserLoginMutation } from '../../mutations/signup-mutation'
import { prepareSetCookie } from '../../../lib/prepare-set-cookie';
import {
registerUserMutation,
registerUserLoginMutation,
} from '../../mutations/signup-mutation'
import { prepareSetCookie } from '../../../lib/prepare-set-cookie'
import { setCookies } from '../../../lib/set-cookie'
import { getCookieExpirationDate } from '../../../lib/get-cookie-expiration-date'
@ -14,7 +17,6 @@ const signup: SignupEndpoint['handlers']['signup'] = async ({
config,
commerce,
}) => {
if (!(email && password)) {
return res.status(400).json({
data: null,
@ -22,9 +24,8 @@ const signup: SignupEndpoint['handlers']['signup'] = async ({
})
}
let response;
let response
try {
// Register user
const registerUserVariables = {
customerAccountInput: {
@ -32,12 +33,14 @@ const signup: SignupEndpoint['handlers']['signup'] = async ({
firstName: firstName,
lastName: lastName,
acceptsMarketing: true,
id: 0
}
id: 0,
},
}
const registerUserResponse = await config.fetch(registerUserMutation, { variables: registerUserVariables})
const accountId = registerUserResponse.data?.account?.id;
const registerUserResponse = await config.fetch(registerUserMutation, {
variables: registerUserVariables,
})
const accountId = registerUserResponse.data?.account?.id
// Login user
const registerUserLoginVairables = {
@ -46,24 +49,27 @@ const signup: SignupEndpoint['handlers']['signup'] = async ({
emailAddress: email,
username: email,
password: password,
isImport: false
}
isImport: false,
},
}
response = await config.fetch(registerUserLoginMutation, { variables: registerUserLoginVairables})
const { account: token } = response.data;
response = await config.fetch(registerUserLoginMutation, {
variables: registerUserLoginVairables,
})
const { account: token } = response.data
// Set Cookie
const cookieExpirationDate = getCookieExpirationDate(config.customerCookieMaxAgeInDays)
const cookieExpirationDate = getCookieExpirationDate(
config.customerCookieMaxAgeInDays
)
const authCookie = prepareSetCookie(
config.customerCookie,
JSON.stringify(token),
token.accessTokenExpiration ? { expires: cookieExpirationDate }: {},
token.accessTokenExpiration ? { expires: cookieExpirationDate } : {}
)
setCookies(res, [authCookie])
} catch (error) {
// Check if the email and password didn't match an existing account
if (

View File

@ -11,7 +11,7 @@ const buildAddToWishlistVariables = ({
productId,
variantId,
productResponse,
wishlist
wishlist,
}: {
productId: string
variantId: string
@ -47,7 +47,7 @@ const buildAddToWishlistVariables = ({
productCode: productId,
variationProductCode: variantId ? variantId : null,
options,
}
},
},
}
}
@ -58,8 +58,10 @@ const addItem: WishlistEndpoint['handlers']['addItem'] = async ({
config,
commerce,
}) => {
const token = customerToken ? Buffer.from(customerToken, 'base64').toString('ascii'): null;
const accessToken = token ? JSON.parse(token).accessToken : null;
const token = customerToken
? Buffer.from(customerToken, 'base64').toString('ascii')
: null
const accessToken = token ? JSON.parse(token).accessToken : null
let result: { data?: any } = {}
let wishlist: any
@ -70,7 +72,8 @@ const addItem: WishlistEndpoint['handlers']['addItem'] = async ({
})
}
const customerId = customerToken && (await getCustomerId({ customerToken, config }))
const customerId =
customerToken && (await getCustomerId({ customerToken, config }))
const wishlistName = config.defaultWishlistName
if (!customerId) {
@ -86,13 +89,18 @@ const addItem: WishlistEndpoint['handlers']['addItem'] = async ({
})
wishlist = wishlistResponse?.wishlist
if (Object.keys(wishlist).length === 0) {
const createWishlistResponse= await config.fetch(createWishlist, {variables: {
const createWishlistResponse = await config.fetch(
createWishlist,
{
variables: {
wishlistInput: {
customerAccountId: customerId,
name: wishlistName
}
}
}, {headers: { 'x-vol-user-claims': accessToken } })
name: wishlistName,
},
},
},
{ headers: { 'x-vol-user-claims': accessToken } }
)
wishlist = createWishlistResponse?.data?.createWishlist
}
@ -103,7 +111,11 @@ const addItem: WishlistEndpoint['handlers']['addItem'] = async ({
const addItemToWishlistResponse = await config.fetch(
addItemToWishlistMutation,
{
variables: buildAddToWishlistVariables({ ...item, productResponse, wishlist }),
variables: buildAddToWishlistVariables({
...item,
productResponse,
wishlist,
}),
},
{ headers: { 'x-vol-user-claims': accessToken } }
)
@ -116,7 +128,14 @@ const addItem: WishlistEndpoint['handlers']['addItem'] = async ({
wishlist = wishlistResponse?.wishlist
}
result = { data: {...wishlist, items: wishlist?.items?.map((item:any) => normalizeWishlistItem(item, config))} }
result = {
data: {
...wishlist,
items: wishlist?.items?.map((item: any) =>
normalizeWishlistItem(item, config)
),
},
}
res.status(200).json({ data: result?.data })
}

View File

@ -11,7 +11,8 @@ const getWishlist: WishlistEndpoint['handlers']['getWishlist'] = async ({
}) => {
let result: { data?: any } = {}
if (customerToken) {
const customerId = customerToken && (await getCustomerId({ customerToken, config }))
const customerId =
customerToken && (await getCustomerId({ customerToken, config }))
const wishlistName = config.defaultWishlistName
if (!customerId) {
// If the customerToken is invalid, then this request is too
@ -26,7 +27,14 @@ const getWishlist: WishlistEndpoint['handlers']['getWishlist'] = async ({
config,
})
result = { data: {...wishlist, items: wishlist?.items?.map((item:any) => normalizeWishlistItem(item, config, includeProducts))} }
result = {
data: {
...wishlist,
items: wishlist?.items?.map((item: any) =>
normalizeWishlistItem(item, config, includeProducts)
),
},
}
}
res.status(200).json({ data: result?.data ?? null })

View File

@ -10,12 +10,15 @@ const removeItem: WishlistEndpoint['handlers']['removeItem'] = async ({
config,
commerce,
}) => {
const token = customerToken ? Buffer.from(customerToken, 'base64').toString('ascii'): null;
const accessToken = token ? JSON.parse(token).accessToken : null;
const token = customerToken
? Buffer.from(customerToken, 'base64').toString('ascii')
: null
const accessToken = token ? JSON.parse(token).accessToken : null
let result: { data?: any } = {}
let wishlist: any
const customerId = customerToken && (await getCustomerId({ customerToken, config }))
const customerId =
customerToken && (await getCustomerId({ customerToken, config }))
const wishlistName = config.defaultWishlistName
const wishlistResponse = await commerce.getCustomerWishlist({
variables: { customerId, wishlistName },
@ -29,18 +32,16 @@ const removeItem: WishlistEndpoint['handlers']['removeItem'] = async ({
errors: [{ message: 'Invalid request' }],
})
}
const removedItem = wishlist?.items?.find(
(item:any) => {
return item.product.productCode === itemId;
}
);
const removedItem = wishlist?.items?.find((item: any) => {
return item.product.productCode === itemId
})
const removeItemFromWishlistResponse = await config.fetch(
removeItemFromWishlistMutation,
{
variables: {
wishlistId: wishlist?.id,
wishlistItemId: removedItem?.id
wishlistItemId: removedItem?.id,
},
},
{ headers: { 'x-vol-user-claims': accessToken } }
@ -53,7 +54,14 @@ const removeItem: WishlistEndpoint['handlers']['removeItem'] = async ({
})
wishlist = wishlistResponse?.wishlist
}
result = { data: {...wishlist, items: wishlist?.items?.map((item:any) => normalizeWishlistItem(item, config))} }
result = {
data: {
...wishlist,
items: wishlist?.items?.map((item: any) =>
normalizeWishlistItem(item, config)
),
},
}
res.status(200).json({ data: result?.data })
}

View File

@ -8,4 +8,4 @@ fragment cartItemDetails on CartItem {
quantity
}
${productDetails}
`;
`

View File

@ -8,4 +8,5 @@ fragment categoryInfo on PrCategory {
slug
description
}
}`;
}
`

View File

@ -5,11 +5,17 @@ fragment productPrices on Product {
salePrice
}
priceRange {
lower { price, salePrice}
upper { price, salePrice }
lower {
price
salePrice
}
upper {
price
salePrice
}
}
`;
}
`
export const productAttributes = /* GraphQL */ `
fragment productAttributes on Product {
properties {
@ -24,7 +30,7 @@ fragment productAttributes on Product {
}
}
}
`;
`
export const productContent = /* GraphQL */ `
fragment productContent on Product {
content {
@ -39,7 +45,7 @@ fragment productContent on Product {
}
}
}
`;
`
export const productOptions = /* GraphQL */ `
fragment productOptions on Product {
options {
@ -58,7 +64,7 @@ fragment productOptions on Product {
}
}
}
`;
`
export const productInfo = /* GraphQL */ `
fragment productInfo on Product {
productCode
@ -69,7 +75,7 @@ fragment productInfo on Product {
}
variations {
productCode,
productCode
options {
__typename
attributeFQN
@ -95,4 +101,4 @@ ${productPrices}
${productAttributes}
${productContent}
${productOptions}
`;
`

View File

@ -1,4 +1,4 @@
import { productInfo } from './product';
import { productInfo } from './product'
export const searchFacets = /* GraphQL */ `
fragment searchFacets on Facet {
@ -12,7 +12,8 @@ fragment searchFacets on Facet {
isDisplayed
count
}
}`;
}
`
export const searchResults = /* GraphQL */ `
fragment searchResults on ProductSearchResult {
@ -29,4 +30,4 @@ fragment searchResults on ProductSearchResult {
}
${searchFacets}
${productInfo}
`;
`

View File

@ -15,10 +15,10 @@ export interface KiboCommerceConfig extends CommerceAPIConfig {
apiHost?: string
clientId?: string
sharedSecret?: string
customerCookieMaxAgeInDays: number,
currencyCode: string,
documentListName: string,
defaultWishlistName: string,
customerCookieMaxAgeInDays: number
currencyCode: string
documentListName: string
defaultWishlistName: string
authUrl?: string
}
@ -37,7 +37,7 @@ const config: KiboCommerceConfig = {
sharedSecret: process.env.KIBO_SHARED_SECRET || '',
customerCookieMaxAgeInDays: 30,
currencyCode: 'USD',
defaultWishlistName: 'My Wishlist'
defaultWishlistName: 'My Wishlist',
}
const operations = {

View File

@ -16,6 +16,6 @@ const addItemToWishlistMutation = /* GraphQL */`
}
}
${productDetails}
`;
`
export default addItemToWishlistMutation;
export default addItemToWishlistMutation

View File

@ -6,6 +6,6 @@ mutation createWishlist($wishlistInput:WishlistInput!) {
customerAccountId
}
}
`;
`
export default createWishlist;
export default createWishlist

View File

@ -1,4 +1,3 @@
export const loginMutation = /* GraphQL */ `
mutation login($loginInput: CustomerUserAuthInfoInput!) {
account: createCustomerAuthTicket(customerUserAuthInfoInput: $loginInput) {
@ -17,4 +16,3 @@ mutation login($loginInput:CustomerUserAuthInfoInput!) {
}
}
`

View File

@ -4,6 +4,6 @@
const removeItemFromCartMutation = /*GraphQL*/ `
mutation deleteCartItem($id: String!) {
deleteCurrentCartItem(cartItemId:$id)
}`;
}`
export default removeItemFromCartMutation;
export default removeItemFromCartMutation

View File

@ -2,7 +2,6 @@ const removeItemFromWishlistMutation = /* GraphQL */`
mutation deletewishlistitem($wishlistId: String!, $wishlistItemId: String!) {
deleteWishlistItem(wishlistId: $wishlistId, wishlistItemId: $wishlistItemId)
}
`;
export default removeItemFromWishlistMutation;
`
export default removeItemFromWishlistMutation

View File

@ -1,7 +1,8 @@
const registerUserMutation = /* GraphQL */ `
mutation registerUser($customerAccountInput: CustomerAccountInput!) {
account:createCustomerAccount(customerAccountInput:$customerAccountInput) {
account: createCustomerAccount(
customerAccountInput: $customerAccountInput
) {
emailAddress
userName
firstName
@ -15,11 +16,18 @@ mutation registerUser($customerAccountInput: CustomerAccountInput!) {
fullyQualifiedName
}
}
}`;
}
`
const registerUserLoginMutation = /* GraphQL */ `
mutation registerUserLogin($accountId: Int!, $customerLoginInfoInput: CustomerLoginInfoInput!) {
account:createCustomerAccountLogin(accountId:$accountId, customerLoginInfoInput:$customerLoginInfoInput) {
mutation registerUserLogin(
$accountId: Int!
$customerLoginInfoInput: CustomerLoginInfoInput!
) {
account: createCustomerAccountLogin(
accountId: $accountId
customerLoginInfoInput: $customerLoginInfoInput
) {
accessToken
accessTokenExpiration
refreshToken
@ -32,10 +40,7 @@ mutation registerUserLogin($accountId: Int!, $customerLoginInfoInput: CustomerLo
userName
}
}
}`;
export {
registerUserMutation,
registerUserLoginMutation
};
}
`
export { registerUserMutation, registerUserLoginMutation }

View File

@ -4,6 +4,6 @@ mutation updateCartItemQuantity($itemId:String!, $quantity: Int!){
id
quantity
}
}`;
}`
export default updateCartItemQuantityMutation;
export default updateCartItemQuantityMutation

View File

@ -1,17 +1,14 @@
import type { OperationContext } from '@vercel/commerce/api/operations'
import type { KiboCommerceConfig } from '../index'
import { getAllPagesQuery } from '../queries/get-all-pages-query'
import { GetPagesQueryParams } from "../../types/page";
import { GetPagesQueryParams } from '../../types/page'
import { normalizePage } from '../../lib/normalize'
export type GetAllPagesResult<
T extends { pages: any[] } = { pages: any[] }
> = T
export type GetAllPagesResult<T extends { pages: any[] } = { pages: any[] }> = T
export default function getAllPagesOperation({
commerce,
}: OperationContext<any>) {
async function getAllPages({
query = getAllPagesQuery,
config,
@ -25,11 +22,11 @@ export default function getAllPagesOperation({
} = {}): Promise<GetAllPagesResult> {
const cfg = commerce.getConfig(config)
variables = {
documentListName: cfg.documentListName
documentListName: cfg.documentListName,
}
const { data } = await cfg.fetch(query, { variables });
const { data } = await cfg.fetch(query, { variables })
const pages = data.documentListDocuments.items.map(normalizePage);
const pages = data.documentListDocuments.items.map(normalizePage)
return { pages }
}

View File

@ -1,24 +1,31 @@
import { KiboCommerceConfig } from '../index'
import { getAllProductsQuery } from '../queries/get-all-products-query';
import { getAllProductsQuery } from '../queries/get-all-products-query'
import { normalizeProduct } from '../../lib/normalize'
export type GetAllProductPathsResult = {
products: Array<{ path: string }>
}
export default function getAllProductPathsOperation({commerce,}: any) {
async function getAllProductPaths({ config }: {config?: KiboCommerceConfig } = {}): Promise<GetAllProductPathsResult> {
export default function getAllProductPathsOperation({ commerce }: any) {
async function getAllProductPaths({
config,
}: { config?: KiboCommerceConfig } = {}): Promise<GetAllProductPathsResult> {
const cfg = commerce.getConfig(config)
const productVariables = {startIndex: 0, pageSize: 100};
const { data } = await cfg.fetch(getAllProductsQuery, { variables: productVariables });
const productVariables = { startIndex: 0, pageSize: 100 }
const { data } = await cfg.fetch(getAllProductsQuery, {
variables: productVariables,
})
const normalizedProducts = data.products.items ? data.products.items.map( (item:any) => normalizeProduct(item, cfg)) : [];
const products = normalizedProducts.map((product: any) => ({ path: product.path }))
const normalizedProducts = data.products.items
? data.products.items.map((item: any) => normalizeProduct(item, cfg))
: []
const products = normalizedProducts.map((product: any) => ({
path: product.path,
}))
return Promise.resolve({
products: products
products: products,
})
}

View File

@ -2,7 +2,7 @@ import { Product } from '@vercel/commerce/types/product'
import { GetAllProductsOperation } from '@vercel/commerce/types/product'
import type { OperationContext } from '@vercel/commerce/api/operations'
import type { KiboCommerceConfig } from '../index'
import { getAllProductsQuery } from '../queries/get-all-products-query';
import { getAllProductsQuery } from '../queries/get-all-products-query'
import { normalizeProduct } from '../../lib/normalize'
export default function getAllProductsOperation({
@ -18,11 +18,12 @@ export default function getAllProductsOperation({
config?: Partial<KiboCommerceConfig>
preview?: boolean
} = {}): Promise<{ products: Product[] | any[] }> {
const cfg = commerce.getConfig(config)
const { data } = await cfg.fetch(query);
const { data } = await cfg.fetch(query)
let normalizedProducts = data.products.items ? data.products.items.map( (item:any) => normalizeProduct(item, cfg)) : [];
let normalizedProducts = data.products.items
? data.products.items.map((item: any) => normalizeProduct(item, cfg))
: []
return {
products: normalizedProducts,

View File

@ -42,10 +42,11 @@ export default function getCustomerWishlistOperation({
}): Promise<T['data']> {
let customerWishlist = {}
try {
config = commerce.getConfig(config)
const result= await config?.fetch(getCustomerWishlistQuery,{variables})
customerWishlist= result?.data?.customerWishlist;
const result = await config?.fetch(getCustomerWishlistQuery, {
variables,
})
customerWishlist = result?.data?.customerWishlist
} catch (e) {
customerWishlist = {}
}

View File

@ -1,15 +1,11 @@
import type {
OperationContext,
} from '@vercel/commerce/api/operations'
import type { OperationContext } from '@vercel/commerce/api/operations'
import type { KiboCommerceConfig, KiboCommerceProvider } from '..'
import { normalizePage } from '../../lib/normalize'
import { getPageQuery } from '../queries/get-page-query'
import type { Page, GetPageQueryParams } from "../../types/page";
import type { Page, GetPageQueryParams } from '../../types/page'
import type { Document } from '../../../schema'
export default function getPageOperation({
commerce,
}: OperationContext<any>) {
export default function getPageOperation({ commerce }: OperationContext<any>) {
async function getPage<T extends Page>({
url,
variables,
@ -24,11 +20,14 @@ export default function getPageOperation({
// RecursivePartial forces the method to check for every prop in the data, which is
// required in case there's a custom `url`
const cfg = commerce.getConfig(config)
const pageVariables = { documentListName: cfg.documentListName, filter: `id eq ${variables.id}` }
const pageVariables = {
documentListName: cfg.documentListName,
filter: `id eq ${variables.id}`,
}
const { data } = await cfg.fetch(getPageQuery, { variables: pageVariables })
const firstPage = data.documentListDocuments.items?.[0];
const firstPage = data.documentListDocuments.items?.[0]
const page = firstPage as Document
if (preview || page?.properties?.is_visible) {
return { page: normalizePage(page as any) }

View File

@ -8,7 +8,6 @@ import { normalizeProduct } from '../../lib/normalize'
export default function getProductOperation({
commerce,
}: OperationContext<any>) {
async function getProduct<T extends GetProductOperation>({
query = getProductQuery,
variables,
@ -22,12 +21,12 @@ export default function getProductOperation({
const productVariables = { productCode: variables?.slug }
const cfg = commerce.getConfig(config)
const { data } = await cfg.fetch(query, { variables: productVariables });
const { data } = await cfg.fetch(query, { variables: productVariables })
const normalizedProduct = normalizeProduct(data.product, cfg)
return {
product: normalizedProduct
product: normalizedProduct,
}
}

View File

@ -11,7 +11,9 @@ export type GetSiteInfoResult<
}
> = T
export default function getSiteInfoOperation({commerce}: OperationContext<any>) {
export default function getSiteInfoOperation({
commerce,
}: OperationContext<any>) {
async function getSiteInfo({
query = categoryTreeQuery,
variables,
@ -23,8 +25,8 @@ export default function getSiteInfoOperation({commerce}: OperationContext<any>)
preview?: boolean
} = {}): Promise<GetSiteInfoResult> {
const cfg = commerce.getConfig(config)
const { data } = await cfg.fetch(query);
const categories= data.categories.items.map(normalizeCategory);
const { data } = await cfg.fetch(query)
const categories = data.categories.items.map(normalizeCategory)
return Promise.resolve({
categories: categories ?? [],
brands: [],

View File

@ -8,4 +8,5 @@ query($documentListName: String!) {
properties
}
}
}`;
}
`

View File

@ -1,18 +1,10 @@
import { productInfo } from '../fragments/product';
import { productInfo } from '../fragments/product'
export const getAllProductsQuery = /* GraphQL */ `
${productInfo}
query products(
$filter: String
$startIndex: Int
$pageSize: Int
) {
products(
filter: $filter
startIndex: $startIndex
pageSize: $pageSize
) {
query products($filter: String, $startIndex: Int, $pageSize: Int) {
products(filter: $filter, startIndex: $startIndex, pageSize: $pageSize) {
items {
...productInfo
}

View File

@ -26,4 +26,5 @@ query GetCategoryTree {
}
}
}
${CategoryInfo}`;
${CategoryInfo}
`

View File

@ -1,7 +1,10 @@
import { productDetails } from '../fragments/productDetails'
export const getCustomerWishlistQuery = /* GraphQL */ `
query wishlist($customerId: Int!, $wishlistName: String!) {
customerWishlist(customerAccountId:$customerId ,wishlistName: $wishlistName){
customerWishlist(
customerAccountId: $customerId
wishlistName: $wishlistName
) {
customerAccountId
name
id

View File

@ -1,6 +1,9 @@
export const getPageQuery = /* GraphQL */ `
query ($documentListName: String!, $filter: String!) {
documentListDocuments(documentListName: $documentListName, filter: $filter){
documentListDocuments(
documentListName: $documentListName
filter: $filter
) {
startIndex
totalCount
items {
@ -11,4 +14,4 @@ query($documentListName: String!, $filter: String!) {
}
}
}
`;
`

View File

@ -1,14 +1,10 @@
import { productInfo } from '../fragments/product';
import { productInfo } from '../fragments/product'
export const getProductQuery = /* GraphQL */ `
${productInfo}
query product(
$productCode: String!
) {
product(
productCode: $productCode
) {
query product($productCode: String!) {
product(productCode: $productCode) {
...productInfo
}
}

View File

@ -1,20 +1,27 @@
import { searchResults } from '../fragments/search'
const query = /* GraphQL */ `
query ProductSearch($query:String, $startIndex:Int,
$pageSize:Int, $sortBy:String, $filter:String,$facetTemplate:String,$facetValueFilter:String ) {
query ProductSearch(
$query: String
$startIndex: Int
$pageSize: Int
$sortBy: String
$filter: String
$facetTemplate: String
$facetValueFilter: String
) {
products: productSearch(
query:$query,
startIndex: $startIndex,
pageSize:$pageSize,
sortBy: $sortBy,
filter:$filter,
facetTemplate:$facetTemplate,
query: $query
startIndex: $startIndex
pageSize: $pageSize
sortBy: $sortBy
filter: $filter
facetTemplate: $facetTemplate
facetValueFilter: $facetValueFilter
) {
...searchResults
}
}
${searchResults}
`;
export default query;
`
export default query

View File

@ -42,7 +42,7 @@ export class APIAuthenticationHelper {
this._sharedSecret = sharedSecret
this._authUrl = authUrl
if (!authTicketCache) {
this._authTicketCache = new RuntimeMemCache();
this._authTicketCache = new RuntimeMemCache()
}
}
private _buildFetchOptions(body: any = {}): FetchOptions {

View File

@ -37,7 +37,7 @@ export default class CookieHandler {
isShopperCookieAnonymous() {
const customerCookieKey = this.config.customerCookie
const shopperCookie = this.request.cookies[customerCookieKey]
const shopperSession = parseCookie(shopperCookie);
const shopperSession = parseCookie(shopperCookie)
const isAnonymous = shopperSession?.customerAccount ? false : true
return isAnonymous
}

View File

@ -2,18 +2,16 @@ import { FetcherError } from '@vercel/commerce/utils/errors'
import type { GraphQLFetcher } from '@vercel/commerce/api'
import type { KiboCommerceConfig } from '../index'
import fetch from './fetch'
import { APIAuthenticationHelper } from './api-auth-helper';
import { APIAuthenticationHelper } from './api-auth-helper'
const fetchGraphqlApi: (
getConfig: () => KiboCommerceConfig
) => GraphQLFetcher = (getConfig) => async (
query: string,
{ variables, preview } = {},
fetchOptions
) => {
) => GraphQLFetcher =
(getConfig) =>
async (query: string, { variables, preview } = {}, fetchOptions) => {
const config = getConfig()
const authHelper = new APIAuthenticationHelper(config);
const apiToken = await authHelper.getAccessToken();
const authHelper = new APIAuthenticationHelper(config)
const apiToken = await authHelper.getAccessToken()
const res = await fetch(config.commerceUrl + (preview ? '/preview' : ''), {
...fetchOptions,
method: 'POST',
@ -30,9 +28,15 @@ const fetchGraphqlApi: (
const json = await res.json()
if (json.errors) {
console.warn(`Kibo API Request Correlation ID: ${res.headers.get('x-vol-correlation')}`);
console.warn(
`Kibo API Request Correlation ID: ${res.headers.get(
'x-vol-correlation'
)}`
)
throw new FetcherError({
errors: json.errors ?? [{ message: 'Failed to fetch KiboCommerce API' }],
errors: json.errors ?? [
{ message: 'Failed to fetch KiboCommerce API' },
],
status: res.status,
})
}

View File

@ -3,7 +3,9 @@ import type { GraphQLFetcher } from '@vercel/commerce/api'
import type { KiboCommerceConfig } from '../index'
import fetch from './fetch'
const fetchGraphqlApi: (getConfig: () => KiboCommerceConfig) => GraphQLFetcher =
const fetchGraphqlApi: (
getConfig: () => KiboCommerceConfig
) => GraphQLFetcher =
(getConfig) =>
async (query: string, { variables, preview } = {}, fetchOptions) => {
const config = getConfig()
@ -25,7 +27,9 @@ const fetchGraphqlApi: (getConfig: () => KiboCommerceConfig) => GraphQLFetcher =
const json = await res.json()
if (json.errors) {
throw new FetcherError({
errors: json.errors ?? [{ message: 'Failed to fetch KiboCommerce API' }],
errors: json.errors ?? [
{ message: 'Failed to fetch KiboCommerce API' },
],
status: res.status,
})
}

View File

@ -8,17 +8,15 @@ async function getCustomerId({
customerToken: string
config: KiboCommerceConfig
}): Promise<string | undefined> {
const token = customerToken ? Buffer.from(customerToken, 'base64').toString('ascii'): null;
const accessToken = token ? JSON.parse(token).accessToken : null;
const { data } = await config.fetch(
getCustomerAccountQuery,
undefined,
{
const token = customerToken
? Buffer.from(customerToken, 'base64').toString('ascii')
: null
const accessToken = token ? JSON.parse(token).accessToken : null
const { data } = await config.fetch(getCustomerAccountQuery, undefined, {
headers: {
'x-vol-user-claims': accessToken,
},
}
)
})
return data?.customerAccount?.id
}

View File

@ -12,7 +12,9 @@ export const handler: MutationHook<LogoutHook> = {
url: '/api/logout',
method: 'GET',
},
useHook: ({ fetch }) => () => {
useHook:
({ fetch }) =>
() => {
const { mutate } = useCustomer()
const { mutate: mutateCart } = useCart()

View File

@ -29,7 +29,9 @@ export const handler: MutationHook<AddItemHook> = {
return data
},
useHook: ({ fetch }) => () => {
useHook:
({ fetch }) =>
() => {
const { mutate } = useCart()
return useCallback(

View File

@ -12,7 +12,9 @@ export const handler: SWRHook<any> = {
async fetcher({ options, fetch }) {
return await fetch({ ...options })
},
useHook: ({ useData }) => (input) => {
useHook:
({ useData }) =>
(input) => {
const response = useData({
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
})

View File

@ -4,8 +4,14 @@ import type {
HookFetcherContext,
} from '@vercel/commerce/utils/types'
import { ValidationError } from '@vercel/commerce/utils/errors'
import useRemoveItem, { UseRemoveItem } from '@vercel/commerce/cart/use-remove-item'
import type { Cart, LineItem, RemoveItemHook } from '@vercel/commerce/types/cart'
import useRemoveItem, {
UseRemoveItem,
} from '@vercel/commerce/cart/use-remove-item'
import type {
Cart,
LineItem,
RemoveItemHook,
} from '@vercel/commerce/types/cart'
import useCart from './use-cart'
export type RemoveItemFn<T = any> = T extends LineItem
@ -30,11 +36,9 @@ export const handler = {
}: HookFetcherContext<RemoveItemHook>) {
return await fetch({ ...options, body: { itemId } })
},
useHook: ({ fetch }: MutationHookContext<RemoveItemHook>) => <
T extends LineItem | undefined = undefined
>(
ctx: { item?: T } = {}
) => {
useHook:
({ fetch }: MutationHookContext<RemoveItemHook>) =>
<T extends LineItem | undefined = undefined>(ctx: { item?: T } = {}) => {
const { item } = ctx
const { mutate } = useCart()
const removeItem: RemoveItemFn<LineItem> = async (input) => {

View File

@ -5,7 +5,9 @@ import type {
HookFetcherContext,
} from '@vercel/commerce/utils/types'
import { ValidationError } from '@vercel/commerce/utils/errors'
import useUpdateItem, { UseUpdateItem } from '@vercel/commerce/cart/use-update-item'
import useUpdateItem, {
UseUpdateItem,
} from '@vercel/commerce/cart/use-update-item'
import type { LineItem, UpdateItemHook } from '@vercel/commerce/types/cart'
import { handler as removeItemHandler } from './use-remove-item'
import useCart from './use-cart'
@ -46,9 +48,9 @@ export const handler = {
body: { itemId, item },
})
},
useHook: ({ fetch }: MutationHookContext<UpdateItemHook>) => <
T extends LineItem | undefined = undefined
>(
useHook:
({ fetch }: MutationHookContext<UpdateItemHook>) =>
<T extends LineItem | undefined = undefined>(
ctx: {
item?: T
wait?: number

View File

@ -1,5 +1,7 @@
import { SWRHook } from '@vercel/commerce/utils/types'
import useCheckout, { UseCheckout } from '@vercel/commerce/checkout/use-checkout'
import useCheckout, {
UseCheckout,
} from '@vercel/commerce/checkout/use-checkout'
export default useCheckout as UseCheckout<typeof handler>

View File

@ -1,4 +1,6 @@
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/address/use-add-item'
import useAddItem, {
UseAddItem,
} from '@vercel/commerce/customer/address/use-add-item'
import { MutationHook } from '@vercel/commerce/utils/types'
export default useAddItem as UseAddItem<typeof handler>

View File

@ -1,4 +1,6 @@
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/card/use-add-item'
import useAddItem, {
UseAddItem,
} from '@vercel/commerce/customer/card/use-add-item'
import { MutationHook } from '@vercel/commerce/utils/types'
export default useAddItem as UseAddItem<typeof handler>

View File

@ -1,5 +1,7 @@
import { SWRHook } from '@vercel/commerce/utils/types'
import useCustomer, { UseCustomer } from '@vercel/commerce/customer/use-customer'
import useCustomer, {
UseCustomer,
} from '@vercel/commerce/customer/use-customer'
import type { CustomerHook } from '../types/customer'
export default useCustomer as UseCustomer<typeof handler>
@ -13,7 +15,9 @@ export const handler: SWRHook<CustomerHook> = {
const data = await fetch(options)
return data?.customer ?? null
},
useHook: ({ useData }) => (input) => {
useHook:
({ useData }) =>
(input) => {
return useData({
swrOptions: {
revalidateOnFocus: false,

View File

@ -1,4 +1,7 @@
import { getCommerceProvider, useCommerce as useCoreCommerce } from '@vercel/commerce'
import {
getCommerceProvider,
useCommerce as useCoreCommerce,
} from '@vercel/commerce'
import { kiboCommerceProvider, KibocommerceProvider } from './provider'
export { kiboCommerceProvider }

View File

@ -1,8 +1,10 @@
export function getCookieExpirationDate(maxAgeInDays: number) {
const today = new Date();
const expirationDate = new Date();
const today = new Date()
const expirationDate = new Date()
const cookieExpirationDate = new Date ( expirationDate.setDate(today.getDate() + maxAgeInDays) )
const cookieExpirationDate = new Date(
expirationDate.setDate(today.getDate() + maxAgeInDays)
)
return cookieExpirationDate;
return cookieExpirationDate
}

View File

@ -1,5 +1,5 @@
import type { PrCategory, CustomerAccountInput, Document } from '../../schema'
import { Page } from '../types/page';
import { Page } from '../types/page'
import { Customer } from '../types/customer'
export function normalizeProduct(productNode: any, config: any): any {
@ -57,7 +57,7 @@ export function normalizePage(page: Document): Page {
url: page.properties.url,
body: page.properties.body,
is_visible: page.properties.is_visible,
sort_order: page.properties.sort_order
sort_order: page.properties.sort_order,
}
}
@ -91,7 +91,7 @@ export function normalizeCustomer(customer: CustomerAccountInput): Customer {
lastName: customer.lastName,
email: customer.emailAddress,
userName: customer.userName,
isAnonymous: customer.isAnonymous
isAnonymous: customer.isAnonymous,
}
}

View File

@ -1,13 +1,17 @@
export function prepareSetCookie(name: string, value: string, options: any = {}): string {
export function prepareSetCookie(
name: string,
value: string,
options: any = {}
): string {
const encodedValue = Buffer.from(value).toString('base64')
const cookieValue = [`${name}=${encodedValue}`];
const cookieValue = [`${name}=${encodedValue}`]
if (options.maxAge) {
cookieValue.push(`Max-Age=${options.maxAge}`);
cookieValue.push(`Max-Age=${options.maxAge}`)
}
if (options.expires && !options.maxAge) {
cookieValue.push(`Expires=${options.expires.toUTCString()}`);
cookieValue.push(`Expires=${options.expires.toUTCString()}`)
}
const cookie = cookieValue.join('; ')

View File

@ -1,9 +1,9 @@
function getFacetValueFilter(categoryCode: string, filters = []) {
let facetValueFilter = '';
let facetValueFilter = ''
if (categoryCode) {
facetValueFilter = `categoryCode:${categoryCode},`;
facetValueFilter = `categoryCode:${categoryCode},`
}
return facetValueFilter + filters.join(',');
return facetValueFilter + filters.join(',')
}
export const buildProductSearchVars = ({
@ -14,33 +14,38 @@ export const buildProductSearchVars = ({
sort = '',
search = '',
}) => {
let facetTemplate = '';
let filter = '';
let sortBy;
let facetTemplate = ''
let filter = ''
let sortBy
if (categoryCode) {
facetTemplate = `categoryCode:${categoryCode}`;
filter = `categoryCode req ${categoryCode}`;
facetTemplate = `categoryCode:${categoryCode}`
filter = `categoryCode req ${categoryCode}`
}
const facetFilterList = Object.keys(filters).filter(k => filters[k].length).reduce((accum, k): any => {
return [...accum, ...filters[k].map((facetValue: any) => `Tenant~${k}:${facetValue}`)];
}, []);
const facetFilterList = Object.keys(filters)
.filter((k) => filters[k].length)
.reduce((accum, k): any => {
return [
...accum,
...filters[k].map((facetValue: any) => `Tenant~${k}:${facetValue}`),
]
}, [])
const facetValueFilter = getFacetValueFilter(categoryCode, facetFilterList);
const facetValueFilter = getFacetValueFilter(categoryCode, facetFilterList)
switch (sort) {
case 'latest-desc':
sortBy= 'createDate desc';
break;
sortBy = 'createDate desc'
break
case 'price-asc':
sortBy= 'price asc';
break;
sortBy = 'price asc'
break
case 'price-desc':
sortBy= 'price desc';
break;
sortBy = 'price desc'
break
case 'trending-desc':
default:
sortBy= '';
break;
sortBy = ''
break
}
return {
@ -50,6 +55,6 @@ export const buildProductSearchVars = ({
sortBy,
filter: filter,
facetTemplate,
facetValueFilter
facetValueFilter,
}
}

View File

@ -1,3 +1,3 @@
export function setCookies(res: any, cookies: string[]): void {
res.setHeader('Set-Cookie', cookies);
res.setHeader('Set-Cookie', cookies)
}

View File

@ -4,9 +4,13 @@ module.exports = {
commerce,
serverRuntimeConfig: {
// Will only be available on the server side
kiboAuthTicket: null
kiboAuthTicket: null,
},
images: {
domains: ['d1slj7rdbjyb5l.cloudfront.net', 'cdn-tp1.mozu.com', 'cdn-sb.mozu.com'],
domains: [
'd1slj7rdbjyb5l.cloudfront.net',
'cdn-tp1.mozu.com',
'cdn-sb.mozu.com',
],
},
}

View File

@ -23,7 +23,9 @@ export const handler: SWRHook<any> = {
method: options.method,
})
},
useHook: ({ useData }) => (input) => {
useHook:
({ useData }) =>
(input) => {
return useData({
input: [
['search', input.search],

View File

@ -16,11 +16,11 @@ export type Scalars = {
}
export type Customer = {
id: Scalars['Int'],
firstName?: Maybe<Scalars['String']>,
lastName?: Maybe<Scalars['String']>,
email?: Maybe<Scalars['String']>,
userName?: Maybe<Scalars['String']>,
id: Scalars['Int']
firstName?: Maybe<Scalars['String']>
lastName?: Maybe<Scalars['String']>
email?: Maybe<Scalars['String']>
userName?: Maybe<Scalars['String']>
isAnonymous?: Maybe<Scalars['Boolean']>
}

View File

@ -23,12 +23,12 @@ export type PageTypes = {
}
export type GetPagesQueryParams = {
documentListName: Maybe<Scalars["String"]>
documentListName: Maybe<Scalars['String']>
}
export type GetPageQueryParams = {
id: Maybe<Scalars["String"]>
documentListName: Maybe<Scalars["String"]>
id: Maybe<Scalars['String']>
documentListName: Maybe<Scalars['String']>
}
export type GetAllPagesOperation = Core.GetAllPagesOperation<PageTypes>

View File

@ -1,6 +1,8 @@
import { useMemo } from 'react'
import { SWRHook } from '@vercel/commerce/utils/types'
import useWishlist, { UseWishlist } from '@vercel/commerce/wishlist/use-wishlist'
import useWishlist, {
UseWishlist,
} from '@vercel/commerce/wishlist/use-wishlist'
import type { GetWishlistHook } from '@vercel/commerce/types/wishlist'
import useCustomer from '../customer/use-customer'
@ -24,7 +26,9 @@ export const handler: SWRHook<any> = {
method: options.method,
})
},
useHook: ({ useData }) => (input) => {
useHook:
({ useData }) =>
(input) => {
const { data: customer } = useCustomer()
const response = useData({
input: [

View File

@ -1,5 +1,8 @@
import type { OperationContext } from '@vercel/commerce/api/operations'
import type { Category, GetSiteInfoOperation } from '@vercel/commerce/types/site'
import type {
Category,
GetSiteInfoOperation,
} from '@vercel/commerce/types/site'
import type { RawCategory } from '../../types/category'
import type { OrdercloudConfig, Provider } from '../index'

View File

@ -1,6 +1,6 @@
import vercelFetch from '@vercel/fetch'
import { FetcherError } from '@vercel/commerce/utils/errors'
import { CustomNodeJsGlobal } from '../../types/node';
import { CustomNodeJsGlobal } from '../../types/node'
import { OrdercloudConfig } from '../index'
@ -144,12 +144,11 @@ export const createBuyerFetcher: (
body?: Record<string, unknown>,
fetchOptions?: Record<string, any>
) => {
const customGlobal = global as unknown as CustomNodeJsGlobal;
const customGlobal = global as unknown as CustomNodeJsGlobal
// Get provider config
const config = getConfig()
// If a token was passed, set it on global
if (fetchOptions?.token) {
customGlobal.token = fetchOptions.token

View File

@ -2,12 +2,18 @@ import type {
MutationHookContext,
HookFetcherContext,
} from '@vercel/commerce/utils/types'
import type { Cart, LineItem, RemoveItemHook } from '@vercel/commerce/types/cart'
import type {
Cart,
LineItem,
RemoveItemHook,
} from '@vercel/commerce/types/cart'
import { useCallback } from 'react'
import { ValidationError } from '@vercel/commerce/utils/errors'
import useRemoveItem, { UseRemoveItem } from '@vercel/commerce/cart/use-remove-item'
import useRemoveItem, {
UseRemoveItem,
} from '@vercel/commerce/cart/use-remove-item'
import useCart from './use-cart'

View File

@ -9,7 +9,9 @@ import debounce from 'lodash.debounce'
import { MutationHook } from '@vercel/commerce/utils/types'
import { ValidationError } from '@vercel/commerce/utils/errors'
import useUpdateItem, { UseUpdateItem } from '@vercel/commerce/cart/use-update-item'
import useUpdateItem, {
UseUpdateItem,
} from '@vercel/commerce/cart/use-update-item'
import { handler as removeItemHandler } from './use-remove-item'
import useCart from './use-cart'

View File

@ -2,7 +2,9 @@ import type { GetCheckoutHook } from '@vercel/commerce/types/checkout'
import { useMemo } from 'react'
import { SWRHook } from '@vercel/commerce/utils/types'
import useCheckout, { UseCheckout } from '@vercel/commerce/checkout/use-checkout'
import useCheckout, {
UseCheckout,
} from '@vercel/commerce/checkout/use-checkout'
import useSubmitCheckout from './use-submit-checkout'
export default useCheckout as UseCheckout<typeof handler>

View File

@ -2,7 +2,9 @@ import type { AddItemHook } from '@vercel/commerce/types/customer/address'
import type { MutationHook } from '@vercel/commerce/utils/types'
import { useCallback } from 'react'
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/address/use-add-item'
import useAddItem, {
UseAddItem,
} from '@vercel/commerce/customer/address/use-add-item'
import useAddresses from './use-addresses'
export default useAddItem as UseAddItem<typeof handler>

Some files were not shown because too many files have changed in this diff Show More