From 65c9d39ae61cdccfbc871605a276a89687e88e32 Mon Sep 17 00:00:00 2001 From: Luis Alvarez D Date: Fri, 11 Feb 2022 11:42:25 -0500 Subject: [PATCH 01/11] Add env vars used for provider detection as keys (#679) --- turbo.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/turbo.json b/turbo.json index ccd7d3567..c734b801f 100644 --- a/turbo.json +++ b/turbo.json @@ -6,7 +6,13 @@ "outputs": ["dist/**"] }, "next-commerce#build": { - "dependsOn": ["^build", "$COMMERCE_PROVIDER"], + "dependsOn": [ + "^build", + "$COMMERCE_PROVIDER", + "$BIGCOMMERCE_STOREFRONT_API_URL", + "$NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN", + "$NEXT_PUBLIC_SWELL_STORE_ID" + ], "outputs": [".next/**"] }, "test": { From db170558d55ee34b4bf86635f78d1aecc9269fa7 Mon Sep 17 00:00:00 2001 From: Dom Sip Date: Fri, 18 Feb 2022 09:26:31 +0000 Subject: [PATCH 02/11] feat: replace next-seo with custom solution (#660) * replace next-seo with custom solution * Updated check Co-authored-by: LFades --- site/components/common/Head/Head.tsx | 23 ++- site/components/common/SEO/SEO.tsx | 157 ++++++++++++++++++ site/components/common/SEO/index.ts | 1 + site/components/common/index.ts | 1 + .../product/ProductView/ProductView.tsx | 8 +- site/config/{seo.json => seo_meta.json} | 5 +- site/package.json | 1 - yarn.lock | 5 - 8 files changed, 176 insertions(+), 25 deletions(-) create mode 100644 site/components/common/SEO/SEO.tsx create mode 100644 site/components/common/SEO/index.ts rename site/config/{seo.json => seo_meta.json} (90%) diff --git a/site/components/common/Head/Head.tsx b/site/components/common/Head/Head.tsx index b2c0c997b..ed43c0d39 100644 --- a/site/components/common/Head/Head.tsx +++ b/site/components/common/Head/Head.tsx @@ -1,17 +1,16 @@ -import { FC } from 'react' -import NextHead from 'next/head' -import { DefaultSeo } from 'next-seo' -import config from '@config/seo.json' +import type { VFC } from 'react' +import { SEO } from '@components/common' -const Head: FC = () => { +const Head: VFC = () => { return ( - <> - - - - - - + + + + ) } diff --git a/site/components/common/SEO/SEO.tsx b/site/components/common/SEO/SEO.tsx new file mode 100644 index 000000000..b5e3ad23b --- /dev/null +++ b/site/components/common/SEO/SEO.tsx @@ -0,0 +1,157 @@ +import Head from 'next/head' +import { FC, Fragment, ReactNode } from 'react' +import config from '@config/seo_meta.json' + +const storeUrl = + process.env.NEXT_PUBLIC_STORE_URL || process.env.NEXT_PUBLIC_VERCEL_URL +const storeBaseUrl = storeUrl ? `https://${storeUrl}` : null + +interface OgImage { + url?: string + width?: string + height?: string + alt?: string +} + +interface Props { + title?: string + description?: string + robots?: string + openGraph?: { + title?: string + type?: string + locale?: string + description?: string + site_name?: string + url?: string + images?: OgImage[] + } + children?: ReactNode +} + +const ogImage = ({ url, width, height, alt }: OgImage, index: number) => { + // generate full URL for OG image url with store base URL + const imgUrl = storeBaseUrl ? new URL(url!, storeBaseUrl).toString() : url + return ( + + + + + + + ) +} + +const SEO: FC = ({ + title, + description, + openGraph, + robots, + children, +}) => { + /** + * @see https://nextjs.org/docs/api-reference/next/head + * + * meta or any other elements need to be contained as direct children of the Head element, + * or wrapped into maximum one level of or arrays + * otherwise the tags won't be correctly picked up on client-side navigations. + * + * The `key` property makes the tag is only rendered once, + */ + return ( + + + {title ? `${config.titleTemplate.replace(/%s/g, title)}` : config.title} + + + + + + + + {openGraph?.locale && ( + + )} + {openGraph?.images?.length + ? openGraph.images.map((img, index) => ogImage(img, index)) + : ogImage(config.openGraph.images[0], 0)} + {config.twitter.cardType && ( + + )} + {config.twitter.site && ( + + )} + {config.twitter.handle && ( + + )} + + + {children} + + ) +} + +export default SEO diff --git a/site/components/common/SEO/index.ts b/site/components/common/SEO/index.ts new file mode 100644 index 000000000..e20ec8600 --- /dev/null +++ b/site/components/common/SEO/index.ts @@ -0,0 +1 @@ +export { default } from './SEO' diff --git a/site/components/common/index.ts b/site/components/common/index.ts index 98dd3394b..054110c75 100644 --- a/site/components/common/index.ts +++ b/site/components/common/index.ts @@ -7,3 +7,4 @@ export { default as Searchbar } from './Searchbar' export { default as UserNav } from './UserNav' export { default as Head } from './Head' export { default as I18nWidget } from './I18nWidget' +export { default as SEO } from './SEO' diff --git a/site/components/product/ProductView/ProductView.tsx b/site/components/product/ProductView/ProductView.tsx index b20c85b0a..31cbcd577 100644 --- a/site/components/product/ProductView/ProductView.tsx +++ b/site/components/product/ProductView/ProductView.tsx @@ -1,6 +1,5 @@ import cn from 'clsx' import Image from 'next/image' -import { NextSeo } from 'next-seo' import s from './ProductView.module.css' import { FC } from 'react' import type { Product } from '@commerce/types/product' @@ -8,6 +7,7 @@ import usePrice from '@framework/product/use-price' import { WishlistButton } from '@components/wishlist' import { ProductSlider, ProductCard } from '@components/product' import { Container, Text } from '@components/ui' +import { SEO } from '@components/common' import ProductSidebar from '../ProductSidebar' import ProductTag from '../ProductTag' interface ProductViewProps { @@ -89,7 +89,7 @@ const ProductView: FC = ({ product, relatedProducts }) => { - = ({ product, relatedProducts }) => { images: [ { url: product.images[0]?.url!, - width: 800, - height: 600, + width: '800', + height: '600', alt: product.name, }, ], diff --git a/site/config/seo.json b/site/config/seo_meta.json similarity index 90% rename from site/config/seo.json rename to site/config/seo_meta.json index 82520cf9b..c9c5fc226 100644 --- a/site/config/seo.json +++ b/site/config/seo_meta.json @@ -6,14 +6,13 @@ "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", "images": [ { "url": "/card.png", - "width": 800, - "height": 600, + "width": "800", + "height": "600", "alt": "Next.js Commerce" } ] diff --git a/site/package.json b/site/package.json index 7a28e7e7b..f5b38acfd 100644 --- a/site/package.json +++ b/site/package.json @@ -34,7 +34,6 @@ "lodash.random": "^3.2.0", "lodash.throttle": "^4.1.1", "next": "^12.0.8", - "next-seo": "^4.28.1", "next-themes": "^0.0.15", "postcss": "^8.3.5", "postcss-nesting": "^8.0.1", diff --git a/yarn.lock b/yarn.lock index 1c1a7fc7b..302dd2402 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4763,11 +4763,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -next-seo@^4.28.1: - version "4.29.0" - resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-4.29.0.tgz#d281e95ba47914117cc99e9e468599f0547d9b9b" - integrity sha512-xmwzcz4uHaYJ8glbuhs6FSBQ7z3irmdPYdJJ5saWm72Uy3o+mPKGaPCXQetTCE6/xxVnpoDV4yFtFlEjUcljSg== - next-themes@^0.0.15: version "0.0.15" resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.15.tgz#ab0cee69cd763b77d41211f631e108beab39bf7d" From 9387178538f35db1c9946543a93c8c936f88098a Mon Sep 17 00:00:00 2001 From: Andrea Barani Date: Fri, 18 Feb 2022 10:40:59 +0100 Subject: [PATCH 03/11] fix(bigcommerce): add limit on product variants (#655) add explicit limit on product variants field to load more than default --- packages/bigcommerce/src/api/fragments/product.ts | 2 +- packages/bigcommerce/src/api/operations/get-product.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/bigcommerce/src/api/fragments/product.ts b/packages/bigcommerce/src/api/fragments/product.ts index d266b8c92..734e0ab63 100644 --- a/packages/bigcommerce/src/api/fragments/product.ts +++ b/packages/bigcommerce/src/api/fragments/product.ts @@ -58,7 +58,7 @@ export const productInfoFragment = /* GraphQL */ ` } } } - variants { + variants(first: 250) { edges { node { entityId diff --git a/packages/bigcommerce/src/api/operations/get-product.ts b/packages/bigcommerce/src/api/operations/get-product.ts index b2f9c9677..c7457de2a 100644 --- a/packages/bigcommerce/src/api/operations/get-product.ts +++ b/packages/bigcommerce/src/api/operations/get-product.ts @@ -21,7 +21,7 @@ export const getProductQuery = /* GraphQL */ ` __typename ... on Product { ...productInfo - variants { + variants(first: 250) { edges { node { entityId From ddc6f83c2ec3e432a0cf36a67623cf1f8e3cde68 Mon Sep 17 00:00:00 2001 From: Dom Sip Date: Tue, 1 Mar 2022 23:50:32 +0000 Subject: [PATCH 04/11] add FAQ for cannot find module error (#695) --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/README.md b/README.md index 1af8bbf35..b8a7b0957 100644 --- a/README.md +++ b/README.md @@ -147,3 +147,40 @@ After Email confirmation, Checkout should be manually enabled through BigCommerc
BigCommerce team has been notified and they plan to add more details about this subject. + +
+When run locally I get `Error: Cannot find module '...@vercel/commerce/dist/config'` + +```bash +commerce/site +❯ yarn dev +yarn run v1.22.17 +$ next dev +ready - started server on 0.0.0.0:3000, url: http://localhost:3000 +info - Loaded env from /commerce/site/.env.local +error - Failed to load next.config.js, see more info here https://nextjs.org/docs/messages/next-config-error +Error: Cannot find module '/Users/dom/work/vercel/commerce/node_modules/@vercel/commerce/dist/config.cjs' + at createEsmNotFoundErr (node:internal/modules/cjs/loader:960:15) + at finalizeEsmResolution (node:internal/modules/cjs/loader:953:15) + at resolveExports (node:internal/modules/cjs/loader:482:14) + at Function.Module._findPath (node:internal/modules/cjs/loader:522:31) + at Function.Module._resolveFilename (node:internal/modules/cjs/loader:919:27) + at Function.mod._resolveFilename (/Users/dom/work/vercel/commerce/node_modules/next/dist/build/webpack/require-hook.js:179:28) + at Function.Module._load (node:internal/modules/cjs/loader:778:27) + at Module.require (node:internal/modules/cjs/loader:1005:19) + at require (node:internal/modules/cjs/helpers:102:18) + at Object. (/Users/dom/work/vercel/commerce/site/commerce-config.js:9:14) { + code: 'MODULE_NOT_FOUND', + path: '/Users/dom/work/vercel/commerce/node_modules/@vercel/commerce/package.json' +} +error Command failed with exit code 1. +info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. +``` + +The error usually occurs when running yarn dev inside of the `/site/` folder after installing a fresh repository. + +In order to fix this, run `yarn dev` in the monorepo root folder first. + +> Using `yarn dev` from the root is recommended for developing, which will run watch mode on all packages. +
+ From bbe97ab0cbc68c3f63f0c6f73d149517603b2696 Mon Sep 17 00:00:00 2001 From: B Date: Wed, 2 Mar 2022 10:51:31 +0100 Subject: [PATCH 05/11] Update README.md with correct Shopify provider variable value (#697) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b8a7b0957..01c66337a 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Open `site/.env.local` and change the value of `COMMERCE_PROVIDER` to the provid The setup for Shopify would look like this for example: ``` -COMMERCE_PROVIDER=shopify +COMMERCE_PROVIDER=@vercel/commerce-shopify NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxx NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN=xxxxxxx.myshopify.com ``` From 0ae927fbcf174293a9283eea3e617c7d6f3fd620 Mon Sep 17 00:00:00 2001 From: Dom Sip Date: Wed, 2 Mar 2022 11:49:12 +0000 Subject: [PATCH 06/11] fix(vendure): add new image domain (#698) --- packages/vendure/src/next.config.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vendure/src/next.config.cjs b/packages/vendure/src/next.config.cjs index 96153ad1e..2e6842f00 100644 --- a/packages/vendure/src/next.config.cjs +++ b/packages/vendure/src/next.config.cjs @@ -3,6 +3,6 @@ const commerce = require('./commerce.config.json') module.exports = { commerce, images: { - domains: ['localhost', 'demo.vendure.io'], + domains: ['localhost', 'demo.vendure.io','readonlydemo.vendure.io'], }, } From 5af4004b57f48ee5bfda7368bfab4b33818c170a Mon Sep 17 00:00:00 2001 From: B Date: Wed, 2 Mar 2022 13:59:13 +0100 Subject: [PATCH 07/11] Bug: Visual Regressions (#699) * ProductTag offset * ProductTag offset --- site/components/product/ProductTag/ProductTag.module.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site/components/product/ProductTag/ProductTag.module.css b/site/components/product/ProductTag/ProductTag.module.css index faf2fd97f..c36b43aa6 100644 --- a/site/components/product/ProductTag/ProductTag.module.css +++ b/site/components/product/ProductTag/ProductTag.module.css @@ -7,7 +7,7 @@ @apply pt-0 max-w-full w-full leading-extra-loose; font-size: 2rem; letter-spacing: 0.4px; - line-height: 2.2em; + line-height: 2.1em; } .root .name span { @@ -27,4 +27,5 @@ .root .price { @apply pt-2 px-6 pb-4 text-sm bg-primary text-accent-9 font-semibold inline-block tracking-wide; + margin-top: -1px; } From 9a45329ad2402c99d6d3bc99e2f4e71d1ac2b233 Mon Sep 17 00:00:00 2001 From: Luis Alvarez D Date: Mon, 7 Mar 2022 19:34:59 -0500 Subject: [PATCH 08/11] Disabled wishlist and user login in bigcommerce (#703) --- package.json | 1 + packages/commerce/src/config.cjs | 6 +++++- site/commerce.config.json | 6 ++++++ turbo.json | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 2854cf992..fc97f30b9 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "build": "turbo run build --scope=next-commerce --include-dependencies --no-deps", "dev": "turbo run dev", "start": "turbo run start", + "types": "turbo run types", "prettier-fix": "prettier --write ." }, "devDependencies": { diff --git a/packages/commerce/src/config.cjs b/packages/commerce/src/config.cjs index aabc16e0c..add0061a9 100644 --- a/packages/commerce/src/config.cjs +++ b/packages/commerce/src/config.cjs @@ -18,10 +18,14 @@ function withCommerceConfig(nextConfig = {}) { const commerceNextConfig = importCwd(path.join(provider, 'next.config')) const config = merge(nextConfig, commerceNextConfig) + const features = merge( + config.commerce.features, + config.commerce[provider]?.features ?? {} + ) config.env = config.env || {} - Object.entries(config.commerce.features).forEach(([k, v]) => { + Object.entries(features).forEach(([k, v]) => { if (v) config.env[`COMMERCE_${k.toUpperCase()}_ENABLED`] = true }) diff --git a/site/commerce.config.json b/site/commerce.config.json index ad72b58de..dd43ae077 100644 --- a/site/commerce.config.json +++ b/site/commerce.config.json @@ -5,5 +5,11 @@ "wishlist": false, "customerAuth": false, "customCheckout": false + }, + "@vercel/commerce-bigcommerce": { + "features": { + "wishlist": false, + "customerAuth": false + } } } diff --git a/turbo.json b/turbo.json index c734b801f..8e38ccddc 100644 --- a/turbo.json +++ b/turbo.json @@ -30,6 +30,9 @@ }, "start": { "cache": false + }, + "types": { + "outputs": ["dist/**/*.d.ts"] } } } From 6e6db0773bd4b826a26d48bbac335826baa82ff8 Mon Sep 17 00:00:00 2001 From: Luis Alvarez D Date: Tue, 8 Mar 2022 23:24:23 -0500 Subject: [PATCH 09/11] Updated deploy button (#705) --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 01c66337a..d93068f06 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-description=An%20all-in-one%20starter%20kit%20for%20high-performance%20e-commerce%20sites.&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&integration-ids=oac_MuWZiE4jtmQ2ejZQaQ7ncuDT) +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-description=An%20all-in-one%20starter%20kit%20for%20high-performance%20e-commerce%20sites.&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&integration-ids=oac_MuWZiE4jtmQ2ejZQaQ7ncuDT,oac_9HSKtXld74NG0srzdxSiBGty&skippable-integrations=1&root-directory=site&build-command=cd%20..%20%26%26%20yarn%20build) # Next.js Commerce @@ -176,11 +176,11 @@ Error: Cannot find module '/Users/dom/work/vercel/commerce/node_modules/@vercel/ error Command failed with exit code 1. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. ``` - + The error usually occurs when running yarn dev inside of the `/site/` folder after installing a fresh repository. In order to fix this, run `yarn dev` in the monorepo root folder first. - + > Using `yarn dev` from the root is recommended for developing, which will run watch mode on all packages. + - From 172deeee86e30dc6fad48970adb7a7b7bff4117f Mon Sep 17 00:00:00 2001 From: Bel Date: Wed, 16 Mar 2022 12:05:58 +0100 Subject: [PATCH 10/11] Fixes & Updates (#704) * Adding Dropdown Component * Styling Issues * Wishlist Fix * Fixes for Wishlist View * Hearts now work again * Rollback ts * Removing extra config to disable BigCommerce * Fixes for Wishlist View * Remove transition/animation for mobile * New Updates. * New Updates. * Dropdown fix * Polish * export * export * revert tsconfig Co-authored-by: Luis Alvarez D. Co-authored-by: Dom Sip Co-authored-by: Luis Alvarez D. --- .../src/api/endpoints/wishlist/add-item.ts | 74 ++-- packages/bigcommerce/src/api/index.ts | 4 +- .../api/operations/get-customer-wishlist.ts | 1 + .../bigcommerce/src/wishlist/use-wishlist.tsx | 8 +- site/assets/base.css | 25 +- site/commerce.config.json | 6 - site/components/common/Layout/Layout.tsx | 66 ++-- site/components/common/Navbar/Navbar.tsx | 2 +- .../common/SidebarLayout/SidebarLayout.tsx | 7 +- .../CustomerMenuContent.module.css | 31 ++ .../CustomerMenuContent.tsx | 86 +++++ .../UserNav/CustomerMenuContent/index.ts | 1 + .../common/UserNav/DropdownMenu.module.css | 26 -- .../common/UserNav/DropdownMenu.tsx | 125 ------- .../MenuSidebarView.module.css | 4 +- .../MenuSidebarView/MenuSidebarView.tsx | 27 +- .../common/UserNav/MenuSidebarView/index.ts | 3 +- .../common/UserNav/UserNav.module.css | 40 ++- site/components/common/UserNav/UserNav.tsx | 76 ++-- site/components/common/UserNav/index.ts | 2 + site/components/icons/index.ts | 11 +- site/components/ui/Container/Container.tsx | 4 +- .../ui/Dropdown/Dropdown.module.css | 32 ++ site/components/ui/Dropdown/Dropdown.tsx | 22 ++ site/components/ui/Sidebar/Sidebar.tsx | 7 +- site/components/ui/index.ts | 1 + .../WishlistButton/WishlistButton.tsx | 4 +- .../WishlistCard/WishlistCard.module.css | 47 ++- .../wishlist/WishlistCard/WishlistCard.tsx | 68 ++-- site/package.json | 1 + site/pages/cart.tsx | 12 +- site/pages/orders.tsx | 2 +- site/pages/profile.tsx | 24 +- site/pages/wishlist.tsx | 8 +- yarn.lock | 327 +++++++++++++++++- 35 files changed, 780 insertions(+), 404 deletions(-) create mode 100644 site/components/common/UserNav/CustomerMenuContent/CustomerMenuContent.module.css create mode 100644 site/components/common/UserNav/CustomerMenuContent/CustomerMenuContent.tsx create mode 100644 site/components/common/UserNav/CustomerMenuContent/index.ts delete mode 100644 site/components/common/UserNav/DropdownMenu.module.css delete mode 100644 site/components/common/UserNav/DropdownMenu.tsx create mode 100644 site/components/ui/Dropdown/Dropdown.module.css create mode 100644 site/components/ui/Dropdown/Dropdown.tsx diff --git a/packages/bigcommerce/src/api/endpoints/wishlist/add-item.ts b/packages/bigcommerce/src/api/endpoints/wishlist/add-item.ts index bf449cb11..734a64402 100644 --- a/packages/bigcommerce/src/api/endpoints/wishlist/add-item.ts +++ b/packages/bigcommerce/src/api/endpoints/wishlist/add-item.ts @@ -3,7 +3,6 @@ import { parseWishlistItem } from '../../utils/parse-item' import getCustomerId from '../../utils/get-customer-id' import type { WishlistEndpoint } from '.' -// Return wishlist info const addItem: WishlistEndpoint['handlers']['addItem'] = async ({ res, body: { customerToken, item }, @@ -17,41 +16,52 @@ const addItem: WishlistEndpoint['handlers']['addItem'] = async ({ }) } - const customerId = - customerToken && (await getCustomerId({ customerToken, config })) + try { + const customerId = + customerToken && (await getCustomerId({ customerToken, config })) - if (!customerId) { - return res.status(400).json({ + if (!customerId) { + throw new Error('Invalid request. No CustomerId') + } + + let { wishlist } = await commerce.getCustomerWishlist({ + variables: { customerId }, + config, + }) + + if (!wishlist) { + // If user has no wishlist, then let's create one with new item + const { data } = await config.storeApiFetch('/v3/wishlists', { + method: 'POST', + body: JSON.stringify({ + name: 'Next.js Commerce Wishlist', + is_public: false, + customer_id: Number(customerId), + items: [parseWishlistItem(item)], + }), + }) + return res.status(200).json(data) + } + + // Existing Wishlist, let's add Item to Wishlist + const { data } = await config.storeApiFetch( + `/v3/wishlists/${wishlist.id}/items`, + { + method: 'POST', + body: JSON.stringify({ + items: [parseWishlistItem(item)], + }), + } + ) + + // Returns Wishlist + return res.status(200).json(data) + } catch (err: any) { + res.status(500).json({ data: null, - errors: [{ message: 'Invalid request' }], + errors: [{ message: err.message }], }) } - - const { wishlist } = await commerce.getCustomerWishlist({ - variables: { customerId }, - config, - }) - const options = { - method: 'POST', - body: JSON.stringify( - wishlist - ? { - items: [parseWishlistItem(item)], - } - : { - name: 'Wishlist', - customer_id: customerId, - items: [parseWishlistItem(item)], - is_public: false, - } - ), - } - - const { data } = wishlist - ? await config.storeApiFetch(`/v3/wishlists/${wishlist.id}/items`, options) - : await config.storeApiFetch('/v3/wishlists', options) - - res.status(200).json({ data }) } export default addItem diff --git a/packages/bigcommerce/src/api/index.ts b/packages/bigcommerce/src/api/index.ts index b4999642b..bd5fcb3b7 100644 --- a/packages/bigcommerce/src/api/index.ts +++ b/packages/bigcommerce/src/api/index.ts @@ -38,9 +38,9 @@ export interface BigcommerceConfig extends CommerceAPIConfig { storeApiFetch(endpoint: string, options?: RequestInit): Promise } -const API_URL = process.env.BIGCOMMERCE_STOREFRONT_API_URL +const API_URL = process.env.BIGCOMMERCE_STOREFRONT_API_URL // GraphAPI const API_TOKEN = process.env.BIGCOMMERCE_STOREFRONT_API_TOKEN -const STORE_API_URL = process.env.BIGCOMMERCE_STORE_API_URL +const STORE_API_URL = process.env.BIGCOMMERCE_STORE_API_URL // REST API const STORE_API_TOKEN = process.env.BIGCOMMERCE_STORE_API_TOKEN const STORE_API_CLIENT_ID = process.env.BIGCOMMERCE_STORE_API_CLIENT_ID const STORE_CHANNEL_ID = process.env.BIGCOMMERCE_CHANNEL_ID diff --git a/packages/bigcommerce/src/api/operations/get-customer-wishlist.ts b/packages/bigcommerce/src/api/operations/get-customer-wishlist.ts index dc0dd0d9a..25e2157e1 100644 --- a/packages/bigcommerce/src/api/operations/get-customer-wishlist.ts +++ b/packages/bigcommerce/src/api/operations/get-customer-wishlist.ts @@ -44,6 +44,7 @@ export default function getCustomerWishlistOperation({ const { data = [] } = await config.storeApiFetch< RecursivePartial<{ data: Wishlist[] }> >(`/v3/wishlists?customer_id=${variables.customerId}`) + const wishlist = data[0] if (includeProducts && wishlist?.items?.length) { diff --git a/packages/bigcommerce/src/wishlist/use-wishlist.tsx b/packages/bigcommerce/src/wishlist/use-wishlist.tsx index e77d6885b..7882233f5 100644 --- a/packages/bigcommerce/src/wishlist/use-wishlist.tsx +++ b/packages/bigcommerce/src/wishlist/use-wishlist.tsx @@ -1,11 +1,13 @@ import { useMemo } from 'react' import { SWRHook } from '@vercel/commerce/utils/types' -import useWishlist, { UseWishlist } from '@vercel/commerce/wishlist/use-wishlist' -import type { GetWishlistHook } from '../types/wishlist' +import useWishlist, { + UseWishlist, +} from '@vercel/commerce/wishlist/use-wishlist' import useCustomer from '../customer/use-customer' -export default useWishlist as UseWishlist +import type { GetWishlistHook } from '../types/wishlist' +export default useWishlist as UseWishlist export const handler: SWRHook = { fetchOptions: { url: '/api/wishlist', diff --git a/site/assets/base.css b/site/assets/base.css index 05a234a73..37e14196c 100644 --- a/site/assets/base.css +++ b/site/assets/base.css @@ -4,11 +4,9 @@ --secondary: #000000; --secondary-2: #111; --selection: var(--cyan); - --text-base: #000000; --text-primary: #000000; --text-secondary: white; - --hover: rgba(0, 0, 0, 0.075); --hover-1: rgba(0, 0, 0, 0.15); --hover-2: rgba(0, 0, 0, 0.25); @@ -17,15 +15,11 @@ --red: #da3c3c; --purple: #f81ce5; --blue: #0070f3; - --pink: #ff0080; --pink-light: #ff379c; - --magenta: #eb367f; - --violet: #7928ca; --violet-dark: #4c2889; - --accent-0: #fff; --accent-1: #fafafa; --accent-2: #eaeaea; @@ -36,7 +30,6 @@ --accent-7: #333333; --accent-8: #111111; --accent-9: #000; - --font-sans: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', sans-serif; } @@ -50,11 +43,9 @@ --hover-1: rgba(255, 255, 255, 0.15); --hover-2: rgba(255, 255, 255, 0.25); --selection: var(--purple); - --text-base: white; --text-primary: white; --text-secondary: black; - --accent-9: #fff; --accent-8: #fafafa; --accent-7: #eaeaea; @@ -73,17 +64,11 @@ box-sizing: inherit; } -html { +html, +body { height: 100%; box-sizing: border-box; touch-action: manipulation; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -html, -body { font-family: var(--font-sans); text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; @@ -104,15 +89,15 @@ a { } .animated { - -webkit-animation-duration: 1s; animation-duration: 1s; - -webkit-animation-fill-mode: both; animation-fill-mode: both; + -webkit-animation-duration: 1s; + -webkit-animation-fill-mode: both; } .fadeIn { - -webkit-animation-name: fadeIn; animation-name: fadeIn; + -webkit-animation-name: fadeIn; } @-webkit-keyframes fadeIn { diff --git a/site/commerce.config.json b/site/commerce.config.json index dd43ae077..ad72b58de 100644 --- a/site/commerce.config.json +++ b/site/commerce.config.json @@ -5,11 +5,5 @@ "wishlist": false, "customerAuth": false, "customCheckout": false - }, - "@vercel/commerce-bigcommerce": { - "features": { - "wishlist": false, - "customerAuth": false - } } } diff --git a/site/components/common/Layout/Layout.tsx b/site/components/common/Layout/Layout.tsx index 5c936a09f..6dda880e4 100644 --- a/site/components/common/Layout/Layout.tsx +++ b/site/components/common/Layout/Layout.tsx @@ -1,12 +1,11 @@ import cn from 'clsx' -import React, { FC } from 'react' +import s from './Layout.module.css' import dynamic from 'next/dynamic' import { useRouter } from 'next/router' import { CommerceProvider } from '@framework' +import LoginView from '@components/auth/LoginView' import { useUI } from '@components/ui/context' -import type { Page } from '@commerce/types/page' import { Navbar, Footer } from '@components/common' -import type { Category } from '@commerce/types/site' import ShippingView from '@components/checkout/ShippingView' import CartSidebarView from '@components/cart/CartSidebarView' import { useAcceptCookies } from '@lib/hooks/useAcceptCookies' @@ -14,10 +13,10 @@ import { Sidebar, Button, LoadingDots } from '@components/ui' import PaymentMethodView from '@components/checkout/PaymentMethodView' import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView' import { CheckoutProvider } from '@components/checkout/context' -import MenuSidebarView, { Link } from '../UserNav/MenuSidebarView' - -import LoginView from '@components/auth/LoginView' -import s from './Layout.module.css' +import { MenuSidebarView } from '@components/common/UserNav' +import type { Page } from '@commerce/types/page' +import type { Category } from '@commerce/types/site' +import type { Link as LinkProps } from '../UserNav/MenuSidebarView' const Loading = () => (
@@ -29,35 +28,26 @@ const dynamicProps = { loading: Loading, } -const SignUpView = dynamic( - () => import('@components/auth/SignUpView'), - { - ...dynamicProps - } -) +const SignUpView = dynamic(() => import('@components/auth/SignUpView'), { + ...dynamicProps, +}) const ForgotPassword = dynamic( () => import('@components/auth/ForgotPassword'), - { - ...dynamicProps - } -) - -const FeatureBar = dynamic( - () => import('@components/common/FeatureBar'), - { - ...dynamicProps - } -) - -const Modal = dynamic( - () => import('@components/ui/Modal'), { ...dynamicProps, - ssr: false } ) +const FeatureBar = dynamic(() => import('@components/common/FeatureBar'), { + ...dynamicProps, +}) + +const Modal = dynamic(() => import('@components/ui/Modal'), { + ...dynamicProps, + ssr: false, +}) + interface Props { pageProps: { pages?: Page[] @@ -65,7 +55,7 @@ interface Props { } } -const ModalView: FC<{ modalView: string; closeModal(): any }> = ({ +const ModalView: React.FC<{ modalView: string; closeModal(): any }> = ({ modalView, closeModal, }) => { @@ -78,41 +68,41 @@ const ModalView: FC<{ modalView: string; closeModal(): any }> = ({ ) } -const ModalUI: FC = () => { +const ModalUI: React.FC = () => { const { displayModal, closeModal, modalView } = useUI() return displayModal ? ( ) : null } -const SidebarView: FC<{ +const SidebarView: React.FC<{ sidebarView: string closeSidebar(): any - links: Link[] + links: LinkProps[] }> = ({ sidebarView, closeSidebar, links }) => { return ( - {sidebarView === 'MOBILEMENU_VIEW' && } {sidebarView === 'CART_VIEW' && } - {sidebarView === 'CHECKOUT_VIEW' && } - {sidebarView === 'PAYMENT_VIEW' && } {sidebarView === 'SHIPPING_VIEW' && } + {sidebarView === 'PAYMENT_VIEW' && } + {sidebarView === 'CHECKOUT_VIEW' && } + {sidebarView === 'MOBILE_MENU_VIEW' && } ) } -const SidebarUI: FC<{ links: any }> = ({ links }) => { +const SidebarUI: React.FC<{ links: LinkProps[] }> = ({ links }) => { const { displaySidebar, closeSidebar, sidebarView } = useUI() return displaySidebar ? ( ) : null } -const Layout: FC = ({ +const Layout: React.FC = ({ children, pageProps: { categories = [], ...pageProps }, }) => { diff --git a/site/components/common/Navbar/Navbar.tsx b/site/components/common/Navbar/Navbar.tsx index bc1969a91..9286ef160 100644 --- a/site/components/common/Navbar/Navbar.tsx +++ b/site/components/common/Navbar/Navbar.tsx @@ -16,7 +16,7 @@ interface NavbarProps { const Navbar: FC = ({ links }) => ( - +
diff --git a/site/components/common/SidebarLayout/SidebarLayout.tsx b/site/components/common/SidebarLayout/SidebarLayout.tsx index 407a938ea..b291e8a68 100644 --- a/site/components/common/SidebarLayout/SidebarLayout.tsx +++ b/site/components/common/SidebarLayout/SidebarLayout.tsx @@ -12,8 +12,8 @@ type ComponentProps = { className?: string } & ( const SidebarLayout: FC = ({ children, className, - handleClose, handleBack, + handleClose, }) => { return (
@@ -38,9 +38,8 @@ const SidebarLayout: FC = ({ Back )} - - - + +
{children}
diff --git a/site/components/common/UserNav/CustomerMenuContent/CustomerMenuContent.module.css b/site/components/common/UserNav/CustomerMenuContent/CustomerMenuContent.module.css new file mode 100644 index 000000000..93a183a2b --- /dev/null +++ b/site/components/common/UserNav/CustomerMenuContent/CustomerMenuContent.module.css @@ -0,0 +1,31 @@ +.root { + @apply inset-0 fixed; + left: 72px; + z-index: 10; + height: 100vh; + min-width: 100vw; + transition: none; +} + +@media screen(lg) { + .root { + @apply static; + min-width: inherit; + height: inherit; + } +} + +.link { + @apply text-primary flex cursor-pointer px-6 py-3 + transition ease-in-out duration-150 leading-6 + font-medium items-center capitalize w-full box-border + outline-0; +} + +.link:hover { + @apply bg-accent-1 outline-none; +} + +.link.active { + @apply font-bold bg-accent-2; +} diff --git a/site/components/common/UserNav/CustomerMenuContent/CustomerMenuContent.tsx b/site/components/common/UserNav/CustomerMenuContent/CustomerMenuContent.tsx new file mode 100644 index 000000000..992d17178 --- /dev/null +++ b/site/components/common/UserNav/CustomerMenuContent/CustomerMenuContent.tsx @@ -0,0 +1,86 @@ +import cn from 'clsx' +import { useTheme } from 'next-themes' +import { useRouter } from 'next/router' +import { Moon, Sun } from '@components/icons' +import s from './CustomerMenuContent.module.css' +import useLogout from '@framework/auth/use-logout' +import { + DropdownContent, + DropdownMenuItem, +} from '@components/ui/Dropdown/Dropdown' + +const LINKS = [ + { + name: 'My Orders', + href: '/orders', + }, + { + name: 'My Profile', + href: '/profile', + }, + { + name: 'My Cart', + href: '/cart', + }, +] + +export default function CustomerMenuContent() { + const router = useRouter() + const logout = useLogout() + const { pathname } = useRouter() + const { theme, setTheme } = useTheme() + + function handleClick(_: React.MouseEvent, href: string) { + router.push(href) + } + + return ( + + {LINKS.map(({ name, href }) => ( + + handleClick(e, href)} + > + {name} + + + ))} + + { + setTheme(theme === 'dark' ? 'light' : 'dark') + }} + > +
+ Theme: {theme}{' '} +
+
+ {theme == 'dark' ? ( + + ) : ( + + )} +
+
+
+ + logout()} + > + Logout + + +
+ ) +} diff --git a/site/components/common/UserNav/CustomerMenuContent/index.ts b/site/components/common/UserNav/CustomerMenuContent/index.ts new file mode 100644 index 000000000..b465e81d6 --- /dev/null +++ b/site/components/common/UserNav/CustomerMenuContent/index.ts @@ -0,0 +1 @@ +export { default } from './CustomerMenuContent' diff --git a/site/components/common/UserNav/DropdownMenu.module.css b/site/components/common/UserNav/DropdownMenu.module.css deleted file mode 100644 index 8c4d9eb98..000000000 --- a/site/components/common/UserNav/DropdownMenu.module.css +++ /dev/null @@ -1,26 +0,0 @@ -@screen lg { - .dropdownMenu { - @apply absolute top-10 border border-accent-1 shadow-lg w-56 h-auto; - } -} - -.dropdownMenu { - @apply fixed right-0 mt-2 origin-top-right outline-none bg-primary z-40 w-full h-full; -} - -.link { - @apply text-primary flex cursor-pointer px-6 py-3 flex transition ease-in-out duration-150 leading-6 font-medium items-center; - text-transform: capitalize; -} - -.link:hover { - @apply bg-accent-1; -} - -.link.active { - @apply font-bold bg-accent-2; -} - -.off { - @apply hidden; -} diff --git a/site/components/common/UserNav/DropdownMenu.tsx b/site/components/common/UserNav/DropdownMenu.tsx deleted file mode 100644 index 9a73003dc..000000000 --- a/site/components/common/UserNav/DropdownMenu.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import cn from 'clsx' -import Link from 'next/link' -import { FC, useRef, useState, useEffect } from 'react' -import { useTheme } from 'next-themes' -import { useRouter } from 'next/router' -import s from './DropdownMenu.module.css' -import { Avatar } from '@components/common' -import { Moon, Sun } from '@components/icons' -import { useUI } from '@components/ui/context' -import ClickOutside from '@lib/click-outside' -import useLogout from '@framework/auth/use-logout' - -import { - disableBodyScroll, - enableBodyScroll, - clearAllBodyScrollLocks, -} from 'body-scroll-lock' - -interface DropdownMenuProps { - open?: boolean -} - -const LINKS = [ - { - name: 'My Orders', - href: '/orders', - }, - { - name: 'My Profile', - href: '/profile', - }, - { - name: 'My Cart', - href: '/cart', - }, -] - -const DropdownMenu: FC = ({ open = false }) => { - const logout = useLogout() - const { pathname } = useRouter() - const { theme, setTheme } = useTheme() - const [display, setDisplay] = useState(false) - const { closeSidebarIfPresent } = useUI() - const ref = useRef() as React.MutableRefObject - - useEffect(() => { - if (ref.current) { - if (display) { - disableBodyScroll(ref.current) - } else { - enableBodyScroll(ref.current) - } - } - return () => { - clearAllBodyScrollLocks() - } - }, [display]) - - return ( - setDisplay(false)}> - - - ) -} - -export default DropdownMenu diff --git a/site/components/common/UserNav/MenuSidebarView/MenuSidebarView.module.css b/site/components/common/UserNav/MenuSidebarView/MenuSidebarView.module.css index 26469d6b6..6c05b013e 100644 --- a/site/components/common/UserNav/MenuSidebarView/MenuSidebarView.module.css +++ b/site/components/common/UserNav/MenuSidebarView/MenuSidebarView.module.css @@ -3,5 +3,5 @@ } .item { - @apply text-2xl font-bold; -} \ No newline at end of file + @apply text-xl font-bold py-2; +} diff --git a/site/components/common/UserNav/MenuSidebarView/MenuSidebarView.tsx b/site/components/common/UserNav/MenuSidebarView/MenuSidebarView.tsx index 334b8de9e..a4ed5b51b 100644 --- a/site/components/common/UserNav/MenuSidebarView/MenuSidebarView.tsx +++ b/site/components/common/UserNav/MenuSidebarView/MenuSidebarView.tsx @@ -1,31 +1,32 @@ import Link from 'next/link' import s from './MenuSidebarView.module.css' -import { FC } from 'react' import { useUI } from '@components/ui/context' import SidebarLayout from '@components/common/SidebarLayout' -import { Link as LinkProps} from '.' +import type { Link as LinkProps } from './index' - -interface MenuProps { +export default function MenuSidebarView({ + links = [], +}: { links?: LinkProps[] -} - -const MenuSidebarView: FC = (props) => { +}) { const { closeSidebar } = useUI() - const handleClose = () => closeSidebar() return ( - + closeSidebar()}>