From 9458dc87b7285927a62bd435d63a6f0aeb270a30 Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 25 Feb 2021 19:27:59 -0300 Subject: [PATCH 01/16] Adding extra config --- commerce.config.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/commerce.config.json b/commerce.config.json index 1c14a53f5..fa2ea9a44 100644 --- a/commerce.config.json +++ b/commerce.config.json @@ -1,6 +1,3 @@ { - "provider": "bigcommerce", - "features": { - "wishlist": false - } + "provider": "bigcommerce" } From 641ce0aa64cc46fbdc492dc55df7942d1d2be3fa Mon Sep 17 00:00:00 2001 From: cond0r Date: Mon, 1 Mar 2021 16:47:30 +0200 Subject: [PATCH 02/16] Shopify Provier Updates (#212) * changes * Adding shopify commit * Changed to query page by id * Fixed page query, Changed use-search GraphQl query * Update use-search.tsx * remove unused util * Changed cookie expiration * Update tsconfig.json Co-authored-by: okbel --- framework/bigcommerce/.env.template | 2 +- framework/shopify/api/index.ts | 4 +- .../shopify/cart/utils/checkout-create.ts | 8 ++- framework/shopify/common/get-all-pages.ts | 3 +- framework/shopify/common/get-page.ts | 15 ++-- framework/shopify/const.ts | 2 + framework/shopify/product/use-search.tsx | 34 ++++++--- framework/shopify/utils/customer-token.ts | 17 +++-- framework/shopify/utils/get-categories.ts | 4 +- .../shopify/utils/get-search-variables.ts | 11 ++- framework/shopify/utils/get-sort-variables.ts | 4 +- framework/shopify/utils/normalize.ts | 59 ++++++++++------ .../utils/queries/get-all-products-query.ts | 69 ++++++++++--------- .../queries/get-collection-products-query.ts | 21 ++++-- .../shopify/utils/queries/get-page-query.ts | 15 ++-- .../utils/queries/get-product-query.ts | 1 + .../shopify/utils/to-commerce-products.ts | 68 ------------------ framework/shopify/wishlist/use-wishlist.tsx | 2 - 18 files changed, 164 insertions(+), 175 deletions(-) delete mode 100644 framework/shopify/utils/to-commerce-products.ts diff --git a/framework/bigcommerce/.env.template b/framework/bigcommerce/.env.template index 83e7dd403..43e85c046 100644 --- a/framework/bigcommerce/.env.template +++ b/framework/bigcommerce/.env.template @@ -3,4 +3,4 @@ BIGCOMMERCE_STOREFRONT_API_TOKEN= BIGCOMMERCE_STORE_API_URL= BIGCOMMERCE_STORE_API_TOKEN= BIGCOMMERCE_STORE_API_CLIENT_ID= -BIGCOMMERCE_CHANNEL_ID= \ No newline at end of file +BIGCOMMERCE_CHANNEL_ID= diff --git a/framework/shopify/api/index.ts b/framework/shopify/api/index.ts index 4e23ce99c..4f15cae15 100644 --- a/framework/shopify/api/index.ts +++ b/framework/shopify/api/index.ts @@ -5,6 +5,7 @@ import { API_TOKEN, SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CUSTOMER_TOKEN_COOKIE, + SHOPIFY_COOKIE_EXPIRE, } from '../const' if (!API_URL) { @@ -43,10 +44,11 @@ export class Config { } const config = new Config({ + locale: 'en-US', commerceUrl: API_URL, apiToken: API_TOKEN!, cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, - cartCookieMaxAge: 60 * 60 * 24 * 30, + cartCookieMaxAge: SHOPIFY_COOKIE_EXPIRE, fetch: fetchGraphqlApi, customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE, }) diff --git a/framework/shopify/cart/utils/checkout-create.ts b/framework/shopify/cart/utils/checkout-create.ts index 6c4f81c21..e950cc7e4 100644 --- a/framework/shopify/cart/utils/checkout-create.ts +++ b/framework/shopify/cart/utils/checkout-create.ts @@ -1,6 +1,7 @@ import { SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CHECKOUT_URL_COOKIE, + SHOPIFY_COOKIE_EXPIRE, } from '../../const' import checkoutCreateMutation from '../../utils/mutations/checkout-create' @@ -15,8 +16,11 @@ export const checkoutCreate = async (fetch: any) => { const checkoutId = checkout?.id if (checkoutId) { - Cookies.set(SHOPIFY_CHECKOUT_ID_COOKIE, checkoutId) - Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout?.webUrl) + const options = { + expires: SHOPIFY_COOKIE_EXPIRE, + } + Cookies.set(SHOPIFY_CHECKOUT_ID_COOKIE, checkoutId, options) + Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout?.webUrl, options) } return checkout diff --git a/framework/shopify/common/get-all-pages.ts b/framework/shopify/common/get-all-pages.ts index 6f06185e2..54231ed03 100644 --- a/framework/shopify/common/get-all-pages.ts +++ b/framework/shopify/common/get-all-pages.ts @@ -25,12 +25,13 @@ const getAllPages = async (options?: { }): Promise => { let { config, variables = { first: 250 } } = options ?? {} config = getConfig(config) + const { locale } = config const { data } = await config.fetch(getAllPagesQuery, { variables }) const pages = data.pages?.edges?.map( ({ node: { title: name, handle, ...node } }: PageEdge) => ({ ...node, - url: `/${handle}`, + url: `/${locale}/${handle}`, name, }) ) diff --git a/framework/shopify/common/get-page.ts b/framework/shopify/common/get-page.ts index 6016c8c9a..be934aa42 100644 --- a/framework/shopify/common/get-page.ts +++ b/framework/shopify/common/get-page.ts @@ -3,33 +3,32 @@ import getPageQuery from '../utils/queries/get-page-query' import { Page } from './get-all-pages' type Variables = { - slug: string + id: string } -type ReturnType = { - page: Page -} +export type GetPageResult = T const getPage = async (options: { variables: Variables config: ShopifyConfig preview?: boolean -}): Promise => { +}): Promise => { let { config, variables } = options ?? {} + config = getConfig(config) + const { locale } = config const { data } = await config.fetch(getPageQuery, { variables, }) - - const { pageByHandle: page } = data + const page = data.node return { page: page ? { ...page, name: page.title, - url: page?.handle, + url: `/${locale}/${page.handle}`, } : null, } diff --git a/framework/shopify/const.ts b/framework/shopify/const.ts index a6e9e8d90..06fbe5054 100644 --- a/framework/shopify/const.ts +++ b/framework/shopify/const.ts @@ -6,6 +6,8 @@ export const SHOPIFY_CUSTOMER_TOKEN_COOKIE = 'shopify_customerToken' export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN +export const SHOPIFY_COOKIE_EXPIRE = 30 + export const API_URL = `https://${STORE_DOMAIN}/api/2021-01/graphql.json` export const API_TOKEN = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN diff --git a/framework/shopify/product/use-search.tsx b/framework/shopify/product/use-search.tsx index 4b14249ca..425df9e83 100644 --- a/framework/shopify/product/use-search.tsx +++ b/framework/shopify/product/use-search.tsx @@ -4,6 +4,7 @@ import useSearch, { UseSearch } from '@commerce/product/use-search' import { ProductEdge } from '../schema' import { getAllProductsQuery, + getCollectionProductsQuery, getSearchVariables, normalizeProduct, } from '../utils' @@ -14,8 +15,8 @@ export default useSearch as UseSearch export type SearchProductsInput = { search?: string - categoryId?: number - brandId?: number + categoryId?: string + brandId?: string sort?: string } @@ -23,6 +24,7 @@ export type SearchProductsData = { products: Product[] found: boolean } + export const handler: SWRHook< SearchProductsData, SearchProductsInput, @@ -32,18 +34,30 @@ export const handler: SWRHook< query: getAllProductsQuery, }, async fetcher({ input, options, fetch }) { - const resp = await fetch({ - query: options?.query, + const { categoryId, brandId } = input + + const data = await fetch({ + query: categoryId ? getCollectionProductsQuery : options.query, method: options?.method, variables: getSearchVariables(input), }) - const edges = resp.products?.edges + + let edges + + if (categoryId) { + edges = data.node?.products?.edges ?? [] + if (brandId) { + edges = edges.filter( + ({ node: { vendor } }: ProductEdge) => vendor === brandId + ) + } + } else { + edges = data.products?.edges ?? [] + } + return { - products: edges?.map(({ node: p }: ProductEdge) => - // TODO: Fix this product type - normalizeProduct(p as any) - ), - found: !!edges?.length, + products: edges.map(({ node }: ProductEdge) => normalizeProduct(node)), + found: !!edges.length, } }, useHook: ({ useData }) => (input = {}) => { diff --git a/framework/shopify/utils/customer-token.ts b/framework/shopify/utils/customer-token.ts index beae54765..85454cb83 100644 --- a/framework/shopify/utils/customer-token.ts +++ b/framework/shopify/utils/customer-token.ts @@ -1,12 +1,21 @@ -import Cookies from 'js-cookie' -import { SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '../const' +import Cookies, { CookieAttributes } from 'js-cookie' +import { SHOPIFY_COOKIE_EXPIRE, SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '../const' export const getCustomerToken = () => Cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE) -export const setCustomerToken = (token: string | null, options?: any) => { +export const setCustomerToken = ( + token: string | null, + options?: CookieAttributes +) => { if (!token) { Cookies.remove(SHOPIFY_CUSTOMER_TOKEN_COOKIE) } else { - Cookies.set(SHOPIFY_CUSTOMER_TOKEN_COOKIE, token, options) + Cookies.set( + SHOPIFY_CUSTOMER_TOKEN_COOKIE, + token, + options ?? { + expires: SHOPIFY_COOKIE_EXPIRE, + } + ) } } diff --git a/framework/shopify/utils/get-categories.ts b/framework/shopify/utils/get-categories.ts index 54048b896..cce4b2ad7 100644 --- a/framework/shopify/utils/get-categories.ts +++ b/framework/shopify/utils/get-categories.ts @@ -17,8 +17,8 @@ const getCategories = async (config: ShopifyConfig): Promise => { return ( data.collections?.edges?.map( - ({ node: { title: name, handle } }: CollectionEdge) => ({ - entityId: handle, + ({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({ + entityId, name, path: `/${handle}`, }) diff --git a/framework/shopify/utils/get-search-variables.ts b/framework/shopify/utils/get-search-variables.ts index 6f5d08b1a..c1b40ae5d 100644 --- a/framework/shopify/utils/get-search-variables.ts +++ b/framework/shopify/utils/get-search-variables.ts @@ -2,9 +2,9 @@ import getSortVariables from './get-sort-variables' import type { SearchProductsInput } from '../product/use-search' export const getSearchVariables = ({ - categoryId, brandId, search, + categoryId, sort, }: SearchProductsInput) => { let query = '' @@ -13,17 +13,14 @@ export const getSearchVariables = ({ query += `product_type:${search} OR title:${search} OR tag:${search}` } - if (categoryId) { - query += `tag:${categoryId}` - } - if (brandId) { - query += `${categoryId ? ' AND ' : ''}vendor:${brandId}` + query += `${search ? ' AND ' : ''}vendor:${brandId}` } return { + categoryId, query, - ...getSortVariables(sort), + ...getSortVariables(sort, !!categoryId), } } diff --git a/framework/shopify/utils/get-sort-variables.ts b/framework/shopify/utils/get-sort-variables.ts index 47650c0d7..b8cdeec51 100644 --- a/framework/shopify/utils/get-sort-variables.ts +++ b/framework/shopify/utils/get-sort-variables.ts @@ -1,4 +1,4 @@ -const getSortVariables = (sort?: string) => { +const getSortVariables = (sort?: string, isCategory = false) => { let output = {} switch (sort) { case 'price-asc': @@ -21,7 +21,7 @@ const getSortVariables = (sort?: string) => { break case 'latest-desc': output = { - sortKey: 'CREATED_AT', + sortKey: isCategory ? 'CREATED' : 'CREATED_AT', reverse: true, } break diff --git a/framework/shopify/utils/normalize.ts b/framework/shopify/utils/normalize.ts index 67ab3a8a2..c9b428b37 100644 --- a/framework/shopify/utils/normalize.ts +++ b/framework/shopify/utils/normalize.ts @@ -1,3 +1,5 @@ +import { Product } from '@commerce/types' + import { Product as ShopifyProduct, Checkout, @@ -5,8 +7,8 @@ import { SelectedOption, ImageConnection, ProductVariantConnection, - ProductOption, MoneyV2, + ProductOption, } from '../schema' import type { Cart, LineItem } from '../types' @@ -19,18 +21,26 @@ const money = ({ amount, currencyCode }: MoneyV2) => { } const normalizeProductOption = ({ + id, name: displayName, values, - ...rest }: ProductOption) => { return { __typename: 'MultipleChoiceOption', + id, displayName, - values: values.map((value) => ({ - label: value, - hexColors: displayName === 'Color' ? [value] : null, - })), - ...rest, + values: values.map((value) => { + let output: any = { + label: value, + } + if (displayName === 'Color') { + output = { + ...output, + hexColors: [value], + } + } + return output + }), } } @@ -41,19 +51,28 @@ const normalizeProductImages = ({ edges }: ImageConnection) => })) const normalizeProductVariants = ({ edges }: ProductVariantConnection) => { - return edges?.map(({ node: { id, selectedOptions } }) => ({ - id, - options: selectedOptions.map(({ name, value }: SelectedOption) => - normalizeProductOption({ - id, - name, - values: [value], - }) - ), - })) + return edges?.map( + ({ + node: { id, selectedOptions, sku, title, priceV2, compareAtPriceV2 }, + }) => ({ + id, + name: title, + sku: sku ?? id, + price: +priceV2.amount, + listPrice: +compareAtPriceV2?.amount, + requiresShipping: true, + options: selectedOptions.map(({ name, value }: SelectedOption) => + normalizeProductOption({ + id, + name, + values: [value], + }) + ), + }) + ) } -export function normalizeProduct(productNode: ShopifyProduct): any { +export function normalizeProduct(productNode: ShopifyProduct): Product { const { id, title: name, @@ -95,8 +114,8 @@ export function normalizeCart(checkout: Checkout): Cart { }, taxesIncluded: checkout.taxesIncluded, lineItems: checkout.lineItems?.edges.map(normalizeLineItem), - lineItemsSubtotalPrice: checkout.subtotalPriceV2?.amount, - subtotalPrice: checkout.subtotalPriceV2?.amount, + lineItemsSubtotalPrice: +checkout.subtotalPriceV2?.amount, + subtotalPrice: +checkout.subtotalPriceV2?.amount, totalPrice: checkout.totalPriceV2?.amount, discounts: [], } diff --git a/framework/shopify/utils/queries/get-all-products-query.ts b/framework/shopify/utils/queries/get-all-products-query.ts index 4a6c20b6e..5eb44c7a7 100644 --- a/framework/shopify/utils/queries/get-all-products-query.ts +++ b/framework/shopify/utils/queries/get-all-products-query.ts @@ -1,3 +1,38 @@ +export const productConnection = ` +pageInfo { + hasNextPage + hasPreviousPage +} +edges { + node { + id + title + vendor + handle + description + priceRange { + minVariantPrice { + amount + currencyCode + } + } + images(first: 1) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + originalSrc + altText + width + height + } + } + } + } +}` + export const productsFragment = ` products( first: $first @@ -5,39 +40,7 @@ products( reverse: $reverse query: $query ) { - pageInfo { - hasNextPage - hasPreviousPage - } - edges { - node { - id - title - vendor - handle - description - priceRange { - minVariantPrice { - amount - currencyCode - } - } - images(first: 1) { - pageInfo { - hasNextPage - hasPreviousPage - } - edges { - node { - originalSrc - altText - width - height - } - } - } - } - } + ${productConnection} } ` diff --git a/framework/shopify/utils/queries/get-collection-products-query.ts b/framework/shopify/utils/queries/get-collection-products-query.ts index dd504b575..04766caa4 100644 --- a/framework/shopify/utils/queries/get-collection-products-query.ts +++ b/framework/shopify/utils/queries/get-collection-products-query.ts @@ -1,16 +1,23 @@ -import { productsFragment } from './get-all-products-query' +import { productConnection } from './get-all-products-query' const getCollectionProductsQuery = /* GraphQL */ ` query getProductsFromCollection( - $categoryHandle: String! + $categoryId: ID! $first: Int = 250 - $query: String = "" - $sortKey: ProductSortKeys = RELEVANCE + $sortKey: ProductCollectionSortKeys = RELEVANCE $reverse: Boolean = false ) { - collectionByHandle(handle: $categoryHandle) - { - ${productsFragment} + node(id: $categoryId) { + id + ... on Collection { + products( + first: $first + sortKey: $sortKey + reverse: $reverse + ) { + ${productConnection} + } + } } } ` diff --git a/framework/shopify/utils/queries/get-page-query.ts b/framework/shopify/utils/queries/get-page-query.ts index dcafdc30d..2ca79abd4 100644 --- a/framework/shopify/utils/queries/get-page-query.ts +++ b/framework/shopify/utils/queries/get-page-query.ts @@ -1,12 +1,13 @@ export const getPageQuery = /* GraphQL */ ` - query getPageBySlug($slug: String!) { - pageByHandle(handle: $slug) { + query($id: ID!) { + node(id: $id) { id - title - handle - body - bodySummary - url + ... on Page { + title + handle + body + bodySummary + } } } ` diff --git a/framework/shopify/utils/queries/get-product-query.ts b/framework/shopify/utils/queries/get-product-query.ts index d054c023d..5c109901b 100644 --- a/framework/shopify/utils/queries/get-product-query.ts +++ b/framework/shopify/utils/queries/get-product-query.ts @@ -32,6 +32,7 @@ const getProductQuery = /* GraphQL */ ` node { id title + sku selectedOptions { name value diff --git a/framework/shopify/utils/to-commerce-products.ts b/framework/shopify/utils/to-commerce-products.ts deleted file mode 100644 index 84925e001..000000000 --- a/framework/shopify/utils/to-commerce-products.ts +++ /dev/null @@ -1,68 +0,0 @@ -// TODO: Fix the types in this file -// import { Product, Image } from '../types' - -type Product = any -type Image = any - -export default function toCommerceProducts(products: Product[]) { - return products.map((product: Product) => { - return { - id: product.id, - entityId: product.id, - name: product.title, - slug: product.handle, - title: product.title, - vendor: product.vendor, - description: product.descriptionHtml, - path: `/${product.handle}`, - price: { - value: +product.variants[0].price, - currencyCode: 'USD', // TODO - }, - images: product.images.map((image: Image) => { - return { - url: image.src, - } - }), - // TODO: Fix the variant type - variants: product.variants.map((variant: any) => { - return { - id: variant.id, - // TODO: Fix the selectedOption type - options: variant.selectedOptions.map((selectedOption: any) => { - return { - __typename: 'MultipleChoiceOption', - displayName: selectedOption.name, - values: [ - { - node: { - id: variant.id, - label: selectedOption.value, - }, - }, - ], - } - }), - } - }), - // TODO: Fix the option type - productOptions: product.options.map((option: any) => { - return { - __typename: 'MultipleChoiceOption', - displayName: option.name, - // TODO: Fix the value type - values: option.values.map((value: any) => { - return { - node: { - entityId: 1, - label: value.value, - hexColors: [value.value], - }, - } - }), - } - }), - options: [], - } - }) -} diff --git a/framework/shopify/wishlist/use-wishlist.tsx b/framework/shopify/wishlist/use-wishlist.tsx index 13632bb95..d2ce9db5b 100644 --- a/framework/shopify/wishlist/use-wishlist.tsx +++ b/framework/shopify/wishlist/use-wishlist.tsx @@ -2,9 +2,7 @@ // Shopify doesn't have a wishlist import { HookFetcher } from '@commerce/utils/types' -import useCommerceWishlist from '@commerce/wishlist/use-wishlist' import { Product } from '../schema' -import useCustomer from '../customer/use-customer' const defaultOpts = {} From 7780ec4818f730cad50eef2ffec306151f3b410b Mon Sep 17 00:00:00 2001 From: Bel Curcio Date: Mon, 1 Mar 2021 15:59:45 -0300 Subject: [PATCH 03/16] Bump and adding dependency --- components/product/Swatch/Swatch.module.css | 1 + package.json | 7 ++++--- yarn.lock | 23 ++++++++++++++++++--- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/components/product/Swatch/Swatch.module.css b/components/product/Swatch/Swatch.module.css index ae37771ad..051435afd 100644 --- a/components/product/Swatch/Swatch.module.css +++ b/components/product/Swatch/Swatch.module.css @@ -1,4 +1,5 @@ .root { + composes: root from 'components/ui/Button/Button.module.css'; @apply h-12 w-12 bg-primary text-primary rounded-full mr-3 inline-flex items-center justify-center cursor-pointer transition duration-150 ease-in-out p-0 shadow-none border-gray-200 border box-border; diff --git a/package.json b/package.json index 906d950dc..a3aac641b 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "sideEffects": false, "license": "MIT", "engines": { - "node": "12.x" + "node": "14.x" }, "prettier": { "semi": false, @@ -23,6 +23,7 @@ "dependencies": { "@reach/portal": "^0.11.2", "@vercel/fetch": "^6.1.0", + "autoprefixer": "^10.2.4", "body-scroll-lock": "^3.1.5", "bowser": "^2.11.0", "classnames": "^2.2.6", @@ -38,7 +39,7 @@ "next": "^10.0.7", "next-seo": "^4.11.0", "next-themes": "^0.0.4", - "postcss": "^8.2.4", + "postcss": "^8.2.6", "postcss-nesting": "^7.0.1", "react": "^17.0.1", "react-dom": "^17.0.1", @@ -47,7 +48,7 @@ "shopify-buy": "^2.11.0", "swr": "^0.4.0", "tabbable": "^5.1.5", - "tailwindcss": "^2.0.2" + "tailwindcss": "^2.0.3" }, "devDependencies": { "@graphql-codegen/cli": "^1.20.0", diff --git a/yarn.lock b/yarn.lock index 9238b1f03..2f23e6a57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1609,6 +1609,18 @@ auto-bind@~4.0.0: resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb" integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ== +autoprefixer@^10.2.4: + version "10.2.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.4.tgz#c0e7cf24fcc6a1ae5d6250c623f0cb8beef2f7e1" + integrity sha512-DCCdUQiMD+P/as8m3XkeTUkUKuuRqLGcwD0nll7wevhqoJfMRpJlkFd1+MQh1pvupjiQuip42lc/VFvfUTMSKw== + dependencies: + browserslist "^4.16.1" + caniuse-lite "^1.0.30001181" + colorette "^1.2.1" + fraction.js "^4.0.13" + normalize-range "^0.1.2" + postcss-value-parser "^4.1.0" + autoprefixer@^9.6.1: version "9.8.6" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" @@ -1818,7 +1830,7 @@ browserslist@4.16.1: escalade "^3.1.1" node-releases "^1.1.69" -browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.6.4: +browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.1, browserslist@^4.6.4: version "4.16.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717" integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw== @@ -3187,6 +3199,11 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +fraction.js@^4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.13.tgz#3c1c315fa16b35c85fffa95725a36fa729c69dfe" + integrity sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA== + fs-capacitor@^6.1.0: version "6.2.0" resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-6.2.0.tgz#fa79ac6576629163cb84561995602d8999afb7f5" @@ -5586,7 +5603,7 @@ postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0. source-map "^0.6.1" supports-color "^6.1.0" -postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.4: +postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.6: version "8.2.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.6.tgz#5d69a974543b45f87e464bc4c3e392a97d6be9fe" integrity sha512-xpB8qYxgPuly166AGlpRjUdEYtmOWx2iCwGmrv4vqZL9YPVviDVPZPRXxnXr6xPZOdxQ9lp3ZBFCRgWJ7LE3Sg== @@ -6617,7 +6634,7 @@ tabbable@^5.1.5: resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.1.5.tgz#efec48ede268d511c261e3b81facbb4782a35147" integrity sha512-oVAPrWgLLqrbvQE8XqcU7CVBq6SQbaIbHkhOca3u7/jzuQvyZycrUKPCGr04qpEIUslmUlULbSeN+m3QrKEykA== -tailwindcss@^2.0.2: +tailwindcss@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.0.3.tgz#f8d07797d1f89dc4b171673c26237b58783c2c86" integrity sha512-s8NEqdLBiVbbdL0a5XwTb8jKmIonOuI4RMENEcKLR61jw6SdKvBss7NWZzwCaD+ZIjlgmesv8tmrjXEp7C0eAQ== From 6e8dbf1156d0223d570aded44174e78b2a426805 Mon Sep 17 00:00:00 2001 From: Bel Curcio Date: Mon, 1 Mar 2021 19:02:56 -0300 Subject: [PATCH 04/16] Adding color checks --- .prettierrc | 6 + .../ProductView/ProductView.module.css | 2 +- lib/colors.ts | 155 +++++++++++++++++- package.json | 6 +- yarn.lock | 2 +- 5 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..e1076edfa --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false +} diff --git a/components/product/ProductView/ProductView.module.css b/components/product/ProductView/ProductView.module.css index dec06f665..6545d611b 100644 --- a/components/product/ProductView/ProductView.module.css +++ b/components/product/ProductView/ProductView.module.css @@ -7,7 +7,7 @@ } .productDisplay { - @apply relative flex px-0 pb-0 relative box-border col-span-1 bg-violet; + @apply relative flex px-0 pb-0 box-border col-span-1 bg-violet; min-height: 600px; @screen md { diff --git a/lib/colors.ts b/lib/colors.ts index 355201146..f9c0b5b0b 100644 --- a/lib/colors.ts +++ b/lib/colors.ts @@ -42,9 +42,160 @@ function hexToRgb(hex: string = '') { return [r, g, b] } -export function isDark(color = '') { +const colorMap: Record = { + aliceblue: '#F0F8FF', + antiquewhite: '#FAEBD7', + aqua: '#00FFFF', + aquamarine: '#7FFFD4', + azure: '#F0FFFF', + beige: '#F5F5DC', + bisque: '#FFE4C4', + black: '#000000', + blanchedalmond: '#FFEBCD', + blue: '#0000FF', + blueviolet: '#8A2BE2', + brown: '#A52A2A', + burlywood: '#DEB887', + cadetblue: '#5F9EA0', + chartreuse: '#7FFF00', + chocolate: '#D2691E', + coral: '#FF7F50', + cornflowerblue: '#6495ED', + cornsilk: '#FFF8DC', + crimson: '#DC143C', + cyan: '#00FFFF', + darkblue: '#00008B', + darkcyan: '#008B8B', + darkgoldenrod: '#B8860B', + darkgray: '#A9A9A9', + darkgreen: '#006400', + darkgrey: '#A9A9A9', + darkkhaki: '#BDB76B', + darkmagenta: '#8B008B', + darkolivegreen: '#556B2F', + darkorange: '#FF8C00', + darkorchid: '#9932CC', + darkred: '#8B0000', + darksalmon: '#E9967A', + darkseagreen: '#8FBC8F', + darkslateblue: '#483D8B', + darkslategray: '#2F4F4F', + darkslategrey: '#2F4F4F', + darkturquoise: '#00CED1', + darkviolet: '#9400D3', + deeppink: '#FF1493', + deepskyblue: '#00BFFF', + dimgray: '#696969', + dimgrey: '#696969', + dodgerblue: '#1E90FF', + firebrick: '#B22222', + floralwhite: '#FFFAF0', + forestgreen: '#228B22', + fuchsia: '#FF00FF', + gainsboro: '#DCDCDC', + ghostwhite: '#F8F8FF', + gold: '#FFD700', + goldenrod: '#DAA520', + gray: '#808080', + green: '#008000', + greenyellow: '#ADFF2F', + grey: '#808080', + honeydew: '#F0FFF0', + hotpink: '#FF69B4', + indianred: '#CD5C5C', + indigo: '#4B0082', + ivory: '#FFFFF0', + khaki: '#F0E68C', + lavender: '#E6E6FA', + lavenderblush: '#FFF0F5', + lawngreen: '#7CFC00', + lemonchiffon: '#FFFACD', + lightblue: '#ADD8E6', + lightcoral: '#F08080', + lightcyan: '#E0FFFF', + lightgoldenrodyellow: '#FAFAD2', + lightgray: '#D3D3D3', + lightgreen: '#90EE90', + lightgrey: '#D3D3D3', + lightpink: '#FFB6C1', + lightsalmon: '#FFA07A', + lightseagreen: '#20B2AA', + lightskyblue: '#87CEFA', + lightslategray: '#778899', + lightslategrey: '#778899', + lightsteelblue: '#B0C4DE', + lightyellow: '#FFFFE0', + lime: '#00FF00', + limegreen: '#32CD32', + linen: '#FAF0E6', + magenta: '#FF00FF', + maroon: '#800000', + mediumaquamarine: '#66CDAA', + mediumblue: '#0000CD', + mediumorchid: '#BA55D3', + mediumpurple: '#9370DB', + mediumseagreen: '#3CB371', + mediumslateblue: '#7B68EE', + mediumspringgreen: '#00FA9A', + mediumturquoise: '#48D1CC', + mediumvioletred: '#C71585', + midnightblue: '#191970', + mintcream: '#F5FFFA', + mistyrose: '#FFE4E1', + moccasin: '#FFE4B5', + navajowhite: '#FFDEAD', + navy: '#000080', + oldlace: '#FDF5E6', + olive: '#808000', + olivedrab: '#6B8E23', + orange: '#FFA500', + orangered: '#FF4500', + orchid: '#DA70D6', + palegoldenrod: '#EEE8AA', + palegreen: '#98FB98', + paleturquoise: '#AFEEEE', + palevioletred: '#DB7093', + papayawhip: '#FFEFD5', + peachpuff: '#FFDAB9', + peru: '#CD853F', + pink: '#FFC0CB', + plum: '#DDA0DD', + powderblue: '#B0E0E6', + purple: '#800080', + rebeccapurple: '#663399', + red: '#FF0000', + rosybrown: '#BC8F8F', + royalblue: '#4169E1', + saddlebrown: '#8B4513', + salmon: '#FA8072', + sandybrown: '#F4A460', + seagreen: '#2E8B57', + seashell: '#FFF5EE', + sienna: '#A0522D', + silver: '#C0C0C0', + skyblue: '#87CEEB', + slateblue: '#6A5ACD', + slategray: '#708090', + slategrey: '#708090', + snow: '#FFFAFA', + springgreen: '#00FF7F', + steelblue: '#4682B4', + tan: '#D2B48C', + teal: '#008080', + thistle: '#D8BFD8', + tomato: '#FF6347', + turquoise: '#40E0D0', + violet: '#EE82EE', + wheat: '#F5DEB3', + white: '#FFFFFF', + whitesmoke: '#F5F5F5', + yellow: '#FFFF00', + yellowgreen: '#9ACD32', +} + +export function isDark(color: string = ''): boolean { // Equation from http://24ways.org/2010/calculating-color-contrast - const rgb = hexToRgb(color) + let rgb = colorMap[color] ? hexToRgb(colorMap[color]) : hexToRgb(color) const res = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000 return res < 128 } diff --git a/package.json b/package.json index a3aac641b..4e8fa8d30 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,6 @@ "engines": { "node": "14.x" }, - "prettier": { - "semi": false, - "singleQuote": true - }, "dependencies": { "@reach/portal": "^0.11.2", "@vercel/fetch": "^6.1.0", @@ -74,7 +70,7 @@ "next-unused": "^0.0.3", "postcss-flexbugs-fixes": "^4.2.1", "postcss-preset-env": "^6.7.0", - "prettier": "^2.1.2", + "prettier": "^2.2.1", "typescript": "^4.0.3" }, "resolutions": { diff --git a/yarn.lock b/yarn.lock index 2f23e6a57..7a1dce814 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5662,7 +5662,7 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier@^2.0.5, prettier@^2.1.2: +prettier@^2.0.5, prettier@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== From c87d02a7cdbfa380836fc2212d189b1187348828 Mon Sep 17 00:00:00 2001 From: Bel Curcio Date: Tue, 2 Mar 2021 11:20:24 -0300 Subject: [PATCH 05/16] Now colors work with lighter colors --- lib/colors.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/colors.ts b/lib/colors.ts index f9c0b5b0b..139cda23d 100644 --- a/lib/colors.ts +++ b/lib/colors.ts @@ -194,6 +194,7 @@ const colorMap: Record = { } export function isDark(color: string = ''): boolean { + color = color.toLowerCase() // Equation from http://24ways.org/2010/calculating-color-contrast let rgb = colorMap[color] ? hexToRgb(colorMap[color]) : hexToRgb(color) const res = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000 From 02e15ae4815c1e8538404a413edb679c15eb934f Mon Sep 17 00:00:00 2001 From: Bel Curcio Date: Tue, 2 Mar 2021 11:24:00 -0300 Subject: [PATCH 06/16] Stable commerce.config.json --- commerce.config.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/commerce.config.json b/commerce.config.json index 01d7fa69e..bef7db222 100644 --- a/commerce.config.json +++ b/commerce.config.json @@ -1,3 +1,7 @@ { - "provider": "shopify" + "provider": "bigcommerce", + "features": { + "wishlist": true, + "customCheckout": false + } } From 394efd9e8191c2f3d44198388e03dc9a4fa4627a Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Tue, 2 Mar 2021 18:13:30 -0500 Subject: [PATCH 07/16] Updated main readme --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f254b1b07..cc181b411 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ We're using Github Projects to keep track of issues in progress and todo's. Here ## Integrations -Next.js Commerce integrates out-of-the-box with BigCommerce. We plan to support all major ecommerce backends. +Next.js Commerce integrates out-of-the-box with BigCommerce and Shopify. We plan to support all major ecommerce backends. ## Goals @@ -38,13 +38,13 @@ Next.js Commerce integrates out-of-the-box with BigCommerce. We plan to support There is a `framework` folder in the root folder that will contain multiple ecommerce providers. -Additionally, we need to ensure feature parity (not all providers have e.g. wishlist) we will also have to build a feature API to disable/enable features in the UI. +Additionally, we need to ensure feature parity (not all providers have e.g. wishlist) so we also have a feature API to disable/enable features in the UI. People actively working on this project: @okbel & @lfades. ## Framework -Framework is where the data comes from. It contains mostly hooks and functions. +Framework is where the data comes from. It contains mostly hook handlers and functions. ## Structure @@ -77,7 +77,7 @@ Main folder and its exposed functions - `config.json` - README.md -#### Example of correct usage of Commerce Framework +#### Example of correct usage of the Commerce Framework ```js import { useUI } from '@components/ui' @@ -85,22 +85,57 @@ import { useCustomer } from '@framework/customer' import { useWishlist, useAddItem, useRemoveItem } from '@framework/wishlist' ``` -## Config +## Configuration -### Features +### How to change providers -In order to make the UI entirely functional, we need to specify which features certain providers do not **provide**. +First, update the provider selected in `commerce.config.json`: -**Disabling wishlist:** - -``` +```json { + "provider": "bigcommerce", "features": { - "wishlist": false + "wishlist": true } } ``` +Then, change the paths defined in `tsconfig.json` and update the `@framework` paths to point to the right folder provider: + +```json +"@framework": ["framework/bigcommerce"], +"@framework/*": ["framework/bigcommerce/*"] +``` + +Make sure to add the environment variables required by the new provider. + +### Features + +Every provider defines the features that it supports under `framework/{provider}/commerce.config.json` + +#### How to turn Features on and off + +> NOTE: The selected provider should support the feature that you are toggling. (This means that you can't turn wishlist on if the provider doesn't support this functionality out the box) + +- Open `commerce.config.json` +- You'll see a config file like this: + ```json + { + "provider": "bigcommerce", + "features": { + "wishlist": false + } + } + ``` +- Turn wishlist on by setting wishlist to true. +- Run the app and the wishlist functionality should be back on. + +### How to create a new provider + +We'd recommend to duplicate a provider folder and push your providers SDK. + +If you succeeded building a provider, submit a PR so we can all enjoy it. + ## Contribute Our commitment to Open Source can be found [here](https://vercel.com/oss). From 8337fa1815d904097a0ee28f550a406266aa106c Mon Sep 17 00:00:00 2001 From: Bel Curcio Date: Wed, 3 Mar 2021 08:24:44 -0300 Subject: [PATCH 08/16] Readme changes --- README.md | 56 ++++++++++++++++++++++--------------------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index cc181b411..885c95e85 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ Start right now at [nextjs.org/commerce](https://nextjs.org/commerce) Demo live at: [demo.vercel.store](https://demo.vercel.store/) -This project is currently under development. +- Shopify Demo: https://shopify.demo.vercel.store/ +- BigCommerce Demo: https://bigcommerce.demo.vercel.store/ ## Features @@ -21,34 +22,22 @@ This project is currently under development. - Integrations - Integrate seamlessly with the most common ecommerce platforms. - Dark Mode Support -## Work in progress - -We're using Github Projects to keep track of issues in progress and todo's. Here is our [Board](https://github.com/vercel/commerce/projects/1) - ## Integrations Next.js Commerce integrates out-of-the-box with BigCommerce and Shopify. We plan to support all major ecommerce backends. -## Goals +## Considerations -- **Next.js Commerce** should have a completely data **agnostic** UI -- **Aware of schema**: should ship with the right data schemas and types. -- All providers should return the right data types and schemas to blend correctly with Next.js Commerce. -- `@framework` will be the alias utilized in commerce and it will map to the ecommerce provider of preference- e.g BigCommerce, Shopify, Swell. All providers should expose the same standardized functions. _Note that the same applies for recipes using a CMS + an ecommerce provider._ +- `framework/commerce` contains all types, helpers and functions to be used as base to build a new **provider**. +- **Providers** live under `framework`'s root folder and they will extend Next.js Commerce types and functionality. +- **Features API** is to ensure feature parity between the UI and the Provider. The UI should update accordingly and no extra code should be bundled. All extra configuration for features will live under `features` in `commerce.config.json` and if needed it can also be accessed programatically. +- Each **provider** should add its corresponding `next.config.js` and `commerce.config.json` adding specific data related to the provider. For example in case of BigCommerce, the images CDN and additional API routes. +- **Providers don't depend on anything that's specific to the application they're used in**. They only depend on `framework/commerce`, on their own framework folder and on some dependencies included in `package.json` +- We recommend that each **provider** ships with an `env.template` file and a `[readme.md](http://readme.md)` file. -There is a `framework` folder in the root folder that will contain multiple ecommerce providers. +## Provider Structure -Additionally, we need to ensure feature parity (not all providers have e.g. wishlist) so we also have a feature API to disable/enable features in the UI. - -People actively working on this project: @okbel & @lfades. - -## Framework - -Framework is where the data comes from. It contains mostly hook handlers and functions. - -## Structure - -Main folder and its exposed functions +Next.js Commerce provides a set of utilities and functions to create new providers. This is how a provider structure looks like. - `product` - usePrice @@ -68,22 +57,15 @@ Main folder and its exposed functions - getCustomerId - getCustomerWistlist - `cart` - - useCart - useAddItem - useRemoveItem - useUpdateItem - -- `config.json` -- README.md - -#### Example of correct usage of the Commerce Framework - -```js -import { useUI } from '@components/ui' -import { useCustomer } from '@framework/customer' -import { useWishlist, useAddItem, useRemoveItem } from '@framework/wishlist' -``` +- `env.template` +- `provider.ts` +- `commerce.config.json` +- `next.config.js` +- `README.md` ## Configuration @@ -136,6 +118,12 @@ We'd recommend to duplicate a provider folder and push your providers SDK. If you succeeded building a provider, submit a PR so we can all enjoy it. +## Work in progress + +We're using Github Projects to keep track of issues in progress and todo's. Here is our [Board](https://github.com/vercel/commerce/projects/1) + +People actively working on this project: @okbel & @lfades. + ## Contribute Our commitment to Open Source can be found [here](https://vercel.com/oss). From 3682e64cfde053bf5491a38b2e72ddf3a7bb40f3 Mon Sep 17 00:00:00 2001 From: Bel Curcio Date: Wed, 3 Mar 2021 08:32:58 -0300 Subject: [PATCH 09/16] Default to bigcommerce --- framework/commerce/with-config.js | 1 + tsconfig.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/framework/commerce/with-config.js b/framework/commerce/with-config.js index da6705cef..1eb1acc19 100644 --- a/framework/commerce/with-config.js +++ b/framework/commerce/with-config.js @@ -7,6 +7,7 @@ const merge = require('deepmerge') const PROVIDERS = ['bigcommerce', 'shopify'] function getProviderName() { + // TODO: OSOT. return process.env.BIGCOMMERCE_STOREFRONT_API_URL ? 'bigcommerce' : null } diff --git a/tsconfig.json b/tsconfig.json index e20f37099..9e712fb18 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,8 +22,8 @@ "@components/*": ["components/*"], "@commerce": ["framework/commerce"], "@commerce/*": ["framework/commerce/*"], - "@framework": ["framework/shopify"], - "@framework/*": ["framework/shopify/*"] + "@framework": ["framework/bigcommerce"], + "@framework/*": ["framework/bigcommerce/*"] } }, "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], From 09500d4edc83b1fe2047d7568453ca9993f52a2d Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 3 Mar 2021 12:05:12 -0300 Subject: [PATCH 10/16] og config --- config/seo.json | 14 ++++++++++++-- public/card.png | Bin 0 -> 6286 bytes 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 public/card.png diff --git a/config/seo.json b/config/seo.json index 0d0c3d37d..82520cf9b 100644 --- a/config/seo.json +++ b/config/seo.json @@ -1,12 +1,22 @@ { "title": "ACME Storefront | Powered by Next.js Commerce", "titleTemplate": "%s - ACME Storefront", - "description": "Next.js Commerce -> https://www.nextjs.org/commerce", + "description": "Next.js Commerce - https://www.nextjs.org/commerce", "openGraph": { + "title": "ACME Storefront | Powered by Next.js Commerce", + "description": "Next.js Commerce - https://www.nextjs.org/commerce", "type": "website", "locale": "en_IE", "url": "https://nextjs.org/commerce", - "site_name": "Next.js Commerce" + "site_name": "Next.js Commerce", + "images": [ + { + "url": "/card.png", + "width": 800, + "height": 600, + "alt": "Next.js Commerce" + } + ] }, "twitter": { "handle": "@nextjs", diff --git a/public/card.png b/public/card.png new file mode 100644 index 0000000000000000000000000000000000000000..40fcf42d109045944da9f2ac1583fac6c379ff75 GIT binary patch literal 6286 zcmeI1`#%%<|G<}2M~ZGIA#{#Yx^1E)#JZAuA!>^e(hSR;&4xOqj*#Sj>$o0iZrPU0 zjC|x4V`Cd*qugd@r|e>8^Krg^!uN;o_m}g-`}KajU+-Vuuh;u^c|P9n7dM@3cJI{M z2><|g+upe50strl0RUSr{j_~kvt|Dg(dMM`=*Hb}06=yBKVu6Zui(%>d*LoNR{%AG zhq;>z<$%kMmjQtKG}U#VZ2-U_ecNl7-D0-zCuNy4)|1<(&L?do{`68M0jiX+|ICF% zyiS6laze)z<}*N+Jpgee!DLUn*1q;vfX^yRaq_|X)fs}@?MYm&RP<$~z?B)(d=&2n zBzc~^O{!z@YoY)Ew@49Q2LLEn**t64|3)kU62_I!0}{UeEB^Jt|8X1~|5^!_bCdVrHHRCDYLQ5v2$v-&pG8Si<9rG<^vRo!6lI3J$ zsUUu%MaCd2@G==^qiyS3uAO&_0rljE-!wXlm1*#77B># z9TkH6o@QqeIapbl|MFJWqH!@e9*ZX*$!4i%-w`J^$F7TUNDWD>7<{D036H$pT7%9O z=Kg&BR>;ST8*8a(!4q|>k0BjHT2Td!d&*Du@>|ux>yL;}Pa_7b$mce^Y#}@Kz}VJi ziZw|*j%e}liuISU(Sl$?+Lq-f_I5dac3kO9hI5UWSe^=*yNdL&@2BUGII~LWqgK?=O*>cM)xTWNHAMnk5(LT(Pwhg(!Fe-3<*%LGD%&!yB z1Bx+(RZg{S|2VDEnJm22aZr3&+&uV>2xuvUmZS?O&>R^I zqv=T*N4pO4!*l&Bb;+w=lVR_=yFnW{zUOggi{Y>3L*`xx5yG4f#c&|9&UTtQ<>*ld z|MJ79oQ0wyt;v$7z*^}-Xt&-jMn*U*DBeq?f=rM*y zBK3^Pjj)Dg6L{!7)&?y~LWm9~ix-E5&6@^99xH}(*U$W5Zzi429Bl)bZn0ybL!E$g=Xg{O2Bzm?z>2y(_8B3v*ZUf~~rPcM!sr9#{#g3|7;v~;FmO*GS+F)d&@^3`X*Cbvhy`l`f4FZb-&KyTK4hZ=mc3-7mr zV2H&D0^x+9|3yt?hju755vOs_=IFg8B)6cEgiBVK$z`bGV7`qtMBf^!31yK8U`Qg+ z$56z}5mB!4jeLUJa7jRK5-P%ul)ETA!QrM)VMD5;P8|{}L2EN(beU9Gcyc&IAd9l| z%sCr1O#&&gFefVeu0H_I6zpRX4qq}MT4jOka9J(*p^@e@ewMTbN~m@su-5Su%{>dW zPNE{V@$eC1J1e9T)8+13;&AgBJp|u9#IUZAnpY56xL;WfT7nk+CDMcl`oFJE3b4_U zf5d&puSJI3$wz*3ITJLRtju5siRe{60$Y)&@+@sG9r%{oQJBq>WeP8MB5P1Tr}rhrT&)Fi9oOu zp$29@|ANKT>+8};NIpCVoy_R5#*@A2!M z^tVA2w@v%H!W83gTtf_nHEr)E zYz;z^^$0h0!?BuUboyH59`v%=$@0}~ zVbFv37dk1V69{W1MmfH2_EWsJuhH$CEhUT+mUhDfzxYAJsQHQQgD42D1E;!Sq&_Cx z%&={QQ6)~x-vKu==!)D$e_mqda5K$3WW`^o#Hs>POIhRZN@-T`(Ui`tUf0E*1>-l# z#~+x-JTwlI)W*wslTaiHzbbKPEMy$EKt)-94Z(#+u;_l*zIT!Z6q}aKHj50M)O-P6 zsQ~rLu%c=hA9Tz5CXB_%)sKo#ALARgc9t$8gCh>U2-iskfwR9^7~hKX%5HLGi09)* zWLYmCaAa)`E0v($UFtv*IjtvPVCfi+OthXA41ms{+8!1fxCGeXFzPM_4aMlQyJl7t zbEaf?+k;@J4cmgWTo}!U(@Wp`;=Ia2QhQK}O}g=9+>bD`-`CbAn-qW)!Fg_RTtEDSc-8xoO&Y>R!z+@PADN0)qFJM z8gJ(Oz?0}2>0wlO(_8uaJQ%5Pv5dn&WhM71vUWs?()W~bE zWJ>UQiC`OHST#@(2{9mK=y~A;535IohpGhgiZk3od&0Z@xq1-;?lNEgMDMJ0Jaxwj zgT`}=+Fs@FP-Ps>@5+ivF?Nmn=%WK~{3tA8{{-RiRs)5$GjFI+@w{m^)(&ykX`xA8s5V%N z+kQ9NtK}dz{4@kdB=KW^%=9h>*cKO=vSUi`&Zk!OlNjy`64A{vr{LkRNbUYZv2}k| zGQgoTK3RK1xEwtt*4Avp@S>bA*JW{Zdix-r{4Pu1*|cZ zUh24-kw7&+#&wMi9O8`k1aANz->e2dYzEGBt2j*TD@P+54Ge1Vs!*N^6>GCJ2?#bR@+VAy^C1Mb$d*UE}_g*9XcwyKClw|}%*3S9}tETnj3pN8} zj?fja?s)30+hWa-d1W~^&FXrwo(UJy;D!R9bb=erD_VFRQ*UmsT zZw05Owu2iKu6D@0Ji2$0=FJAvo*;Z;IK|Tjab(Ch;P|23jYn{;GWRid&gYP!Bz-T~ux|$axOtWBgxoJk1nF#H7X`CHO z@$M&`5ECXg`&#xqg!wTGhJwE^>rzZK$X1FsT33ndT9}mq(`bDvB+Ed9Rtdsny8N&| z2TVxP8T&A?>qm>Y`l9obxr6C{0eM|)bx{N`mZLo7h-IBW~O_+L@)O@Y?ZJ=-@N=O2xpW; zJCs6rS#Z`i0y+38UFwycHHPrd_ft?YQ>}_6xJgf2KUwf(e8@O!uH!H~9cp16D=-QV z2=rl9JO$2f);lwV#aRqHZ@8+;8uG?w&cid`{k^GF78frjd@v1wBX(NhA|&r}?1h`? z;Hv~hK3&GcP#Pg!ja~rRM)_!FrXD zKWp&naCl;|;K{IRut4cG>zuuTmFGyZA(dbKHKv*FBs2+*5bohc@* z9ZZV6;mrcomFr3t9on3ez(EaioSse+D>lTN$Ip-w=32A({ort?g>58heNQNh_%f1F z-v|y_MC0C^{vR^v7XQL?+(V9_+G?8Zbq>3t%{@zus9*NHs1Ci2()c3%U6NEBFw$D< zWq9K-;gD|lpE^wme&mYLlSefkv$48xU{IzPVzf!Elh*p%@gUN2=Os&*d5Fx$TNWr^ zbo^pvigGerUqFfVf+RIO1;{%@- zXrQ?H)0Y_E$_ zqL?$x|8Nd}1iFg``0PZL8t`Jhd5%`tMMW;?2(<7yI`N@fs!Tn8wR3=Qs`#vLSV|BS z6a~HK7H%~8Zkd|xYoRp`sdyB&IPuXET1Z2QPN}N})q{TpfBMnBMM61hqH^+7`Rs^~ z2{oW(bb{U7^}1r!D?Y=7n~aahZ-{1O>poB= ziynUle5QK$q}e8sSoZ--T|;Keu);MZTraMRZa%qhQk=EWI1^|K9s8QK z;6C5zB{!c~c9nEHVrw%k4A=fap|HUV4-w80DXHq`BM<0u!_za|Kw9?BCZeJn_ZBr8 z8eh^~>u~ig6&aDdYp4qZ=;uU>I63u&tU#6D6E)zkH`n`x6%%$^6e2u9ouw)D>HIH*5k-JpCXIUsPF}I2=H^#I70q-4g8N9X|NCu%jtSsAw7Ud62+K1yK#L# zx|0d(ZFq6FXMAnbZ4V{wiF%xpHb6qpOj4Ul70vAu@-zX7yO(c1I}y9S8oFXq1W}&i zSxmVfEpuFXApV>~1#e5(!<^7-QrwSLwCT=9N# zg$e`GXhCKJ`vKX`dgniG)${<$nH85WRdzf%t5=e=3vj`2>fYuX=dJ=(z|F$;?SPvF t|B8Qo@c$hL6Aa00;10m0+a4P`9x^|hNMP)S&F=$%?RBSXHCMbJ{}*ufSCaq$ literal 0 HcmV?d00001 From e2368efa9598a7fb68b55b34c8d738e94a2ca236 Mon Sep 17 00:00:00 2001 From: cond0r Date: Wed, 3 Mar 2021 17:48:11 +0200 Subject: [PATCH 11/16] Fix add to cart & prepare for user activation --- components/product/helpers.ts | 4 + .../api/operations/get-all-collections.ts | 21 ----- framework/shopify/api/operations/get-page.ts | 25 ------ framework/shopify/auth/use-signup.tsx | 44 +++++----- framework/shopify/cart/use-add-item.tsx | 3 +- framework/shopify/cart/use-cart.tsx | 4 +- .../shopify/cart/utils/checkout-create.ts | 5 +- .../shopify/cart/utils/checkout-to-cart.ts | 12 ++- framework/shopify/product/use-search.tsx | 3 +- framework/shopify/utils/get-vendors.ts | 22 +++-- .../utils/handle-account-activation.ts | 35 ++++++++ framework/shopify/utils/handle-login.ts | 18 ++++ framework/shopify/utils/index.ts | 2 + .../mutations/customer-activate-by-url.ts | 19 ++++ .../utils/mutations/customer-activate.ts | 19 ++++ framework/shopify/utils/mutations/index.ts | 2 + framework/shopify/utils/normalize.ts | 59 ++++++++----- framework/shopify/wishlist/use-add-item.tsx | 39 +++++++-- .../shopify/wishlist/use-remove-item.tsx | 47 +++++++--- framework/shopify/wishlist/use-wishlist.tsx | 87 ++++++++++--------- pages/customer/activate.tsx | 26 ++++++ pages/search.tsx | 6 +- tsconfig.json | 4 +- 23 files changed, 329 insertions(+), 177 deletions(-) delete mode 100644 framework/shopify/api/operations/get-all-collections.ts delete mode 100644 framework/shopify/api/operations/get-page.ts create mode 100644 framework/shopify/utils/handle-account-activation.ts create mode 100644 framework/shopify/utils/mutations/customer-activate-by-url.ts create mode 100644 framework/shopify/utils/mutations/customer-activate.ts create mode 100644 pages/customer/activate.tsx diff --git a/components/product/helpers.ts b/components/product/helpers.ts index 029476c92..381dcbc1d 100644 --- a/components/product/helpers.ts +++ b/components/product/helpers.ts @@ -14,6 +14,10 @@ export function getVariant(product: Product, opts: SelectedOptions) { option.displayName.toLowerCase() === key.toLowerCase() ) { return option.values.find((v) => v.label.toLowerCase() === value) + } else if (!value) { + return !variant.options.filter( + ({ displayName }) => displayName.toLowerCase() === key + ).length } }) ) diff --git a/framework/shopify/api/operations/get-all-collections.ts b/framework/shopify/api/operations/get-all-collections.ts deleted file mode 100644 index 9cf216a91..000000000 --- a/framework/shopify/api/operations/get-all-collections.ts +++ /dev/null @@ -1,21 +0,0 @@ -import Client from 'shopify-buy' -import { ShopifyConfig } from '../index' - -type Options = { - config: ShopifyConfig -} - -const getAllCollections = async (options: Options) => { - const { config } = options - - const client = Client.buildClient({ - storefrontAccessToken: config.apiToken, - domain: config.commerceUrl, - }) - - const res = await client.collection.fetchAllWithProducts() - - return JSON.parse(JSON.stringify(res)) -} - -export default getAllCollections diff --git a/framework/shopify/api/operations/get-page.ts b/framework/shopify/api/operations/get-page.ts deleted file mode 100644 index 32acb7c8f..000000000 --- a/framework/shopify/api/operations/get-page.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Page } from '../../schema' -import { ShopifyConfig, getConfig } from '..' - -export type GetPageResult = T - -export type PageVariables = { - id: string -} - -async function getPage({ - url, - variables, - config, - preview, -}: { - url?: string - variables: PageVariables - config?: ShopifyConfig - preview?: boolean -}): Promise { - config = getConfig(config) - return {} -} - -export default getPage diff --git a/framework/shopify/auth/use-signup.tsx b/framework/shopify/auth/use-signup.tsx index 7f66448d3..65ed9f71d 100644 --- a/framework/shopify/auth/use-signup.tsx +++ b/framework/shopify/auth/use-signup.tsx @@ -1,15 +1,16 @@ import { useCallback } from 'react' import type { MutationHook } from '@commerce/utils/types' -import { CommerceError } from '@commerce/utils/errors' +import { CommerceError, ValidationError } from '@commerce/utils/errors' import useSignup, { UseSignup } from '@commerce/auth/use-signup' import useCustomer from '../customer/use-customer' -import { CustomerCreateInput } from '../schema' - import { - customerCreateMutation, - customerAccessTokenCreateMutation, -} from '../utils/mutations' -import handleLogin from '../utils/handle-login' + CustomerCreateInput, + Mutation, + MutationCustomerCreateArgs, +} from '../schema' + +import { customerCreateMutation } from '../utils/mutations' +import { handleAutomaticLogin, handleAccountActivation } from '../utils' export default useSignup as UseSignup @@ -33,7 +34,11 @@ export const handler: MutationHook< 'A first name, last name, email and password are required to signup', }) } - const data = await fetch({ + + const { customerCreate } = await fetch< + Mutation, + MutationCustomerCreateArgs + >({ ...options, variables: { input: { @@ -45,19 +50,18 @@ export const handler: MutationHook< }, }) - try { - const loginData = await fetch({ - query: customerAccessTokenCreateMutation, - variables: { - input: { - email, - password, - }, - }, + const errors = customerCreate?.customerUserErrors + + if (errors && errors.length) { + const [error] = errors + throw new ValidationError({ + message: error.message, }) - handleLogin(loginData) - } catch (error) {} - return data + } + + await handleAutomaticLogin(fetch, { email, password }) + + return null }, useHook: ({ fetch }) => () => { const { revalidate } = useCustomer() diff --git a/framework/shopify/cart/use-add-item.tsx b/framework/shopify/cart/use-add-item.tsx index d0f891148..36f02847b 100644 --- a/framework/shopify/cart/use-add-item.tsx +++ b/framework/shopify/cart/use-add-item.tsx @@ -40,8 +40,7 @@ export const handler: MutationHook = { }, }) - // TODO: Fix this Cart type here - return checkoutToCart(checkoutLineItemsAdd) as any + return checkoutToCart(checkoutLineItemsAdd) }, useHook: ({ fetch }) => () => { const { mutate } = useCart() diff --git a/framework/shopify/cart/use-cart.tsx b/framework/shopify/cart/use-cart.tsx index d154bb837..a8be04969 100644 --- a/framework/shopify/cart/use-cart.tsx +++ b/framework/shopify/cart/use-cart.tsx @@ -22,6 +22,7 @@ export const handler: SWRHook< }, async fetcher({ input: { cartId: checkoutId }, options, fetch }) { let checkout + if (checkoutId) { const data = await fetch({ ...options, @@ -36,8 +37,7 @@ export const handler: SWRHook< checkout = await checkoutCreate(fetch) } - // TODO: Fix this type - return checkoutToCart({ checkout } as any) + return checkoutToCart({ checkout }) }, useHook: ({ useData }) => (input) => { const response = useData({ diff --git a/framework/shopify/cart/utils/checkout-create.ts b/framework/shopify/cart/utils/checkout-create.ts index e950cc7e4..20c23bcd3 100644 --- a/framework/shopify/cart/utils/checkout-create.ts +++ b/framework/shopify/cart/utils/checkout-create.ts @@ -6,8 +6,11 @@ import { import checkoutCreateMutation from '../../utils/mutations/checkout-create' import Cookies from 'js-cookie' +import { CheckoutCreatePayload } from '../../schema' -export const checkoutCreate = async (fetch: any) => { +export const checkoutCreate = async ( + fetch: any +): Promise => { const data = await fetch({ query: checkoutCreateMutation, }) diff --git a/framework/shopify/cart/utils/checkout-to-cart.ts b/framework/shopify/cart/utils/checkout-to-cart.ts index 03005f342..5465e511c 100644 --- a/framework/shopify/cart/utils/checkout-to-cart.ts +++ b/framework/shopify/cart/utils/checkout-to-cart.ts @@ -5,14 +5,24 @@ import { CheckoutLineItemsAddPayload, CheckoutLineItemsRemovePayload, CheckoutLineItemsUpdatePayload, - Maybe, + CheckoutCreatePayload, + Checkout, + UserError, } from '../../schema' import { normalizeCart } from '../../utils' +import { Maybe } from 'framework/bigcommerce/schema' + +export type CheckoutQuery = { + checkout: Checkout + userErrors?: Array +} export type CheckoutPayload = | CheckoutLineItemsAddPayload | CheckoutLineItemsUpdatePayload | CheckoutLineItemsRemovePayload + | CheckoutCreatePayload + | CheckoutQuery const checkoutToCart = (checkoutPayload?: Maybe): Cart => { if (!checkoutPayload) { diff --git a/framework/shopify/product/use-search.tsx b/framework/shopify/product/use-search.tsx index 425df9e83..bf812af3d 100644 --- a/framework/shopify/product/use-search.tsx +++ b/framework/shopify/product/use-search.tsx @@ -48,7 +48,8 @@ export const handler: SWRHook< edges = data.node?.products?.edges ?? [] if (brandId) { edges = edges.filter( - ({ node: { vendor } }: ProductEdge) => vendor === brandId + ({ node: { vendor } }: ProductEdge) => + vendor.replace(/\s+/g, '-').toLowerCase() === brandId ) } } else { diff --git a/framework/shopify/utils/get-vendors.ts b/framework/shopify/utils/get-vendors.ts index f04483bb1..24843f177 100644 --- a/framework/shopify/utils/get-vendors.ts +++ b/framework/shopify/utils/get-vendors.ts @@ -2,13 +2,14 @@ import { ShopifyConfig } from '../api' import fetchAllProducts from '../api/utils/fetch-all-products' import getAllProductVendors from './queries/get-all-product-vendors-query' -export type BrandNode = { +export type Brand = { + entityId: string name: string path: string } export type BrandEdge = { - node: BrandNode + node: Brand } export type Brands = BrandEdge[] @@ -24,13 +25,16 @@ const getVendors = async (config: ShopifyConfig): Promise => { let vendorsStrings = vendors.map(({ node: { vendor } }) => vendor) - return [...new Set(vendorsStrings)].map((v) => ({ - node: { - entityId: v, - name: v, - path: `brands/${v}`, - }, - })) + return [...new Set(vendorsStrings)].map((v) => { + const id = v.replace(/\s+/g, '-').toLowerCase() + return { + node: { + entityId: id, + name: v, + path: `brands/${id}`, + }, + } + }) } export default getVendors diff --git a/framework/shopify/utils/handle-account-activation.ts b/framework/shopify/utils/handle-account-activation.ts new file mode 100644 index 000000000..3f5aff5b8 --- /dev/null +++ b/framework/shopify/utils/handle-account-activation.ts @@ -0,0 +1,35 @@ +import { ValidationError } from '@commerce/utils/errors' +import { FetcherOptions } from '@commerce/utils/types' +import { + MutationCustomerActivateArgs, + MutationCustomerActivateByUrlArgs, +} from '../schema' +import { Mutation } from '../schema' +import { customerActivateByUrlMutation } from './mutations' + +const handleAccountActivation = async ( + fetch: (options: FetcherOptions) => Promise, + input: MutationCustomerActivateByUrlArgs +) => { + try { + const { customerActivateByUrl } = await fetch< + Mutation, + MutationCustomerActivateArgs + >({ + query: customerActivateByUrlMutation, + variables: { + input, + }, + }) + + const errors = customerActivateByUrl?.customerUserErrors + if (errors && errors.length) { + const [error] = errors + throw new ValidationError({ + message: error.message, + }) + } + } catch (error) {} +} + +export default handleAccountActivation diff --git a/framework/shopify/utils/handle-login.ts b/framework/shopify/utils/handle-login.ts index 77b6873e3..0a0a2e8ec 100644 --- a/framework/shopify/utils/handle-login.ts +++ b/framework/shopify/utils/handle-login.ts @@ -1,5 +1,8 @@ import { ValidationError } from '@commerce/utils/errors' +import { FetcherOptions } from '@commerce/utils/types' +import { CustomerAccessTokenCreateInput } from '../schema' import { setCustomerToken } from './customer-token' +import { customerAccessTokenCreateMutation } from './mutations' const getErrorMessage = ({ code, @@ -36,4 +39,19 @@ const handleLogin = (data: any) => { return customerAccessToken } +export const handleAutomaticLogin = async ( + fetch: (options: FetcherOptions) => Promise, + input: CustomerAccessTokenCreateInput +) => { + try { + const loginData = await fetch({ + query: customerAccessTokenCreateMutation, + variables: { + input, + }, + }) + handleLogin(loginData) + } catch (error) {} +} + export default handleLogin diff --git a/framework/shopify/utils/index.ts b/framework/shopify/utils/index.ts index 2d59aa506..01a5743e5 100644 --- a/framework/shopify/utils/index.ts +++ b/framework/shopify/utils/index.ts @@ -4,6 +4,8 @@ export { default as getSortVariables } from './get-sort-variables' export { default as getVendors } from './get-vendors' export { default as getCategories } from './get-categories' export { default as getCheckoutId } from './get-checkout-id' +export { default as handleLogin, handleAutomaticLogin } from './handle-login' +export { default as handleAccountActivation } from './handle-account-activation' export * from './queries' export * from './mutations' export * from './normalize' diff --git a/framework/shopify/utils/mutations/customer-activate-by-url.ts b/framework/shopify/utils/mutations/customer-activate-by-url.ts new file mode 100644 index 000000000..345d502bd --- /dev/null +++ b/framework/shopify/utils/mutations/customer-activate-by-url.ts @@ -0,0 +1,19 @@ +const customerActivateByUrlMutation = /* GraphQL */ ` + mutation customerActivateByUrl($activationUrl: URL!, $password: String!) { + customerActivateByUrl(activationUrl: $activationUrl, password: $password) { + customer { + id + } + customerAccessToken { + accessToken + expiresAt + } + customerUserErrors { + code + field + message + } + } + } +` +export default customerActivateByUrlMutation diff --git a/framework/shopify/utils/mutations/customer-activate.ts b/framework/shopify/utils/mutations/customer-activate.ts new file mode 100644 index 000000000..b1d057c69 --- /dev/null +++ b/framework/shopify/utils/mutations/customer-activate.ts @@ -0,0 +1,19 @@ +const customerActivateMutation = /* GraphQL */ ` + mutation customerActivate($id: ID!, $input: CustomerActivateInput!) { + customerActivate(id: $id, input: $input) { + customer { + id + } + customerAccessToken { + accessToken + expiresAt + } + customerUserErrors { + code + field + message + } + } + } +` +export default customerActivateMutation diff --git a/framework/shopify/utils/mutations/index.ts b/framework/shopify/utils/mutations/index.ts index 3a16d7cec..165fb192d 100644 --- a/framework/shopify/utils/mutations/index.ts +++ b/framework/shopify/utils/mutations/index.ts @@ -5,3 +5,5 @@ export { default as checkoutLineItemUpdateMutation } from './checkout-line-item- export { default as checkoutLineItemRemoveMutation } from './checkout-line-item-remove' export { default as customerAccessTokenCreateMutation } from './customer-access-token-create' export { default as customerAccessTokenDeleteMutation } from './customer-access-token-delete' +export { default as customerActivateMutation } from './customer-activate' +export { default as customerActivateByUrlMutation } from './customer-activate-by-url' diff --git a/framework/shopify/utils/normalize.ts b/framework/shopify/utils/normalize.ts index c9b428b37..5f11fe7c6 100644 --- a/framework/shopify/utils/normalize.ts +++ b/framework/shopify/utils/normalize.ts @@ -33,7 +33,7 @@ const normalizeProductOption = ({ let output: any = { label: value, } - if (displayName === 'Color') { + if (displayName.match(/colou?r/gi)) { output = { ...output, hexColors: [value], @@ -54,21 +54,24 @@ const normalizeProductVariants = ({ edges }: ProductVariantConnection) => { return edges?.map( ({ node: { id, selectedOptions, sku, title, priceV2, compareAtPriceV2 }, - }) => ({ - id, - name: title, - sku: sku ?? id, - price: +priceV2.amount, - listPrice: +compareAtPriceV2?.amount, - requiresShipping: true, - options: selectedOptions.map(({ name, value }: SelectedOption) => - normalizeProductOption({ - id, - name, - values: [value], - }) - ), - }) + }) => { + return { + id, + name: title, + sku: sku ?? id, + price: +priceV2.amount, + listPrice: +compareAtPriceV2?.amount, + requiresShipping: true, + options: selectedOptions.map(({ name, value }: SelectedOption) => { + const options = normalizeProductOption({ + id, + name, + values: [value], + }) + return options + }), + } + } ) } @@ -96,7 +99,12 @@ export function normalizeProduct(productNode: ShopifyProduct): Product { price: money(priceRange?.minVariantPrice), images: normalizeProductImages(images), variants: variants ? normalizeProductVariants(variants) : [], - options: options ? options.map((o) => normalizeProductOption(o)) : [], + options: + options + ?.filter(({ name, values }) => { + return name !== 'Title' && values !== ['Default Title'] + }) + .map((o) => normalizeProductOption(o)) ?? [], ...rest, } @@ -122,7 +130,7 @@ export function normalizeCart(checkout: Checkout): Cart { } function normalizeLineItem({ - node: { id, title, variant, quantity }, + node: { id, title, variant, quantity, ...rest }, }: CheckoutLineItemEdge): LineItem { return { id, @@ -135,7 +143,7 @@ function normalizeLineItem({ sku: variant?.sku ?? '', name: variant?.title!, image: { - url: variant?.image?.originalSrc, + url: variant?.image?.originalSrc ?? '/product-img-placeholder.svg', }, requiresShipping: variant?.requiresShipping ?? false, price: variant?.priceV2?.amount, @@ -143,10 +151,13 @@ function normalizeLineItem({ }, path: '', discounts: [], - options: [ - { - value: variant?.title, - }, - ], + options: + variant?.title !== 'Default Title' + ? [ + { + value: variant?.title, + }, + ] + : [], } } diff --git a/framework/shopify/wishlist/use-add-item.tsx b/framework/shopify/wishlist/use-add-item.tsx index 75f067c3a..438397f2b 100644 --- a/framework/shopify/wishlist/use-add-item.tsx +++ b/framework/shopify/wishlist/use-add-item.tsx @@ -1,13 +1,34 @@ import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useAddItem, { UseAddItem } from '@commerce/wishlist/use-add-item' -export function emptyHook() { - const useEmptyHook = async (options = {}) => { - return useCallback(async function () { - return Promise.resolve() - }, []) - } +import useCustomer from '../customer/use-customer' +import useWishlist from './use-wishlist' - return useEmptyHook +export default useAddItem as UseAddItem + +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + useHook: ({ fetch }) => () => { + const { data: customer } = useCustomer() + const { revalidate } = useWishlist() + + return useCallback( + async function addItem(item) { + if (!customer) { + // A signed customer is required in order to have a wishlist + throw new CommerceError({ + message: 'Signed customer not found', + }) + } + + await revalidate() + return null + }, + [fetch, revalidate, customer] + ) + }, } - -export default emptyHook diff --git a/framework/shopify/wishlist/use-remove-item.tsx b/framework/shopify/wishlist/use-remove-item.tsx index a2d3a8a05..971ec082f 100644 --- a/framework/shopify/wishlist/use-remove-item.tsx +++ b/framework/shopify/wishlist/use-remove-item.tsx @@ -1,17 +1,36 @@ import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useRemoveItem, { + UseRemoveItem, +} from '@commerce/wishlist/use-remove-item' -type Options = { - includeProducts?: boolean +import useCustomer from '../customer/use-customer' +import useWishlist from './use-wishlist' + +export default useRemoveItem as UseRemoveItem + +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + useHook: ({ fetch }) => () => { + const { data: customer } = useCustomer() + const { revalidate } = useWishlist() + + return useCallback( + async function addItem(item) { + if (!customer) { + // A signed customer is required in order to have a wishlist + throw new CommerceError({ + message: 'Signed customer not found', + }) + } + + await revalidate() + return null + }, + [fetch, revalidate, customer] + ) + }, } - -export function emptyHook(options?: Options) { - const useEmptyHook = async ({ id }: { id: string | number }) => { - return useCallback(async function () { - return Promise.resolve() - }, []) - } - - return useEmptyHook -} - -export default emptyHook diff --git a/framework/shopify/wishlist/use-wishlist.tsx b/framework/shopify/wishlist/use-wishlist.tsx index d2ce9db5b..651ea06c8 100644 --- a/framework/shopify/wishlist/use-wishlist.tsx +++ b/framework/shopify/wishlist/use-wishlist.tsx @@ -1,46 +1,49 @@ -// TODO: replace this hook and other wishlist hooks with a handler, or remove them if -// Shopify doesn't have a wishlist +import { useMemo } from 'react' +import { SWRHook } from '@commerce/utils/types' +import useWishlist, { UseWishlist } from '@commerce/wishlist/use-wishlist' +import useCustomer from '../customer/use-customer' -import { HookFetcher } from '@commerce/utils/types' -import { Product } from '../schema' +export type UseWishlistInput = { includeProducts?: boolean } -const defaultOpts = {} +export default useWishlist as UseWishlist -export type Wishlist = { - items: [ - { - product_id: number - variant_id: number - id: number - product: Product - } - ] +export const handler: SWRHook< + any | null, + UseWishlistInput, + { customerId?: number } & UseWishlistInput, + { isEmpty?: boolean } +> = { + fetchOptions: { + url: '/api/bigcommerce/wishlist', + method: 'GET', + }, + fetcher() { + return { items: [] } + }, + useHook: ({ useData }) => (input) => { + const { data: customer } = useCustomer() + const response = useData({ + input: [ + ['customerId', customer?.entityId], + ['includeProducts', input?.includeProducts], + ], + swrOptions: { + revalidateOnFocus: false, + ...input?.swrOptions, + }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.items?.length || 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, } - -export interface UseWishlistOptions { - includeProducts?: boolean -} - -export interface UseWishlistInput extends UseWishlistOptions { - customerId?: number -} - -export const fetcher: HookFetcher = () => { - return null -} - -export function extendHook( - customFetcher: typeof fetcher, - // swrOptions?: SwrOptions - swrOptions?: any -) { - const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => { - return { data: null } - } - - useWishlist.extend = extendHook - - return useWishlist -} - -export default extendHook(fetcher) diff --git a/pages/customer/activate.tsx b/pages/customer/activate.tsx new file mode 100644 index 000000000..61e4da0ca --- /dev/null +++ b/pages/customer/activate.tsx @@ -0,0 +1,26 @@ +import type { GetStaticPropsContext } from 'next' +import { getConfig } from '@framework/api' +import getAllPages from '@framework/common/get-all-pages' +import { Layout } from '@components/common' +import { Container, Text } from '@components/ui' + +export async function getStaticProps({ + preview, + locale, +}: GetStaticPropsContext) { + const config = getConfig({ locale }) + const { pages } = await getAllPages({ config, preview }) + return { + props: { pages }, + } +} + +export default function ActivateAccount() { + return ( + + Activate Your Account + + ) +} + +ActivateAccount.Layout = Layout diff --git a/pages/search.tsx b/pages/search.tsx index da2edccd8..4100108bc 100644 --- a/pages/search.tsx +++ b/pages/search.tsx @@ -75,10 +75,8 @@ export default function Search({ const { data } = useSearch({ search: typeof q === 'string' ? q : '', - // TODO: Shopify - Fix this type - categoryId: activeCategory?.entityId as any, - // TODO: Shopify - Fix this type - brandId: (activeBrand as any)?.entityId, + categoryId: activeCategory?.entityId, + brandId: activeBrand?.entityId, sort: typeof sort === 'string' ? sort : '', }) diff --git a/tsconfig.json b/tsconfig.json index e20f37099..9e712fb18 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,8 +22,8 @@ "@components/*": ["components/*"], "@commerce": ["framework/commerce"], "@commerce/*": ["framework/commerce/*"], - "@framework": ["framework/shopify"], - "@framework/*": ["framework/shopify/*"] + "@framework": ["framework/bigcommerce"], + "@framework/*": ["framework/bigcommerce/*"] } }, "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], From 59dedf58cc7044b28bc4097763f5c173e1856fcb Mon Sep 17 00:00:00 2001 From: cond0r Date: Wed, 3 Mar 2021 20:06:21 +0200 Subject: [PATCH 12/16] Update helpers.ts --- components/product/helpers.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/product/helpers.ts b/components/product/helpers.ts index 381dcbc1d..5dd1e2d04 100644 --- a/components/product/helpers.ts +++ b/components/product/helpers.ts @@ -15,9 +15,9 @@ export function getVariant(product: Product, opts: SelectedOptions) { ) { return option.values.find((v) => v.label.toLowerCase() === value) } else if (!value) { - return !variant.options.filter( - ({ displayName }) => displayName.toLowerCase() === key - ).length + return !variant.options.find( + (v) => v.displayName.toLowerCase() === key + ) } }) ) From 639863bb354fc6a90fae5b52ab0facecede974b7 Mon Sep 17 00:00:00 2001 From: cond0r Date: Wed, 3 Mar 2021 20:36:36 +0200 Subject: [PATCH 13/16] Update helpers.ts --- components/product/helpers.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/components/product/helpers.ts b/components/product/helpers.ts index 5dd1e2d04..44bdeca97 100644 --- a/components/product/helpers.ts +++ b/components/product/helpers.ts @@ -8,18 +8,18 @@ export type SelectedOptions = { export function getVariant(product: Product, opts: SelectedOptions) { const variant = product.variants.find((variant) => { return Object.entries(opts).every(([key, value]) => - variant.options.find((option) => { - if ( - option.__typename === 'MultipleChoiceOption' && - option.displayName.toLowerCase() === key.toLowerCase() - ) { - return option.values.find((v) => v.label.toLowerCase() === value) - } else if (!value) { - return !variant.options.find( - (v) => v.displayName.toLowerCase() === key + value + ? variant.options.find((option) => { + if ( + option.__typename === 'MultipleChoiceOption' && + option.displayName.toLowerCase() === key.toLowerCase() + ) { + return option.values.find((v) => v.label.toLowerCase() === value) + } + }) + : !variant.options.find( + (v) => v.displayName.toLowerCase() === key.toLowerCase() ) - } - }) ) }) return variant From 9ccb32ce21574e81ad257d0a551ea9cc6e197f63 Mon Sep 17 00:00:00 2001 From: cond0r Date: Thu, 4 Mar 2021 10:37:51 +0200 Subject: [PATCH 14/16] Changes, fix Shopify GraphQL deprecations --- commerce.config.json | 4 +- framework/shopify/.env.template | 4 +- framework/shopify/auth/use-login.tsx | 9 +---- framework/shopify/auth/use-signup.tsx | 12 +----- framework/shopify/cart/index.ts | 1 + framework/shopify/cart/use-add-item.tsx | 9 +++-- framework/shopify/cart/use-cart.tsx | 2 +- framework/shopify/cart/use-remove-item.tsx | 13 +++---- framework/shopify/cart/use-update-item.tsx | 2 +- framework/shopify/cart/utils/fetcher.ts | 31 --------------- framework/shopify/cart/utils/index.ts | 2 - framework/shopify/provider.ts | 3 -- .../{cart => }/utils/checkout-create.ts | 11 +++--- .../{cart => }/utils/checkout-to-cart.ts | 28 ++++++-------- framework/shopify/utils/get-sort-variables.ts | 2 +- .../utils/handle-account-activation.ts | 11 ++---- framework/shopify/utils/handle-login.ts | 25 +----------- framework/shopify/utils/index.ts | 3 ++ .../utils/mutations/checkout-create.ts | 5 ++- .../utils/mutations/checkout-line-item-add.ts | 5 ++- .../mutations/checkout-line-item-remove.ts | 5 ++- .../mutations/checkout-line-item-update.ts | 5 ++- .../mutations/customer-access-token-delete.ts | 2 +- framework/shopify/utils/throw-user-errors.ts | 38 +++++++++++++++++++ tsconfig.json | 4 +- 25 files changed, 103 insertions(+), 133 deletions(-) delete mode 100644 framework/shopify/cart/utils/fetcher.ts delete mode 100644 framework/shopify/cart/utils/index.ts rename framework/shopify/{cart => }/utils/checkout-create.ts (72%) rename framework/shopify/{cart => }/utils/checkout-to-cart.ts (56%) create mode 100644 framework/shopify/utils/throw-user-errors.ts diff --git a/commerce.config.json b/commerce.config.json index bef7db222..e8418f296 100644 --- a/commerce.config.json +++ b/commerce.config.json @@ -1,7 +1,7 @@ { - "provider": "bigcommerce", + "provider": "shopify", "features": { - "wishlist": true, + "wishlist": false, "customCheckout": false } } diff --git a/framework/shopify/.env.template b/framework/shopify/.env.template index 24521c2a1..9dc3674b6 100644 --- a/framework/shopify/.env.template +++ b/framework/shopify/.env.template @@ -1,2 +1,2 @@ -SHOPIFY_STORE_DOMAIN= -SHOPIFY_STOREFRONT_ACCESS_TOKEN= +NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN= +NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN= diff --git a/framework/shopify/auth/use-login.tsx b/framework/shopify/auth/use-login.tsx index 188dd54a2..7993822cd 100644 --- a/framework/shopify/auth/use-login.tsx +++ b/framework/shopify/auth/use-login.tsx @@ -10,7 +10,7 @@ import { MutationCheckoutCreateArgs, } from '../schema' import useLogin, { UseLogin } from '@commerce/auth/use-login' -import { setCustomerToken } from '../utils' +import { setCustomerToken, throwUserErrors } from '../utils' export default useLogin as UseLogin @@ -45,13 +45,8 @@ export const handler: MutationHook = { }, }) - const errors = customerAccessTokenCreate?.customerUserErrors + throwUserErrors(customerAccessTokenCreate?.customerUserErrors) - if (errors && errors.length) { - throw new ValidationError({ - message: getErrorMessage(errors[0]), - }) - } const customerAccessToken = customerAccessTokenCreate?.customerAccessToken const accessToken = customerAccessToken?.accessToken diff --git a/framework/shopify/auth/use-signup.tsx b/framework/shopify/auth/use-signup.tsx index 65ed9f71d..9ca5c682f 100644 --- a/framework/shopify/auth/use-signup.tsx +++ b/framework/shopify/auth/use-signup.tsx @@ -10,7 +10,7 @@ import { } from '../schema' import { customerCreateMutation } from '../utils/mutations' -import { handleAutomaticLogin, handleAccountActivation } from '../utils' +import { handleAutomaticLogin, throwUserErrors } from '../utils' export default useSignup as UseSignup @@ -50,15 +50,7 @@ export const handler: MutationHook< }, }) - const errors = customerCreate?.customerUserErrors - - if (errors && errors.length) { - const [error] = errors - throw new ValidationError({ - message: error.message, - }) - } - + throwUserErrors(customerCreate?.customerUserErrors) await handleAutomaticLogin(fetch, { email, password }) return null diff --git a/framework/shopify/cart/index.ts b/framework/shopify/cart/index.ts index 3d288b1df..f6d36b443 100644 --- a/framework/shopify/cart/index.ts +++ b/framework/shopify/cart/index.ts @@ -1,3 +1,4 @@ export { default as useCart } from './use-cart' export { default as useAddItem } from './use-add-item' +export { default as useUpdateItem } from './use-update-item' export { default as useRemoveItem } from './use-remove-item' diff --git a/framework/shopify/cart/use-add-item.tsx b/framework/shopify/cart/use-add-item.tsx index 36f02847b..cce0950e9 100644 --- a/framework/shopify/cart/use-add-item.tsx +++ b/framework/shopify/cart/use-add-item.tsx @@ -1,12 +1,15 @@ +import { useCallback } from 'react' import type { MutationHook } from '@commerce/utils/types' import { CommerceError } from '@commerce/utils/errors' import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' import useCart from './use-cart' +import { + checkoutLineItemAddMutation, + getCheckoutId, + checkoutToCart, +} from '../utils' import { Cart, CartItemBody } from '../types' -import { checkoutLineItemAddMutation, getCheckoutId } from '../utils' -import { checkoutToCart } from './utils' import { Mutation, MutationCheckoutLineItemsAddArgs } from '../schema' -import { useCallback } from 'react' export default useAddItem as UseAddItem diff --git a/framework/shopify/cart/use-cart.tsx b/framework/shopify/cart/use-cart.tsx index a8be04969..ea1982c2c 100644 --- a/framework/shopify/cart/use-cart.tsx +++ b/framework/shopify/cart/use-cart.tsx @@ -6,7 +6,7 @@ import useCommerceCart, { import { Cart } from '../types' import { SWRHook } from '@commerce/utils/types' -import { checkoutCreate, checkoutToCart } from './utils' +import { checkoutCreate, checkoutToCart } from '../utils' import getCheckoutQuery from '../utils/queries/get-checkout-query' export default useCommerceCart as UseCart diff --git a/framework/shopify/cart/use-remove-item.tsx b/framework/shopify/cart/use-remove-item.tsx index e2aef13d8..8db38eac2 100644 --- a/framework/shopify/cart/use-remove-item.tsx +++ b/framework/shopify/cart/use-remove-item.tsx @@ -1,23 +1,22 @@ import { useCallback } from 'react' - import type { MutationHookContext, HookFetcherContext, } from '@commerce/utils/types' - +import { RemoveCartItemBody } from '@commerce/types' import { ValidationError } from '@commerce/utils/errors' - import useRemoveItem, { RemoveItemInput as RemoveItemInputBase, UseRemoveItem, } from '@commerce/cart/use-remove-item' - import useCart from './use-cart' -import { checkoutLineItemRemoveMutation, getCheckoutId } from '../utils' -import { checkoutToCart } from './utils' +import { + checkoutLineItemRemoveMutation, + getCheckoutId, + checkoutToCart, +} from '../utils' import { Cart, LineItem } from '../types' import { Mutation, MutationCheckoutLineItemsRemoveArgs } from '../schema' -import { RemoveCartItemBody } from '@commerce/types' export type RemoveItemFn = T extends LineItem ? (input?: RemoveItemInput) => Promise diff --git a/framework/shopify/cart/use-update-item.tsx b/framework/shopify/cart/use-update-item.tsx index 666ce3d08..49dd6be14 100644 --- a/framework/shopify/cart/use-update-item.tsx +++ b/framework/shopify/cart/use-update-item.tsx @@ -13,7 +13,7 @@ import useUpdateItem, { import useCart from './use-cart' import { handler as removeItemHandler } from './use-remove-item' import type { Cart, LineItem, UpdateCartItemBody } from '../types' -import { checkoutToCart } from './utils' +import { checkoutToCart } from '../utils' import { getCheckoutId, checkoutLineItemUpdateMutation } from '../utils' import { Mutation, MutationCheckoutLineItemsUpdateArgs } from '../schema' diff --git a/framework/shopify/cart/utils/fetcher.ts b/framework/shopify/cart/utils/fetcher.ts deleted file mode 100644 index 6afb55f18..000000000 --- a/framework/shopify/cart/utils/fetcher.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { HookFetcherFn } from '@commerce/utils/types' -import { Cart } from '@commerce/types' -import { checkoutCreate, checkoutToCart } from '.' -import { FetchCartInput } from '@commerce/cart/use-cart' - -const fetcher: HookFetcherFn = async ({ - options, - input: { cartId: checkoutId }, - fetch, -}) => { - let checkout - - if (checkoutId) { - const data = await fetch({ - ...options, - variables: { - checkoutId, - }, - }) - checkout = data.node - } - - if (checkout?.completedAt || !checkoutId) { - checkout = await checkoutCreate(fetch) - } - - // TODO: Fix this type - return checkoutToCart({ checkout } as any) -} - -export default fetcher diff --git a/framework/shopify/cart/utils/index.ts b/framework/shopify/cart/utils/index.ts deleted file mode 100644 index 20d04955d..000000000 --- a/framework/shopify/cart/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as checkoutToCart } from './checkout-to-cart' -export { default as checkoutCreate } from './checkout-create' diff --git a/framework/shopify/provider.ts b/framework/shopify/provider.ts index 383822baa..5041770c6 100644 --- a/framework/shopify/provider.ts +++ b/framework/shopify/provider.ts @@ -23,9 +23,6 @@ export const shopifyProvider = { customer: { useCustomer }, products: { useSearch }, auth: { useLogin, useLogout, useSignup }, - features: { - wishlist: false, - }, } export type ShopifyProvider = typeof shopifyProvider diff --git a/framework/shopify/cart/utils/checkout-create.ts b/framework/shopify/utils/checkout-create.ts similarity index 72% rename from framework/shopify/cart/utils/checkout-create.ts rename to framework/shopify/utils/checkout-create.ts index 20c23bcd3..359d16315 100644 --- a/framework/shopify/cart/utils/checkout-create.ts +++ b/framework/shopify/utils/checkout-create.ts @@ -1,12 +1,13 @@ +import Cookies from 'js-cookie' + import { SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CHECKOUT_URL_COOKIE, SHOPIFY_COOKIE_EXPIRE, -} from '../../const' +} from '../const' -import checkoutCreateMutation from '../../utils/mutations/checkout-create' -import Cookies from 'js-cookie' -import { CheckoutCreatePayload } from '../../schema' +import checkoutCreateMutation from './mutations/checkout-create' +import { CheckoutCreatePayload } from '../schema' export const checkoutCreate = async ( fetch: any @@ -23,7 +24,7 @@ export const checkoutCreate = async ( expires: SHOPIFY_COOKIE_EXPIRE, } Cookies.set(SHOPIFY_CHECKOUT_ID_COOKIE, checkoutId, options) - Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout?.webUrl, options) + Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout.webUrl, options) } return checkout diff --git a/framework/shopify/cart/utils/checkout-to-cart.ts b/framework/shopify/utils/checkout-to-cart.ts similarity index 56% rename from framework/shopify/cart/utils/checkout-to-cart.ts rename to framework/shopify/utils/checkout-to-cart.ts index 5465e511c..b27b619d3 100644 --- a/framework/shopify/cart/utils/checkout-to-cart.ts +++ b/framework/shopify/utils/checkout-to-cart.ts @@ -1,20 +1,22 @@ -import { Cart } from '../../types' -import { CommerceError, ValidationError } from '@commerce/utils/errors' +import { Cart } from '../types' +import { CommerceError } from '@commerce/utils/errors' import { CheckoutLineItemsAddPayload, CheckoutLineItemsRemovePayload, CheckoutLineItemsUpdatePayload, CheckoutCreatePayload, + CheckoutUserError, Checkout, - UserError, -} from '../../schema' -import { normalizeCart } from '../../utils' -import { Maybe } from 'framework/bigcommerce/schema' + Maybe, +} from '../schema' + +import { normalizeCart } from './normalize' +import throwUserErrors from './throw-user-errors' export type CheckoutQuery = { checkout: Checkout - userErrors?: Array + checkoutUserErrors: Array } export type CheckoutPayload = @@ -27,22 +29,16 @@ export type CheckoutPayload = const checkoutToCart = (checkoutPayload?: Maybe): Cart => { if (!checkoutPayload) { throw new CommerceError({ - message: 'Invalid response from Shopify', + message: 'Missing checkout payload from response', }) } const checkout = checkoutPayload?.checkout - const userErrors = checkoutPayload?.userErrors - - if (userErrors && userErrors.length) { - throw new ValidationError({ - message: userErrors[0].message, - }) - } + throwUserErrors(checkoutPayload?.checkoutUserErrors) if (!checkout) { throw new CommerceError({ - message: 'Invalid response from Shopify', + message: 'Missing checkout object from response', }) } diff --git a/framework/shopify/utils/get-sort-variables.ts b/framework/shopify/utils/get-sort-variables.ts index b8cdeec51..141d9a180 100644 --- a/framework/shopify/utils/get-sort-variables.ts +++ b/framework/shopify/utils/get-sort-variables.ts @@ -1,4 +1,4 @@ -const getSortVariables = (sort?: string, isCategory = false) => { +const getSortVariables = (sort?: string, isCategory: boolean = false) => { let output = {} switch (sort) { case 'price-asc': diff --git a/framework/shopify/utils/handle-account-activation.ts b/framework/shopify/utils/handle-account-activation.ts index 3f5aff5b8..d11f80ba1 100644 --- a/framework/shopify/utils/handle-account-activation.ts +++ b/framework/shopify/utils/handle-account-activation.ts @@ -1,5 +1,6 @@ -import { ValidationError } from '@commerce/utils/errors' import { FetcherOptions } from '@commerce/utils/types' +import throwUserErrors from './throw-user-errors' + import { MutationCustomerActivateArgs, MutationCustomerActivateByUrlArgs, @@ -22,13 +23,7 @@ const handleAccountActivation = async ( }, }) - const errors = customerActivateByUrl?.customerUserErrors - if (errors && errors.length) { - const [error] = errors - throw new ValidationError({ - message: error.message, - }) - } + throwUserErrors(customerActivateByUrl?.customerUserErrors) } catch (error) {} } diff --git a/framework/shopify/utils/handle-login.ts b/framework/shopify/utils/handle-login.ts index 0a0a2e8ec..de86fa1d2 100644 --- a/framework/shopify/utils/handle-login.ts +++ b/framework/shopify/utils/handle-login.ts @@ -1,33 +1,12 @@ -import { ValidationError } from '@commerce/utils/errors' import { FetcherOptions } from '@commerce/utils/types' import { CustomerAccessTokenCreateInput } from '../schema' import { setCustomerToken } from './customer-token' import { customerAccessTokenCreateMutation } from './mutations' - -const getErrorMessage = ({ - code, - message, -}: { - code: string - message: string -}) => { - switch (code) { - case 'UNIDENTIFIED_CUSTOMER': - message = 'Cannot find an account that matches the provided credentials' - break - } - return message -} +import throwUserErrors from './throw-user-errors' const handleLogin = (data: any) => { const response = data.customerAccessTokenCreate - const errors = response?.customerUserErrors - - if (errors && errors.length) { - throw new ValidationError({ - message: getErrorMessage(errors[0]), - }) - } + throwUserErrors(response?.customerUserErrors) const customerAccessToken = response?.customerAccessToken const accessToken = customerAccessToken?.accessToken diff --git a/framework/shopify/utils/index.ts b/framework/shopify/utils/index.ts index 01a5743e5..61e5975d7 100644 --- a/framework/shopify/utils/index.ts +++ b/framework/shopify/utils/index.ts @@ -4,8 +4,11 @@ export { default as getSortVariables } from './get-sort-variables' export { default as getVendors } from './get-vendors' export { default as getCategories } from './get-categories' export { default as getCheckoutId } from './get-checkout-id' +export { default as checkoutCreate } from './checkout-create' +export { default as checkoutToCart } from './checkout-to-cart' export { default as handleLogin, handleAutomaticLogin } from './handle-login' export { default as handleAccountActivation } from './handle-account-activation' +export { default as throwUserErrors } from './throw-user-errors' export * from './queries' export * from './mutations' export * from './normalize' diff --git a/framework/shopify/utils/mutations/checkout-create.ts b/framework/shopify/utils/mutations/checkout-create.ts index 912e1cbd2..ffbd555c7 100644 --- a/framework/shopify/utils/mutations/checkout-create.ts +++ b/framework/shopify/utils/mutations/checkout-create.ts @@ -3,9 +3,10 @@ import { checkoutDetailsFragment } from '../queries/get-checkout-query' const checkoutCreateMutation = /* GraphQL */ ` mutation { checkoutCreate(input: {}) { - userErrors { - message + checkoutUserErrors { + code field + message } checkout { ${checkoutDetailsFragment} diff --git a/framework/shopify/utils/mutations/checkout-line-item-add.ts b/framework/shopify/utils/mutations/checkout-line-item-add.ts index 67b9cf250..2282c4e26 100644 --- a/framework/shopify/utils/mutations/checkout-line-item-add.ts +++ b/framework/shopify/utils/mutations/checkout-line-item-add.ts @@ -3,9 +3,10 @@ import { checkoutDetailsFragment } from '../queries/get-checkout-query' const checkoutLineItemAddMutation = /* GraphQL */ ` mutation($checkoutId: ID!, $lineItems: [CheckoutLineItemInput!]!) { checkoutLineItemsAdd(checkoutId: $checkoutId, lineItems: $lineItems) { - userErrors { - message + checkoutUserErrors { + code field + message } checkout { ${checkoutDetailsFragment} diff --git a/framework/shopify/utils/mutations/checkout-line-item-remove.ts b/framework/shopify/utils/mutations/checkout-line-item-remove.ts index d967a5168..8dea4ce08 100644 --- a/framework/shopify/utils/mutations/checkout-line-item-remove.ts +++ b/framework/shopify/utils/mutations/checkout-line-item-remove.ts @@ -6,9 +6,10 @@ const checkoutLineItemRemoveMutation = /* GraphQL */ ` checkoutId: $checkoutId lineItemIds: $lineItemIds ) { - userErrors { - message + checkoutUserErrors { + code field + message } checkout { ${checkoutDetailsFragment} diff --git a/framework/shopify/utils/mutations/checkout-line-item-update.ts b/framework/shopify/utils/mutations/checkout-line-item-update.ts index 8edf17587..76254341e 100644 --- a/framework/shopify/utils/mutations/checkout-line-item-update.ts +++ b/framework/shopify/utils/mutations/checkout-line-item-update.ts @@ -3,9 +3,10 @@ import { checkoutDetailsFragment } from '../queries/get-checkout-query' const checkoutLineItemUpdateMutation = /* GraphQL */ ` mutation($checkoutId: ID!, $lineItems: [CheckoutLineItemUpdateInput!]!) { checkoutLineItemsUpdate(checkoutId: $checkoutId, lineItems: $lineItems) { - userErrors { - message + checkoutUserErrors { + code field + message } checkout { ${checkoutDetailsFragment} diff --git a/framework/shopify/utils/mutations/customer-access-token-delete.ts b/framework/shopify/utils/mutations/customer-access-token-delete.ts index c46eff1e5..208e69c09 100644 --- a/framework/shopify/utils/mutations/customer-access-token-delete.ts +++ b/framework/shopify/utils/mutations/customer-access-token-delete.ts @@ -3,7 +3,7 @@ const customerAccessTokenDeleteMutation = /* GraphQL */ ` customerAccessTokenDelete(customerAccessToken: $customerAccessToken) { deletedAccessToken deletedCustomerAccessTokenId - userErrors { + customerUserErrors { field message } diff --git a/framework/shopify/utils/throw-user-errors.ts b/framework/shopify/utils/throw-user-errors.ts new file mode 100644 index 000000000..5488ba282 --- /dev/null +++ b/framework/shopify/utils/throw-user-errors.ts @@ -0,0 +1,38 @@ +import { ValidationError } from '@commerce/utils/errors' + +import { + CheckoutErrorCode, + CheckoutUserError, + CustomerErrorCode, + CustomerUserError, +} from '../schema' + +export type UserErrors = Array + +export type UserErrorCode = + | CustomerErrorCode + | CheckoutErrorCode + | null + | undefined + +const getCustomMessage = (code: UserErrorCode, message: string) => { + switch (code) { + case 'UNIDENTIFIED_CUSTOMER': + message = 'Cannot find an account that matches the provided credentials' + break + } + return message +} + +export const throwUserErrors = (errors?: UserErrors) => { + if (errors && errors.length) { + throw new ValidationError({ + errors: errors.map(({ code, message }) => ({ + code: code ?? 'validation_error', + message: getCustomMessage(code, message), + })), + }) + } +} + +export default throwUserErrors diff --git a/tsconfig.json b/tsconfig.json index 9e712fb18..e20f37099 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,8 +22,8 @@ "@components/*": ["components/*"], "@commerce": ["framework/commerce"], "@commerce/*": ["framework/commerce/*"], - "@framework": ["framework/bigcommerce"], - "@framework/*": ["framework/bigcommerce/*"] + "@framework": ["framework/shopify"], + "@framework/*": ["framework/shopify/*"] } }, "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], From 5ed0286a2c5192e851b8446a2318885dbef1e2a9 Mon Sep 17 00:00:00 2001 From: cond0r Date: Thu, 4 Mar 2021 10:41:18 +0200 Subject: [PATCH 15/16] Update checkout-to-cart.ts --- framework/shopify/utils/checkout-to-cart.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/shopify/utils/checkout-to-cart.ts b/framework/shopify/utils/checkout-to-cart.ts index b27b619d3..034ff11d7 100644 --- a/framework/shopify/utils/checkout-to-cart.ts +++ b/framework/shopify/utils/checkout-to-cart.ts @@ -16,7 +16,7 @@ import throwUserErrors from './throw-user-errors' export type CheckoutQuery = { checkout: Checkout - checkoutUserErrors: Array + checkoutUserErrors?: Array } export type CheckoutPayload = From 7c3dc90326a3e8900dab88903de0e34667d7ee8d Mon Sep 17 00:00:00 2001 From: cond0r Date: Thu, 4 Mar 2021 10:52:46 +0200 Subject: [PATCH 16/16] Default to BigCommerce --- commerce.config.json | 4 ++-- tsconfig.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/commerce.config.json b/commerce.config.json index e8418f296..bef7db222 100644 --- a/commerce.config.json +++ b/commerce.config.json @@ -1,7 +1,7 @@ { - "provider": "shopify", + "provider": "bigcommerce", "features": { - "wishlist": false, + "wishlist": true, "customCheckout": false } } diff --git a/tsconfig.json b/tsconfig.json index e20f37099..9e712fb18 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,8 +22,8 @@ "@components/*": ["components/*"], "@commerce": ["framework/commerce"], "@commerce/*": ["framework/commerce/*"], - "@framework": ["framework/shopify"], - "@framework/*": ["framework/shopify/*"] + "@framework": ["framework/bigcommerce"], + "@framework/*": ["framework/bigcommerce/*"] } }, "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],