From 4171df649287c0584dee2716a3d012475a97f413 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Fri, 6 Oct 2023 12:16:14 +0200 Subject: [PATCH 01/47] feat(GCOM-535) added @graphcommerce/magento-recently-viewed-products to store recently viewed products in localstorage --- examples/magento-graphcms/package.json | 1 + .../CHANGELOG.md | 1 + .../README.md | 10 +++ .../graphql/RecentlyViewedProducts.graphql | 11 +++ .../graphql/RecentlyViewedProducts.graphqls | 13 +++ .../hooks/useRecentlyViewedProducts.tsx | 34 ++++++++ .../hooks/useRecentlyViewedSkus.tsx | 19 +++++ .../magento-recently-viewed-products/index.ts | 1 + .../package.json | 35 ++++++++ .../plugins/SetRecentlyViewedProducts.tsx | 85 +++++++++++++++++++ 10 files changed, 210 insertions(+) create mode 100644 packages/magento-recently-viewed-products/CHANGELOG.md create mode 100644 packages/magento-recently-viewed-products/README.md create mode 100644 packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphql create mode 100644 packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphqls create mode 100644 packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx create mode 100644 packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx create mode 100644 packages/magento-recently-viewed-products/index.ts create mode 100644 packages/magento-recently-viewed-products/package.json create mode 100644 packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx diff --git a/examples/magento-graphcms/package.json b/examples/magento-graphcms/package.json index d5d1496051..10374d255d 100644 --- a/examples/magento-graphcms/package.json +++ b/examples/magento-graphcms/package.json @@ -59,6 +59,7 @@ "@graphcommerce/magento-product-grouped": "7.1.0-canary.30", "@graphcommerce/magento-product-simple": "7.1.0-canary.30", "@graphcommerce/magento-product-virtual": "7.1.0-canary.30", + "@graphcommerce/magento-recently-viewed-products": "7.1.0-canary.30", "@graphcommerce/magento-review": "7.1.0-canary.30", "@graphcommerce/magento-search": "7.1.0-canary.30", "@graphcommerce/magento-store": "7.1.0-canary.30", diff --git a/packages/magento-recently-viewed-products/CHANGELOG.md b/packages/magento-recently-viewed-products/CHANGELOG.md new file mode 100644 index 0000000000..420e6f23d0 --- /dev/null +++ b/packages/magento-recently-viewed-products/CHANGELOG.md @@ -0,0 +1 @@ +# Change Log diff --git a/packages/magento-recently-viewed-products/README.md b/packages/magento-recently-viewed-products/README.md new file mode 100644 index 0000000000..07e06c0a0a --- /dev/null +++ b/packages/magento-recently-viewed-products/README.md @@ -0,0 +1,10 @@ +# @graphcommerce/magento-recently-viewed-products + +When visiting a product page, the product SKU is added to a list of recently +viewed products, stored in the users localStorage. + +## Configuration + +When `configurableVariantForSimple` is enabled in `graphcommerce.config.js`, +fully configured configurable products will be shown as the selected variant in +recently viewed products. diff --git a/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphql b/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphql new file mode 100644 index 0000000000..6433f2b12d --- /dev/null +++ b/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphql @@ -0,0 +1,11 @@ +query RecentlyViewedProducts { + recentlyViewedProducts @client { + __typename + items { + __typename + sku + parentSku + time + } + } +} diff --git a/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphqls b/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphqls new file mode 100644 index 0000000000..b6cec587cc --- /dev/null +++ b/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphqls @@ -0,0 +1,13 @@ +extend type Query { + recentlyViewedProducts: RecentlyViewedProducts +} + +type RecentlyViewedProducts { + items: [RecentlyViewedProduct!]! +} + +type RecentlyViewedProduct { + sku: String! + parentSku: String! + time: Int! +} diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx new file mode 100644 index 0000000000..75dd5d3b5b --- /dev/null +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx @@ -0,0 +1,34 @@ +import { useQuery } from '@graphcommerce/graphql' +import { ProductListDocument } from '@graphcommerce/magento-product' +import { useRecentlyViewedSkus } from './useRecentlyViewedSkus' + +export function useRecentlyViewedProducts({ exclude }: { exclude?: string[] } = {}) { + const { skus, loading } = useRecentlyViewedSkus({ exclude }) + const getTimeBySku = (sku: string) => skus.find((s) => s.sku === sku)?.time || 0 + + const { + loading: loadingProducts, + data, + previousData, + } = useQuery(ProductListDocument, { + variables: { + filters: { + sku: { + in: skus.map((p) => p.sku), + }, + }, + }, + skip: loading || !skus.length, + }) + + let products = data?.products?.items || previousData?.products?.items || [] + // Sort products based on the time they were viewed. Last viewed item should be the first item in the array + products = [...products].sort((a, b) => + getTimeBySku(b?.sku || '') > getTimeBySku(a?.sku || '') ? 1 : -1, + ) + + return { + products, + loading: loading || loadingProducts, + } +} diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx new file mode 100644 index 0000000000..0d5a043f77 --- /dev/null +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx @@ -0,0 +1,19 @@ +import { useQuery } from '@graphcommerce/graphql' +import { RecentlyViewedProductsDocument } from '../graphql/RecentlyViewedProducts.gql' + +export function useRecentlyViewedSkus({ exclude }: { exclude?: string[] } = {}) { + const { data, loading, previousData } = useQuery(RecentlyViewedProductsDocument) + let skus = (loading ? previousData : data)?.recentlyViewedProducts?.items || [] + + // Filter out excluded products (current product page) + if (exclude) + skus = skus.filter( + (item) => + item?.sku && + !exclude.includes(item.sku) && + item?.parentSku && + !exclude.includes(item.parentSku), + ) + + return { skus, loading } +} diff --git a/packages/magento-recently-viewed-products/index.ts b/packages/magento-recently-viewed-products/index.ts new file mode 100644 index 0000000000..cb64ac1b52 --- /dev/null +++ b/packages/magento-recently-viewed-products/index.ts @@ -0,0 +1 @@ +export * from './components' diff --git a/packages/magento-recently-viewed-products/package.json b/packages/magento-recently-viewed-products/package.json new file mode 100644 index 0000000000..6ead6d56cc --- /dev/null +++ b/packages/magento-recently-viewed-products/package.json @@ -0,0 +1,35 @@ +{ + "name": "@graphcommerce/magento-recently-viewed-products", + "homepage": "https://www.graphcommerce.org/", + "repository": "github:graphcommerce-org/graphcommerce", + "version": "7.0.0", + "sideEffects": false, + "prettier": "@graphcommerce/prettier-config-pwa", + "eslintConfig": { + "extends": "@graphcommerce/eslint-config-pwa", + "parserOptions": { + "project": "./tsconfig.json" + } + }, + "dependencies": { + "@graphcommerce/graphql": "7.0.2-canary.4", + "@graphcommerce/graphql-mesh": "7.0.2-canary.4", + "@graphcommerce/magento-cart": "7.0.2-canary.4", + "@graphcommerce/magento-product-configurable": "7.0.2-canary.4", + "@graphcommerce/magento-product": "7.0.2-canary.4", + "@graphcommerce/next-config": "7.0.2-canary.4", + "@graphcommerce/next-ui": "7.0.2-canary.4" + }, + "devDependencies": { + "@graphcommerce/eslint-config-pwa": "7.0.2-canary.4", + "@graphcommerce/next-config": "^7.0.2-canary.4", + "@graphcommerce/prettier-config-pwa": "7.0.2-canary.4", + "@graphcommerce/typescript-config-pwa": "7.0.2-canary.4" + }, + "peerDependencies": { + "@mui/material": "^5.10.16", + "next": "^13.2.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } +} diff --git a/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx new file mode 100644 index 0000000000..9e98997e68 --- /dev/null +++ b/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx @@ -0,0 +1,85 @@ +import { useApolloClient } from '@graphcommerce/graphql' +import { + type AddToCartItemSelector, + type ProductPageMeta, + ProductPageMetaFragment, +} from '@graphcommerce/magento-product' +import { useConfigurableSelectedVariant } from '@graphcommerce/magento-product-configurable/hooks' +import type { ReactPlugin } from '@graphcommerce/next-config' +import { RecentlyViewedProductsDocument } from '../graphql/RecentlyViewedProducts.gql' +import { useRecentlyViewedSkus } from '../hooks/useRecentlyViewedSkus' + +export const component = 'ProductPageMeta' +export const exported = '@graphcommerce/magento-product/components/ProductPageMeta/ProductPageMeta' + +type PluginType = ReactPlugin + +function ViewHandling(props: { product: ProductPageMetaFragment }) { + const { product } = props + const { cache } = useApolloClient() + const { skus: recentlyViewedSkus, loading } = useRecentlyViewedSkus() + const variant = useConfigurableSelectedVariant({ url_key: product?.url_key, index: 0 }) + + if (loading) { + return null + } + + const isValidVariant = + (variant?.url_rewrites ?? []).length > 0 && + variant?.url_key && + import.meta.graphCommerce.configurableVariantForSimple + + const parentSku = product.sku || '' + const sku = (isValidVariant ? variant.sku : product.sku) || '' + + const parentSkuAlreadySet = recentlyViewedSkus.some( + (p) => p.sku === parentSku || p.parentSku === parentSku, + ) + const skuAlreadySet = recentlyViewedSkus.some((p) => p.sku === sku) + const skuIsLastItem = + [...recentlyViewedSkus].sort((a, b) => (a.time > b.time ? 1 : -1))[ + recentlyViewedSkus.length - 1 + ]?.sku === sku + + if (skuAlreadySet && skuIsLastItem) { + return null + } + + // Current SKU not yet found in recently viewed or SKU is found, but not set as last visited - add to list/update in list + cache.writeQuery({ + query: RecentlyViewedProductsDocument, + broadcast: true, + data: { + recentlyViewedProducts: { + __typename: 'RecentlyViewedProducts', + items: [ + // If SKU already exists in recently viewed products, replace it, else add it + ...(skuIsLastItem || parentSkuAlreadySet + ? recentlyViewedSkus.filter((p) => p.sku !== parentSku && p.parentSku !== parentSku) + : recentlyViewedSkus), + { + __typename: 'RecentlyViewedProduct', + parentSku, + sku, + time: Date.now(), + }, + ], + }, + }, + }) + + return null +} + +const SetRecentlyViewedProducts: PluginType = (props) => { + const { Prev, product } = props + + return ( + <> + + + + ) +} + +export const Plugin = SetRecentlyViewedProducts From 76878148da6ad05fbc3ae7b1c2267f718802e5cd Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Fri, 6 Oct 2023 16:36:23 +0200 Subject: [PATCH 02/47] feat(GCOM-535) fix unnecessary rerenders by adding product to recently viewed when navigating away from page instead of on page load Also removed unnecessary time prop --- .../graphql/RecentlyViewedProducts.graphql | 1 - .../graphql/RecentlyViewedProducts.graphqls | 3 +- .../plugins/SetRecentlyViewedProducts.tsx | 83 +++++++++---------- 3 files changed, 40 insertions(+), 47 deletions(-) diff --git a/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphql b/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphql index 6433f2b12d..de87ed321d 100644 --- a/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphql +++ b/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphql @@ -5,7 +5,6 @@ query RecentlyViewedProducts { __typename sku parentSku - time } } } diff --git a/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphqls b/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphqls index b6cec587cc..2c07f8aece 100644 --- a/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphqls +++ b/packages/magento-recently-viewed-products/graphql/RecentlyViewedProducts.graphqls @@ -8,6 +8,5 @@ type RecentlyViewedProducts { type RecentlyViewedProduct { sku: String! - parentSku: String! - time: Int! + parentSku: String } diff --git a/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx index 9e98997e68..7f598fdbef 100644 --- a/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx @@ -6,8 +6,10 @@ import { } from '@graphcommerce/magento-product' import { useConfigurableSelectedVariant } from '@graphcommerce/magento-product-configurable/hooks' import type { ReactPlugin } from '@graphcommerce/next-config' +import { useEventCallback } from '@mui/material' +import { useRouter } from 'next/router' +import { useEffect } from 'react' import { RecentlyViewedProductsDocument } from '../graphql/RecentlyViewedProducts.gql' -import { useRecentlyViewedSkus } from '../hooks/useRecentlyViewedSkus' export const component = 'ProductPageMeta' export const exported = '@graphcommerce/magento-product/components/ProductPageMeta/ProductPageMeta' @@ -16,58 +18,51 @@ type PluginType = ReactPlugin function ViewHandling(props: { product: ProductPageMetaFragment }) { const { product } = props - const { cache } = useApolloClient() - const { skus: recentlyViewedSkus, loading } = useRecentlyViewedSkus() + const client = useApolloClient() const variant = useConfigurableSelectedVariant({ url_key: product?.url_key, index: 0 }) + const { events } = useRouter() - if (loading) { - return null - } + const registerView = useEventCallback(async () => { + const recentlyViewed = await client.query({ query: RecentlyViewedProductsDocument }) + const skus = recentlyViewed.data.recentlyViewedProducts?.items ?? [] - const isValidVariant = - (variant?.url_rewrites ?? []).length > 0 && - variant?.url_key && - import.meta.graphCommerce.configurableVariantForSimple + const isValidVariant = + (variant?.url_rewrites ?? []).length > 0 && + variant?.url_key && + import.meta.graphCommerce.configurableVariantForSimple - const parentSku = product.sku || '' - const sku = (isValidVariant ? variant.sku : product.sku) || '' + const parentSku = product.sku || '' + const sku = (isValidVariant ? variant.sku : product.sku) || '' - const parentSkuAlreadySet = recentlyViewedSkus.some( - (p) => p.sku === parentSku || p.parentSku === parentSku, - ) - const skuAlreadySet = recentlyViewedSkus.some((p) => p.sku === sku) - const skuIsLastItem = - [...recentlyViewedSkus].sort((a, b) => (a.time > b.time ? 1 : -1))[ - recentlyViewedSkus.length - 1 - ]?.sku === sku + const parentSkuAlreadySet = skus.some( + (p) => p.sku === product.sku || p.parentSku === product.sku, + ) + const skuAlreadySet = skus.some((p) => p.sku === sku) + const skuIsLastItem = skus[skus.length - 1].sku === sku + + if (skuAlreadySet && skuIsLastItem) return - if (skuAlreadySet && skuIsLastItem) { - return null - } + const items = [ + // If SKU already exists in recently viewed products, replace it, else add it + ...(skuIsLastItem || parentSkuAlreadySet + ? skus.filter((p) => p.sku !== parentSku && p.parentSku !== parentSku) + : skus), + { __typename: 'RecentlyViewedProduct' as const, parentSku, sku }, + ] - // Current SKU not yet found in recently viewed or SKU is found, but not set as last visited - add to list/update in list - cache.writeQuery({ - query: RecentlyViewedProductsDocument, - broadcast: true, - data: { - recentlyViewedProducts: { - __typename: 'RecentlyViewedProducts', - items: [ - // If SKU already exists in recently viewed products, replace it, else add it - ...(skuIsLastItem || parentSkuAlreadySet - ? recentlyViewedSkus.filter((p) => p.sku !== parentSku && p.parentSku !== parentSku) - : recentlyViewedSkus), - { - __typename: 'RecentlyViewedProduct', - parentSku, - sku, - time: Date.now(), - }, - ], - }, - }, + // Current SKU not yet found in recently viewed or SKU is found, but not set as last visited - add to list/update in list + client.writeQuery({ + query: RecentlyViewedProductsDocument, + broadcast: true, + data: { recentlyViewedProducts: { __typename: 'RecentlyViewedProducts', items } }, + }) }) + useEffect(() => { + events.on('routeChangeStart', registerView) + return () => events.off('routeChangeStart', registerView) + }, [events, registerView]) + return null } From 564178de99771ac3812cc174db496ff75941215b Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Fri, 6 Oct 2023 16:39:31 +0200 Subject: [PATCH 03/47] feat(GCOM-535) sort recently viewed products based on array order --- .../hooks/useRecentlyViewedProducts.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx index 75dd5d3b5b..548a031ee9 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx @@ -1,10 +1,10 @@ import { useQuery } from '@graphcommerce/graphql' import { ProductListDocument } from '@graphcommerce/magento-product' import { useRecentlyViewedSkus } from './useRecentlyViewedSkus' +import { nonNullable } from '@graphcommerce/next-ui' export function useRecentlyViewedProducts({ exclude }: { exclude?: string[] } = {}) { const { skus, loading } = useRecentlyViewedSkus({ exclude }) - const getTimeBySku = (sku: string) => skus.find((s) => s.sku === sku)?.time || 0 const { loading: loadingProducts, @@ -23,9 +23,7 @@ export function useRecentlyViewedProducts({ exclude }: { exclude?: string[] } = let products = data?.products?.items || previousData?.products?.items || [] // Sort products based on the time they were viewed. Last viewed item should be the first item in the array - products = [...products].sort((a, b) => - getTimeBySku(b?.sku || '') > getTimeBySku(a?.sku || '') ? 1 : -1, - ) + products = skus.map((sku) => products.find((p) => (p?.sku || '') === sku.sku)).filter(nonNullable) return { products, From 05123fe401356987dbc55f8e892cd9ebd79e7e62 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Fri, 6 Oct 2023 16:43:23 +0200 Subject: [PATCH 04/47] feat(GCOM-535) fix recently viewed products order + add item limit --- docs/framework/config.md | 4 ++++ .../magento-recently-viewed-products/Config.graphqls | 6 ++++++ .../plugins/SetRecentlyViewedProducts.tsx | 12 ++++++++---- packagesDev/next-config/dist/generated/config.js | 1 + packagesDev/next-config/src/generated/config.ts | 3 +++ 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 packages/magento-recently-viewed-products/Config.graphqls diff --git a/docs/framework/config.md b/docs/framework/config.md index f2a0c86f4c..8540a0ea1b 100644 --- a/docs/framework/config.md +++ b/docs/framework/config.md @@ -272,6 +272,10 @@ By default we route products to /p/[url] but you can change this to /product/[ur Default: '/p/' Example: '/product/' +#### `recentlyViewedProductsCount: Int` + +Number of recently viewed products to be stored in localStorage + #### `robotsAllow: Boolean` Allow the site to be indexed by search engines. diff --git a/packages/magento-recently-viewed-products/Config.graphqls b/packages/magento-recently-viewed-products/Config.graphqls new file mode 100644 index 0000000000..b28a4ba7ab --- /dev/null +++ b/packages/magento-recently-viewed-products/Config.graphqls @@ -0,0 +1,6 @@ +extend input GraphCommerceConfig { + """ + Number of recently viewed products to be stored in localStorage + """ + recentlyViewedProductsCount: Int +} diff --git a/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx index 7f598fdbef..33863de905 100644 --- a/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx @@ -42,15 +42,19 @@ function ViewHandling(props: { product: ProductPageMetaFragment }) { if (skuAlreadySet && skuIsLastItem) return - const items = [ - // If SKU already exists in recently viewed products, replace it, else add it + // If SKU already exists in recently viewed products, remove it, so we can re-add it as the first item of the array + const viewedSkus = [ ...(skuIsLastItem || parentSkuAlreadySet ? skus.filter((p) => p.sku !== parentSku && p.parentSku !== parentSku) : skus), - { __typename: 'RecentlyViewedProduct' as const, parentSku, sku }, ] - // Current SKU not yet found in recently viewed or SKU is found, but not set as last visited - add to list/update in list + // Limit array + const items = [ + { __typename: 'RecentlyViewedProduct' as const, parentSku, sku }, + ...viewedSkus, + ].splice(0, import.meta.graphCommerce.recentlyViewedProductsCount || 10) + client.writeQuery({ query: RecentlyViewedProductsDocument, broadcast: true, diff --git a/packagesDev/next-config/dist/generated/config.js b/packagesDev/next-config/dist/generated/config.js index 0bac37a935..9d598689ea 100644 --- a/packagesDev/next-config/dist/generated/config.js +++ b/packagesDev/next-config/dist/generated/config.js @@ -72,6 +72,7 @@ function GraphCommerceConfigSchema() { productFiltersLayout: ProductFiltersLayoutSchema.nullish(), productFiltersPro: _zod.z.boolean().nullish(), productRoute: _zod.z.string().nullish(), + recentlyViewedProductsCount: _zod.z.number().nullish(), robotsAllow: _zod.z.boolean().nullish(), storefront: _zod.z.array(GraphCommerceStorefrontConfigSchema()), wishlistHideForGuests: _zod.z.boolean().nullish(), diff --git a/packagesDev/next-config/src/generated/config.ts b/packagesDev/next-config/src/generated/config.ts index 4847b29743..a8a61836fb 100644 --- a/packagesDev/next-config/src/generated/config.ts +++ b/packagesDev/next-config/src/generated/config.ts @@ -277,6 +277,8 @@ export type GraphCommerceConfig = { * Example: '/product/' */ productRoute?: InputMaybe; + /** Number of recently viewed products to be stored in localStorage */ + recentlyViewedProductsCount?: InputMaybe; /** * Allow the site to be indexed by search engines. * If false, the robots.txt file will be set to disallow all. @@ -426,6 +428,7 @@ export function GraphCommerceConfigSchema(): z.ZodObject Date: Fri, 6 Oct 2023 16:46:03 +0200 Subject: [PATCH 05/47] Fixed import order --- .../hooks/useRecentlyViewedProducts.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx index 548a031ee9..129ffe865f 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx @@ -1,7 +1,7 @@ import { useQuery } from '@graphcommerce/graphql' import { ProductListDocument } from '@graphcommerce/magento-product' -import { useRecentlyViewedSkus } from './useRecentlyViewedSkus' import { nonNullable } from '@graphcommerce/next-ui' +import { useRecentlyViewedSkus } from './useRecentlyViewedSkus' export function useRecentlyViewedProducts({ exclude }: { exclude?: string[] } = {}) { const { skus, loading } = useRecentlyViewedSkus({ exclude }) From 727d1004dfcb7dddf6e35b6b157a34491bb05cc6 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 9 Oct 2023 11:13:39 +0200 Subject: [PATCH 06/47] Fixed ItemScroller className --- .changeset/fifty-impalas-hug.md | 5 +++++ packages/next-ui/FramerScroller/ItemScroller.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/fifty-impalas-hug.md diff --git a/.changeset/fifty-impalas-hug.md b/.changeset/fifty-impalas-hug.md new file mode 100644 index 0000000000..7ca2de1c39 --- /dev/null +++ b/.changeset/fifty-impalas-hug.md @@ -0,0 +1,5 @@ +--- +'@graphcommerce/next-ui': patch +--- + +Fixed ItemScroller component className. Changed from SidebarSlider to ItemScroller diff --git a/packages/next-ui/FramerScroller/ItemScroller.tsx b/packages/next-ui/FramerScroller/ItemScroller.tsx index d0ad9c91cf..02199bccd5 100644 --- a/packages/next-ui/FramerScroller/ItemScroller.tsx +++ b/packages/next-ui/FramerScroller/ItemScroller.tsx @@ -10,7 +10,7 @@ import { extendableComponent, responsiveVal } from '../Styles' import { useFabSize } from '../Theme' import { iconChevronLeft, iconChevronRight } from '../icons' -const { classes } = extendableComponent('SidebarSlider', [ +const { classes } = extendableComponent('ItemScroller', [ 'root', 'grid', 'sidebar', From 0d2cb22a58451d40102981263209aacb93016c76 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 9 Oct 2023 11:16:38 +0200 Subject: [PATCH 07/47] Removed unwanted space below ProductListItem images caused by line-height Images are now perfectly square as expected --- .changeset/odd-poets-greet.md | 5 +++++ .../components/ProductListItem/ProductListItem.tsx | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 .changeset/odd-poets-greet.md diff --git a/.changeset/odd-poets-greet.md b/.changeset/odd-poets-greet.md new file mode 100644 index 0000000000..092fc09adb --- /dev/null +++ b/.changeset/odd-poets-greet.md @@ -0,0 +1,5 @@ +--- +'@graphcommerce/magento-product': patch +--- + +Removed unwanted space below ProductListItem images caused by line-height. Images are now perfectly square as expected. diff --git a/packages/magento-product/components/ProductListItem/ProductListItem.tsx b/packages/magento-product/components/ProductListItem/ProductListItem.tsx index 065d765c44..21c39bc1d2 100644 --- a/packages/magento-product/components/ProductListItem/ProductListItem.tsx +++ b/packages/magento-product/components/ProductListItem/ProductListItem.tsx @@ -81,8 +81,8 @@ export function ProductListItem(props: ProductListItemProps) { onClick, } = props - const handleClick = useEventCallback((e: React.MouseEvent) => - onClick?.(e, props), + const handleClick = useEventCallback( + (e: React.MouseEvent) => onClick?.(e, props), ) const productLink = useProductLink(props) @@ -140,7 +140,11 @@ export function ProductListItem(props: ProductListItemProps) { alt={small_image.label ?? ''} className={classes.image} loading={loading} - sx={{ objectFit: 'contain', aspectRatio: `${aspectRatio[0] / aspectRatio[1]}` }} + sx={{ + objectFit: 'contain', + aspectRatio: `${aspectRatio[0] / aspectRatio[1]}`, + display: 'block', + }} /> ) : ( Date: Mon, 9 Oct 2023 11:31:47 +0200 Subject: [PATCH 08/47] feat(GCOM-535) added export for ItemScrollerProps --- packages/next-ui/FramerScroller/ItemScroller.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next-ui/FramerScroller/ItemScroller.tsx b/packages/next-ui/FramerScroller/ItemScroller.tsx index 02199bccd5..ce46fe7dff 100644 --- a/packages/next-ui/FramerScroller/ItemScroller.tsx +++ b/packages/next-ui/FramerScroller/ItemScroller.tsx @@ -21,13 +21,13 @@ const { classes } = extendableComponent('ItemScroller', [ 'centerRight', ] as const) -type SliderProps = { +export type ItemScrollerProps = { children: React.ReactNode sx?: SxProps buttonSize?: ScrollerButtonProps['size'] } & Pick -export function ItemScroller(props: SliderProps) { +export function ItemScroller(props: ItemScrollerProps) { const { children, sx, buttonSize = 'responsive', showButtons } = props const size = useFabSize(buttonSize) From 7664e45873142078eb6681fd1bb268db8035cb2e Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 9 Oct 2023 11:33:41 +0200 Subject: [PATCH 09/47] feat(GCOM-535) Added ProductScroller component with built-in skeleton loader --- .changeset/afraid-baboons-move.md | 5 + .../ProductListItems/ProductScroller.tsx | 138 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 .changeset/afraid-baboons-move.md create mode 100644 examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx diff --git a/.changeset/afraid-baboons-move.md b/.changeset/afraid-baboons-move.md new file mode 100644 index 0000000000..51575d9445 --- /dev/null +++ b/.changeset/afraid-baboons-move.md @@ -0,0 +1,5 @@ +--- +'@graphcommerce/magento-graphcms': patch +--- + +Added ProductScroller component with built-in skeleton loader diff --git a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx new file mode 100644 index 0000000000..67bcc2c253 --- /dev/null +++ b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx @@ -0,0 +1,138 @@ +import { + AddProductsToCartContext, + AddProductsToCartForm, + AddProductsToCartFormProps, + ProductListQuery, +} from '@graphcommerce/magento-product' +import { + ItemScroller, + ItemScrollerProps, + RenderType, + breakpointVal, + responsiveVal, +} from '@graphcommerce/next-ui' +import { + Box, + Container, + ContainerProps, + SxProps, + Theme, + Typography, + TypographyProps, + useTheme, +} from '@mui/material' +import { useContext } from 'react' +import { productListRenderer } from './productListRenderer' + +export const skeletonRenderer = { + Skeleton: ({ imageOnly = false }: { imageOnly?: boolean }) => ( + + ({ + background: 'linear-gradient(45deg, white, #f9f9f9, white)', + width: '100%', + aspectRatio: '1/1', + ...breakpointVal( + 'borderRadius', + theme.shape.borderRadius * 2, + theme.shape.borderRadius * 3, + theme.breakpoints.values, + ), + })} + /> + {!imageOnly && ( + ({ + marginTop: theme.spacings.xs, + display: 'block', + color: 'text.primary', + overflowWrap: 'break-word', + wordBreak: 'break-all', + maxWidth: '100%', + gridArea: 'title', + fontWeight: 'fontWeightBold', + })} + > +   + + )} + + ), +} + +export function ProductScroller({ + title = '', + items, + imageOnly = false, + skeletonItemCount = 0, + skeleton = skeletonRenderer, + sx = [], + containerProps, + titleProps, + itemScrollerProps, + addProductsToCartFormProps, +}: { + title?: string + items: Exclude['items'] + imageOnly?: boolean + skeletonItemCount: number + skeleton?: typeof skeletonRenderer + sx?: SxProps + containerProps?: ContainerProps + titleProps?: TypographyProps + addProductsToCartFormProps?: AddProductsToCartFormProps + itemScrollerProps?: ItemScrollerProps +}) { + const theme = useTheme() + + if (!!useContext(AddProductsToCartContext) && process.env.NODE_ENV !== 'production') + throw new Error("Can't use ProductScroller inside of AddProductsToCartForm") + + if (!items) return null + + return ( + + + {title && ( + + {title} + + )} + + {(!!items.length || !!skeletonItemCount) && ( + + + {(!items || !items.length) && + [...Array(skeletonItemCount).keys()].map((i) => { + const item = { + __typename: 'Skeleton', + } + return ( + + ) + })} + + {items?.map((item) => + item ? ( + + ) : null, + )} + + + )} + + ) +} From f8316e3a0a3b5ec707781e57d70c89b4be75d85c Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 9 Oct 2023 11:44:34 +0200 Subject: [PATCH 10/47] Fixed @graphcommerce/magento-recently-viewed-products version --- .../package.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/magento-recently-viewed-products/package.json b/packages/magento-recently-viewed-products/package.json index 6ead6d56cc..7b01373cb6 100644 --- a/packages/magento-recently-viewed-products/package.json +++ b/packages/magento-recently-viewed-products/package.json @@ -2,7 +2,7 @@ "name": "@graphcommerce/magento-recently-viewed-products", "homepage": "https://www.graphcommerce.org/", "repository": "github:graphcommerce-org/graphcommerce", - "version": "7.0.0", + "version": "7.1.0-canary.8", "sideEffects": false, "prettier": "@graphcommerce/prettier-config-pwa", "eslintConfig": { @@ -12,19 +12,19 @@ } }, "dependencies": { - "@graphcommerce/graphql": "7.0.2-canary.4", - "@graphcommerce/graphql-mesh": "7.0.2-canary.4", - "@graphcommerce/magento-cart": "7.0.2-canary.4", - "@graphcommerce/magento-product-configurable": "7.0.2-canary.4", - "@graphcommerce/magento-product": "7.0.2-canary.4", - "@graphcommerce/next-config": "7.0.2-canary.4", - "@graphcommerce/next-ui": "7.0.2-canary.4" + "@graphcommerce/graphql": "7.1.0-canary.8", + "@graphcommerce/graphql-mesh": "7.1.0-canary.8", + "@graphcommerce/magento-cart": "7.1.0-canary.8", + "@graphcommerce/magento-product-configurable": "7.1.0-canary.8", + "@graphcommerce/magento-product": "7.1.0-canary.8", + "@graphcommerce/next-config": "7.1.0-canary.8", + "@graphcommerce/next-ui": "7.1.0-canary.8" }, "devDependencies": { - "@graphcommerce/eslint-config-pwa": "7.0.2-canary.4", - "@graphcommerce/next-config": "^7.0.2-canary.4", - "@graphcommerce/prettier-config-pwa": "7.0.2-canary.4", - "@graphcommerce/typescript-config-pwa": "7.0.2-canary.4" + "@graphcommerce/eslint-config-pwa": "7.1.0-canary.8", + "@graphcommerce/next-config": "^7.1.0-canary.8", + "@graphcommerce/prettier-config-pwa": "7.1.0-canary.8", + "@graphcommerce/typescript-config-pwa": "7.1.0-canary.8" }, "peerDependencies": { "@mui/material": "^5.10.16", From e205e631bdd5939381c969df107c648856d31d04 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 9 Oct 2023 11:45:39 +0200 Subject: [PATCH 11/47] feat(GCOM-535) added RecentlyViewedProducts component --- .../RecentlyViewedProducts.tsx | 24 +++++++++++++++++++ .../hooks/useRecentlyViewedProducts.tsx | 3 ++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx diff --git a/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx b/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx new file mode 100644 index 0000000000..8fadaf9018 --- /dev/null +++ b/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx @@ -0,0 +1,24 @@ +import { + UseRecentlyViewedProductsProps, + useRecentlyViewedProducts, +} from '@graphcommerce/magento-recently-viewed-products/hooks/useRecentlyViewedProducts' +import { useRecentlyViewedSkus } from '@graphcommerce/magento-recently-viewed-products/hooks/useRecentlyViewedSkus' +import { ProductScroller } from './ProductScroller' + +export type RecentlyViewedProductsProps = UseRecentlyViewedProductsProps +export function RecentlyViewedProducts({ exclude }: RecentlyViewedProductsProps = {}) { + const { skus } = useRecentlyViewedSkus({ exclude }) + const { products, loading } = useRecentlyViewedProducts({ exclude }) + + if (!loading && !skus.length) { + return null + } + + return ( + + ) +} diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx index 129ffe865f..82ff1b8cff 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx @@ -3,7 +3,8 @@ import { ProductListDocument } from '@graphcommerce/magento-product' import { nonNullable } from '@graphcommerce/next-ui' import { useRecentlyViewedSkus } from './useRecentlyViewedSkus' -export function useRecentlyViewedProducts({ exclude }: { exclude?: string[] } = {}) { +export type UseRecentlyViewedProductsProps = { exclude?: string[] } +export function useRecentlyViewedProducts({ exclude }: UseRecentlyViewedProductsProps = {}) { const { skus, loading } = useRecentlyViewedSkus({ exclude }) const { From e661106d45e51c617533f19b397a812e22b6fc82 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 9 Oct 2023 11:47:40 +0200 Subject: [PATCH 12/47] Added changeset for recently viewed products --- .changeset/long-llamas-cheer.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/long-llamas-cheer.md diff --git a/.changeset/long-llamas-cheer.md b/.changeset/long-llamas-cheer.md new file mode 100644 index 0000000000..c348b8e704 --- /dev/null +++ b/.changeset/long-llamas-cheer.md @@ -0,0 +1,5 @@ +--- +'@graphcommerce/magento-recently-viewed-products': minor +--- + +Added recently viewd products hook and render component From 783188c83e2f86a3faa23dea5de4867eec9808e3 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 9 Oct 2023 13:25:28 +0200 Subject: [PATCH 13/47] feat(GCOM-535) Fixed error when trying to add first recently viewed product --- .../plugins/SetRecentlyViewedProducts.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx index 33863de905..739cc2a94c 100644 --- a/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx @@ -38,7 +38,7 @@ function ViewHandling(props: { product: ProductPageMetaFragment }) { (p) => p.sku === product.sku || p.parentSku === product.sku, ) const skuAlreadySet = skus.some((p) => p.sku === sku) - const skuIsLastItem = skus[skus.length - 1].sku === sku + const skuIsLastItem = skus.length === 0 || skus[skus.length - 1].sku === sku if (skuAlreadySet && skuIsLastItem) return From cf3e3db108b44ea803acc33912a8bd01f13f962e Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 9 Oct 2023 15:09:43 +0200 Subject: [PATCH 14/47] =?UTF-8?q?feat(GCOM-535)=20Added=20RowProduct=20var?= =?UTF-8?q?iant=20=E2=80=9CRecent=E2=80=9D=20to=20show=20recently=20viewed?= =?UTF-8?q?=20products?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/GraphCMS/RowProduct/RowProduct.tsx | 4 +++- .../components/GraphCMS/RowProduct/variant/Recent.tsx | 8 ++++++++ .../components/GraphCMS/RowProduct/variant/index.tsx | 1 + .../ProductListItems/RecentlyViewedProducts.tsx | 6 +++--- 4 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx diff --git a/examples/magento-graphcms/components/GraphCMS/RowProduct/RowProduct.tsx b/examples/magento-graphcms/components/GraphCMS/RowProduct/RowProduct.tsx index ce9acb43a4..75451489ea 100644 --- a/examples/magento-graphcms/components/GraphCMS/RowProduct/RowProduct.tsx +++ b/examples/magento-graphcms/components/GraphCMS/RowProduct/RowProduct.tsx @@ -5,6 +5,7 @@ import { Feature, FeatureBoxed, Grid, + Recent, Related, Reviews, Specs, @@ -19,7 +20,7 @@ type VariantRenderer = Record< type RowProductProps = RowProductFragment & { renderer?: Partial -} & ProductSpecsFragment & { items?: unknown } +} & ProductSpecsFragment & { items?: unknown } & { sku?: string | null | undefined } const defaultRenderer: Partial = { Specs, @@ -27,6 +28,7 @@ const defaultRenderer: Partial = { Feature, FeatureBoxed, Grid, + Recent, Related, Reviews, Upsells, diff --git a/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx b/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx new file mode 100644 index 0000000000..406e651c54 --- /dev/null +++ b/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx @@ -0,0 +1,8 @@ +import { RecentlyViewedProducts } from '../../../ProductListItems/RecentlyViewedProducts' +import { RowProductFragment } from '../RowProduct.gql' + +type RecentProps = RowProductFragment & { sku?: string | null | undefined } + +export function Recent({ title, sku }: RecentProps) { + return +} diff --git a/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/index.tsx b/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/index.tsx index a7123ddae5..ca42031c30 100644 --- a/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/index.tsx +++ b/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/index.tsx @@ -2,6 +2,7 @@ export * from './Backstory' export * from './Feature' export * from './FeatureBoxed' export * from './Grid' +export * from './Recent' export * from './Related' export * from './Reviews' export * from './Specs' diff --git a/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx b/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx index 8fadaf9018..eba521f812 100644 --- a/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx +++ b/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx @@ -5,8 +5,8 @@ import { import { useRecentlyViewedSkus } from '@graphcommerce/magento-recently-viewed-products/hooks/useRecentlyViewedSkus' import { ProductScroller } from './ProductScroller' -export type RecentlyViewedProductsProps = UseRecentlyViewedProductsProps -export function RecentlyViewedProducts({ exclude }: RecentlyViewedProductsProps = {}) { +export type RecentlyViewedProductsProps = UseRecentlyViewedProductsProps & { title?: string } +export function RecentlyViewedProducts({ exclude, title }: RecentlyViewedProductsProps = {}) { const { skus } = useRecentlyViewedSkus({ exclude }) const { products, loading } = useRecentlyViewedProducts({ exclude }) @@ -16,7 +16,7 @@ export function RecentlyViewedProducts({ exclude }: RecentlyViewedProductsProps return ( From b44f7c5dea2a2deaa365f7731d8dd619d9d2ee84 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 12 Oct 2023 13:08:05 +0200 Subject: [PATCH 15/47] Fix changeset typo Co-authored-by: Mike Keehnen --- .changeset/long-llamas-cheer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/long-llamas-cheer.md b/.changeset/long-llamas-cheer.md index c348b8e704..4aa24de92e 100644 --- a/.changeset/long-llamas-cheer.md +++ b/.changeset/long-llamas-cheer.md @@ -2,4 +2,4 @@ '@graphcommerce/magento-recently-viewed-products': minor --- -Added recently viewd products hook and render component +Added recently viewed products hook and render component From b2b7ff6e69c044fdeb48471e9609b29f3607bce4 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 12 Oct 2023 16:27:36 +0200 Subject: [PATCH 16/47] feat(GCOM-535) Refactor skeleton loader --- .../ProductListItems/ProductScroller.tsx | 54 ++++++------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx index 67bcc2c253..b4a78ce788 100644 --- a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx +++ b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx @@ -4,17 +4,12 @@ import { AddProductsToCartFormProps, ProductListQuery, } from '@graphcommerce/magento-product' -import { - ItemScroller, - ItemScrollerProps, - RenderType, - breakpointVal, - responsiveVal, -} from '@graphcommerce/next-ui' +import { ItemScroller, ItemScrollerProps, RenderType, responsiveVal } from '@graphcommerce/next-ui' import { Box, Container, ContainerProps, + Skeleton, SxProps, Theme, Typography, @@ -23,23 +18,13 @@ import { } from '@mui/material' import { useContext } from 'react' import { productListRenderer } from './productListRenderer' +import React from 'react' -export const skeletonRenderer = { - Skeleton: ({ imageOnly = false }: { imageOnly?: boolean }) => ( +export function ProductScrollerItemSkeleton({ imageOnly = false }: { imageOnly?: boolean }) { + return ( - ({ - background: 'linear-gradient(45deg, white, #f9f9f9, white)', - width: '100%', - aspectRatio: '1/1', - ...breakpointVal( - 'borderRadius', - theme.shape.borderRadius * 2, - theme.shape.borderRadius * 3, - theme.breakpoints.values, - ), - })} - /> + + {!imageOnly && ( )} - ), + ) } export function ProductScroller({ @@ -66,7 +51,7 @@ export function ProductScroller({ items, imageOnly = false, skeletonItemCount = 0, - skeleton = skeletonRenderer, + skeleton, sx = [], containerProps, titleProps, @@ -77,7 +62,7 @@ export function ProductScroller({ items: Exclude['items'] imageOnly?: boolean skeletonItemCount: number - skeleton?: typeof skeletonRenderer + skeleton?: React.ReactNode sx?: SxProps containerProps?: ContainerProps titleProps?: TypographyProps @@ -104,20 +89,11 @@ export function ProductScroller({ {(!items || !items.length) && - [...Array(skeletonItemCount).keys()].map((i) => { - const item = { - __typename: 'Skeleton', - } - return ( - - ) - })} + [...Array(skeletonItemCount + 10).keys()].map((i) => ( + + {skeleton || } + + ))} {items?.map((item) => item ? ( From 679231970dc668f74e954f9647771d47dbcebf53 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 12 Oct 2023 16:35:09 +0200 Subject: [PATCH 17/47] feat(GCOM-535) cleanup ProductScroller --- .../ProductListItems/ProductScroller.tsx | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx index b4a78ce788..2e8e084218 100644 --- a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx +++ b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx @@ -4,7 +4,13 @@ import { AddProductsToCartFormProps, ProductListQuery, } from '@graphcommerce/magento-product' -import { ItemScroller, ItemScrollerProps, RenderType, responsiveVal } from '@graphcommerce/next-ui' +import { + ItemScroller, + ItemScrollerProps, + RenderType, + nonNullable, + responsiveVal, +} from '@graphcommerce/next-ui' import { Box, Container, @@ -95,17 +101,15 @@ export function ProductScroller({ ))} - {items?.map((item) => - item ? ( - - ) : null, - )} + {items.filter(nonNullable).map((item) => ( + + ))} )} From 25b0e7dc5808cc41df4c71966dab4578f02d2512 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Fri, 20 Oct 2023 15:45:29 +0200 Subject: [PATCH 18/47] Rename SetRecentlyViewedProducts plugin to RegisterProductAsRecentlyViewed --- ...ViewedProducts.tsx => RegisterProductAsRecentlyViewed.tsx} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename packages/magento-recently-viewed-products/plugins/{SetRecentlyViewedProducts.tsx => RegisterProductAsRecentlyViewed.tsx} (95%) diff --git a/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/plugins/RegisterProductAsRecentlyViewed.tsx similarity index 95% rename from packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx rename to packages/magento-recently-viewed-products/plugins/RegisterProductAsRecentlyViewed.tsx index 739cc2a94c..c177717313 100644 --- a/packages/magento-recently-viewed-products/plugins/SetRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/plugins/RegisterProductAsRecentlyViewed.tsx @@ -70,7 +70,7 @@ function ViewHandling(props: { product: ProductPageMetaFragment }) { return null } -const SetRecentlyViewedProducts: PluginType = (props) => { +const RegisterProductAsRecentlyViewed: PluginType = (props) => { const { Prev, product } = props return ( @@ -81,4 +81,4 @@ const SetRecentlyViewedProducts: PluginType = (props) => { ) } -export const Plugin = SetRecentlyViewedProducts +export const Plugin = RegisterProductAsRecentlyViewed From 95ed0a817fbd6f8a674164fb8653b453d086b601 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Fri, 20 Oct 2023 15:47:10 +0200 Subject: [PATCH 19/47] Fix types & code style --- .../ProductListItems/ProductScroller.tsx | 51 +++++++++---------- .../hooks/useRecentlyViewedProducts.tsx | 10 ++-- .../hooks/useRecentlyViewedSkus.tsx | 4 +- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx index 2e8e084218..63497a7a72 100644 --- a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx +++ b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx @@ -2,15 +2,10 @@ import { AddProductsToCartContext, AddProductsToCartForm, AddProductsToCartFormProps, - ProductListQuery, + ProductListItemFragment, + ProductListItemProps, } from '@graphcommerce/magento-product' -import { - ItemScroller, - ItemScrollerProps, - RenderType, - nonNullable, - responsiveVal, -} from '@graphcommerce/next-ui' +import { ItemScroller, ItemScrollerProps, RenderType, responsiveVal } from '@graphcommerce/next-ui' import { Box, Container, @@ -22,9 +17,8 @@ import { TypographyProps, useTheme, } from '@mui/material' -import { useContext } from 'react' +import React, { useContext } from 'react' import { productListRenderer } from './productListRenderer' -import React from 'react' export function ProductScrollerItemSkeleton({ imageOnly = false }: { imageOnly?: boolean }) { return ( @@ -52,21 +46,10 @@ export function ProductScrollerItemSkeleton({ imageOnly = false }: { imageOnly?: ) } -export function ProductScroller({ - title = '', - items, - imageOnly = false, - skeletonItemCount = 0, - skeleton, - sx = [], - containerProps, - titleProps, - itemScrollerProps, - addProductsToCartFormProps, -}: { +export type ProductScrollerProps = { title?: string - items: Exclude['items'] - imageOnly?: boolean + items: ProductListItemFragment[] + imageOnly?: ProductListItemProps['imageOnly'] skeletonItemCount: number skeleton?: React.ReactNode sx?: SxProps @@ -74,7 +57,21 @@ export function ProductScroller({ titleProps?: TypographyProps addProductsToCartFormProps?: AddProductsToCartFormProps itemScrollerProps?: ItemScrollerProps -}) { +} +export function ProductScroller(props: ProductScrollerProps) { + const { + title = '', + items, + imageOnly = false, + skeletonItemCount = 0, + skeleton, + sx = [], + containerProps, + titleProps, + itemScrollerProps, + addProductsToCartFormProps, + } = props + const theme = useTheme() if (!!useContext(AddProductsToCartContext) && process.env.NODE_ENV !== 'production') @@ -94,14 +91,14 @@ export function ProductScroller({ {(!!items.length || !!skeletonItemCount) && ( - {(!items || !items.length) && + {!items.length && [...Array(skeletonItemCount + 10).keys()].map((i) => ( {skeleton || } ))} - {items.filter(nonNullable).map((item) => ( + {items.map((item) => ( products.find((p) => (p?.sku || '') === sku.sku)).filter(nonNullable) + const products = skus + .map((sku) => productData.find((p) => (p?.sku || '') === sku.sku)) + .filter(nonNullable) return { products, diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx index 0d5a043f77..00cea1cc6e 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx @@ -1,7 +1,9 @@ import { useQuery } from '@graphcommerce/graphql' import { RecentlyViewedProductsDocument } from '../graphql/RecentlyViewedProducts.gql' -export function useRecentlyViewedSkus({ exclude }: { exclude?: string[] } = {}) { +export type useRecentlyViewedSkusProps = { exclude?: string[] } + +export function useRecentlyViewedSkus({ exclude }: useRecentlyViewedSkusProps = {}) { const { data, loading, previousData } = useQuery(RecentlyViewedProductsDocument) let skus = (loading ? previousData : data)?.recentlyViewedProducts?.items || [] From ef622e9d43f7c5d126443bd2a393857717de56ea Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Fri, 20 Oct 2023 15:47:48 +0200 Subject: [PATCH 20/47] Remove manually added changelog Should be added automatically --- packages/magento-recently-viewed-products/CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 packages/magento-recently-viewed-products/CHANGELOG.md diff --git a/packages/magento-recently-viewed-products/CHANGELOG.md b/packages/magento-recently-viewed-products/CHANGELOG.md deleted file mode 100644 index 420e6f23d0..0000000000 --- a/packages/magento-recently-viewed-products/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -# Change Log From f0dddaab4d148ca1810024a2d3000db9f46381ff Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 26 Oct 2023 10:59:42 +0200 Subject: [PATCH 21/47] Fixed skeleton item count added 10 during testing and forgot to remove --- .../components/ProductListItems/ProductScroller.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx index 63497a7a72..0ee45de881 100644 --- a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx +++ b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx @@ -92,7 +92,7 @@ export function ProductScroller(props: ProductScrollerProps) { {!items.length && - [...Array(skeletonItemCount + 10).keys()].map((i) => ( + [...Array(skeletonItemCount).keys()].map((i) => ( {skeleton || } From 04f8b6a8582ef259ed02a39e98e15bc13c0c64aa Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 26 Oct 2023 11:00:09 +0200 Subject: [PATCH 22/47] Fixed ProductScroller image sizes --- .../components/ProductListItems/ProductScroller.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx index 0ee45de881..e2b5133eeb 100644 --- a/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx +++ b/examples/magento-graphcms/components/ProductListItems/ProductScroller.tsx @@ -104,7 +104,7 @@ export function ProductScroller(props: ProductScrollerProps) { renderer={productListRenderer} {...item} imageOnly={imageOnly} - sizes={responsiveVal(180, 900)} + sizes={responsiveVal(200, 300)} /> ))} From 1929280a2eb65872ae4f6bfb7b7224582a7b1778 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 26 Oct 2023 13:21:04 +0200 Subject: [PATCH 23/47] Move ProductScroller outside of example folder --- .../RecentlyViewedProducts.tsx | 4 +++- .../ProductScroller}/ProductScroller.tsx | 18 ++++++++++-------- packages/magento-product/components/index.ts | 1 + 3 files changed, 14 insertions(+), 9 deletions(-) rename {examples/magento-graphcms/components/ProductListItems => packages/magento-product/components/ProductScroller}/ProductScroller.tsx (90%) diff --git a/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx b/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx index eba521f812..3ddc75a91b 100644 --- a/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx +++ b/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx @@ -1,9 +1,10 @@ +import { ProductScroller } from '@graphcommerce/magento-product' import { UseRecentlyViewedProductsProps, useRecentlyViewedProducts, } from '@graphcommerce/magento-recently-viewed-products/hooks/useRecentlyViewedProducts' import { useRecentlyViewedSkus } from '@graphcommerce/magento-recently-viewed-products/hooks/useRecentlyViewedSkus' -import { ProductScroller } from './ProductScroller' +import { productListRenderer } from './productListRenderer' export type RecentlyViewedProductsProps = UseRecentlyViewedProductsProps & { title?: string } export function RecentlyViewedProducts({ exclude, title }: RecentlyViewedProductsProps = {}) { @@ -16,6 +17,7 @@ export function RecentlyViewedProducts({ exclude, title }: RecentlyViewedProduct return ( Date: Thu, 26 Oct 2023 14:30:56 +0200 Subject: [PATCH 24/47] Move RecentlyViewedProducts component to package instead of example folder --- .../GraphCMS/RowProduct/variant/Recent.tsx | 11 +++++++++-- .../components}/RecentlyViewedProducts.tsx | 15 +++++++++------ .../hooks/index.ts | 2 ++ .../magento-recently-viewed-products/index.ts | 4 +++- 4 files changed, 23 insertions(+), 9 deletions(-) rename {examples/magento-graphcms/components/ProductListItems => packages/magento-recently-viewed-products/components}/RecentlyViewedProducts.tsx (52%) create mode 100644 packages/magento-recently-viewed-products/hooks/index.ts diff --git a/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx b/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx index 406e651c54..9d42e28268 100644 --- a/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx +++ b/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx @@ -1,8 +1,15 @@ -import { RecentlyViewedProducts } from '../../../ProductListItems/RecentlyViewedProducts' +import { RecentlyViewedProducts } from '@graphcommerce/magento-recently-viewed-products' +import { productListRenderer } from '../../../ProductListItems' import { RowProductFragment } from '../RowProduct.gql' type RecentProps = RowProductFragment & { sku?: string | null | undefined } export function Recent({ title, sku }: RecentProps) { - return + return ( + + ) } diff --git a/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx similarity index 52% rename from examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx rename to packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx index 3ddc75a91b..824400bb21 100644 --- a/examples/magento-graphcms/components/ProductListItems/RecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx @@ -1,13 +1,16 @@ -import { ProductScroller } from '@graphcommerce/magento-product' +import { ProductListItemRenderer, ProductScroller } from '@graphcommerce/magento-product' import { UseRecentlyViewedProductsProps, useRecentlyViewedProducts, -} from '@graphcommerce/magento-recently-viewed-products/hooks/useRecentlyViewedProducts' -import { useRecentlyViewedSkus } from '@graphcommerce/magento-recently-viewed-products/hooks/useRecentlyViewedSkus' -import { productListRenderer } from './productListRenderer' + useRecentlyViewedSkus, +} from '../hooks' -export type RecentlyViewedProductsProps = UseRecentlyViewedProductsProps & { title?: string } -export function RecentlyViewedProducts({ exclude, title }: RecentlyViewedProductsProps = {}) { +export type RecentlyViewedProductsProps = UseRecentlyViewedProductsProps & { + title?: string + productListRenderer: ProductListItemRenderer +} +export function RecentlyViewedProducts(props: RecentlyViewedProductsProps) { + const { exclude, title, productListRenderer } = props const { skus } = useRecentlyViewedSkus({ exclude }) const { products, loading } = useRecentlyViewedProducts({ exclude }) diff --git a/packages/magento-recently-viewed-products/hooks/index.ts b/packages/magento-recently-viewed-products/hooks/index.ts new file mode 100644 index 0000000000..af145c0ca7 --- /dev/null +++ b/packages/magento-recently-viewed-products/hooks/index.ts @@ -0,0 +1,2 @@ +export * from './useRecentlyViewedProducts' +export * from './useRecentlyViewedSkus' diff --git a/packages/magento-recently-viewed-products/index.ts b/packages/magento-recently-viewed-products/index.ts index cb64ac1b52..c8fd0c7e6e 100644 --- a/packages/magento-recently-viewed-products/index.ts +++ b/packages/magento-recently-viewed-products/index.ts @@ -1 +1,3 @@ -export * from './components' +export * from './components/RecentlyViewedProducts' +export * from './hooks' +export * from './graphql/RecentlyViewedProducts.gql' From 5a2d8aa729b6462f772a83612a4f270c9d5f06d9 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 26 Oct 2023 14:37:22 +0200 Subject: [PATCH 25/47] Use PacalCase for type --- .../hooks/useRecentlyViewedProducts.tsx | 4 ++-- .../hooks/useRecentlyViewedSkus.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx index 1af661a7c7..9817672c15 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx @@ -1,9 +1,9 @@ import { useQuery } from '@graphcommerce/graphql' import { ProductListDocument } from '@graphcommerce/magento-product' import { nonNullable } from '@graphcommerce/next-ui' -import { useRecentlyViewedSkus, useRecentlyViewedSkusProps } from './useRecentlyViewedSkus' +import { useRecentlyViewedSkus, UseRecentlyViewedSkusProps } from './useRecentlyViewedSkus' -export type UseRecentlyViewedProductsProps = useRecentlyViewedSkusProps +export type UseRecentlyViewedProductsProps = UseRecentlyViewedSkusProps export function useRecentlyViewedProducts({ exclude }: UseRecentlyViewedProductsProps = {}) { const { skus, loading } = useRecentlyViewedSkus({ exclude }) diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx index 00cea1cc6e..925b3eda8d 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx @@ -1,9 +1,9 @@ import { useQuery } from '@graphcommerce/graphql' import { RecentlyViewedProductsDocument } from '../graphql/RecentlyViewedProducts.gql' -export type useRecentlyViewedSkusProps = { exclude?: string[] } +export type UseRecentlyViewedSkusProps = { exclude?: string[] } -export function useRecentlyViewedSkus({ exclude }: useRecentlyViewedSkusProps = {}) { +export function useRecentlyViewedSkus({ exclude }: UseRecentlyViewedSkusProps = {}) { const { data, loading, previousData } = useQuery(RecentlyViewedProductsDocument) let skus = (loading ? previousData : data)?.recentlyViewedProducts?.items || [] From 16da39811258b7a54125f02182265a501872aeb1 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 26 Oct 2023 14:38:20 +0200 Subject: [PATCH 26/47] Improve codestyle --- .../hooks/useRecentlyViewedProducts.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx index 9817672c15..69d2995246 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx @@ -4,14 +4,11 @@ import { nonNullable } from '@graphcommerce/next-ui' import { useRecentlyViewedSkus, UseRecentlyViewedSkusProps } from './useRecentlyViewedSkus' export type UseRecentlyViewedProductsProps = UseRecentlyViewedSkusProps -export function useRecentlyViewedProducts({ exclude }: UseRecentlyViewedProductsProps = {}) { +export function useRecentlyViewedProducts(props: UseRecentlyViewedProductsProps) { + const { exclude } = props const { skus, loading } = useRecentlyViewedSkus({ exclude }) - const { - loading: loadingProducts, - data, - previousData, - } = useQuery(ProductListDocument, { + const productList = useQuery(ProductListDocument, { variables: { filters: { sku: { @@ -22,7 +19,8 @@ export function useRecentlyViewedProducts({ exclude }: UseRecentlyViewedProducts skip: loading || !skus.length, }) - const productData = data?.products?.items || previousData?.products?.items || [] + const productData = + productList.data?.products?.items || productList.previousData?.products?.items || [] // Sort products based on the time they were viewed. Last viewed item should be the first item in the array const products = skus .map((sku) => productData.find((p) => (p?.sku || '') === sku.sku)) @@ -30,6 +28,6 @@ export function useRecentlyViewedProducts({ exclude }: UseRecentlyViewedProducts return { products, - loading: loading || loadingProducts, + loading: loading || productList.loading, } } From 8fc2ddd93d5fea5144201f6851d10cb7d0a3efea Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 26 Oct 2023 14:40:30 +0200 Subject: [PATCH 27/47] Sort SKUs to prevent unnecessary queries for the same list (in a different order) when visiting recently viewed products --- .../hooks/useRecentlyViewedProducts.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx index 69d2995246..b73d514add 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx @@ -12,7 +12,7 @@ export function useRecentlyViewedProducts(props: UseRecentlyViewedProductsProps) variables: { filters: { sku: { - in: skus.map((p) => p.sku), + in: skus.map((p) => p.sku).sort(), }, }, }, From b4d6541fde23c3f7cdfc7160bb7c9c13468aa86f Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 26 Oct 2023 15:12:59 +0200 Subject: [PATCH 28/47] Added config to enable/disable recently viewed products --- docs/framework/config.md | 16 ++++++++++++--- .../Config.graphqls | 15 ++++++++++++-- .../hooks/useRecentlyViewedSkus.tsx | 4 +++- .../RegisterProductAsRecentlyViewed.tsx | 5 +++-- .../next-config/dist/generated/config.js | 11 +++++++++- .../next-config/src/generated/config.ts | 20 ++++++++++++++++--- 6 files changed, 59 insertions(+), 12 deletions(-) diff --git a/docs/framework/config.md b/docs/framework/config.md index 8540a0ea1b..90cb9c20c4 100644 --- a/docs/framework/config.md +++ b/docs/framework/config.md @@ -272,9 +272,9 @@ By default we route products to /p/[url] but you can change this to /product/[ur Default: '/p/' Example: '/product/' -#### `recentlyViewedProductsCount: Int` +#### `recentlyViewedProducts: [RecentlyViewedProductsConfg](#RecentlyViewedProductsConfg)` -Number of recently viewed products to be stored in localStorage +Settings for recently viewed products #### `robotsAllow: Boolean` @@ -397,4 +397,14 @@ provided that the gallery images for the selected variant differ from the curren When a variant is selected the URL of the product will be changed in the address bar. -This only happens when the actual variant is can be accessed by the URL. \ No newline at end of file +This only happens when the actual variant is can be accessed by the URL. + +### RecentlyViewedProductsConfg + +#### `enabled: Boolean` + +Enable/disable recently viewed products + +#### `maxCount: Int` + +Number of recently viewed products to be stored in localStorage \ No newline at end of file diff --git a/packages/magento-recently-viewed-products/Config.graphqls b/packages/magento-recently-viewed-products/Config.graphqls index b28a4ba7ab..c15d66fae8 100644 --- a/packages/magento-recently-viewed-products/Config.graphqls +++ b/packages/magento-recently-viewed-products/Config.graphqls @@ -1,6 +1,17 @@ -extend input GraphCommerceConfig { +input RecentlyViewedProductsConfg { + """ + Enable/disable recently viewed products + """ + enabled: Boolean """ Number of recently viewed products to be stored in localStorage """ - recentlyViewedProductsCount: Int + maxCount: Int +} + +extend input GraphCommerceConfig { + """ + Settings for recently viewed products + """ + recentlyViewedProducts: RecentlyViewedProductsConfg } diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx index 925b3eda8d..4f0cba20ef 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx @@ -4,7 +4,9 @@ import { RecentlyViewedProductsDocument } from '../graphql/RecentlyViewedProduct export type UseRecentlyViewedSkusProps = { exclude?: string[] } export function useRecentlyViewedSkus({ exclude }: UseRecentlyViewedSkusProps = {}) { - const { data, loading, previousData } = useQuery(RecentlyViewedProductsDocument) + const { data, loading, previousData } = useQuery(RecentlyViewedProductsDocument, { + skip: !import.meta.graphCommerce.recentlyViewedProducts?.enabled, + }) let skus = (loading ? previousData : data)?.recentlyViewedProducts?.items || [] // Filter out excluded products (current product page) diff --git a/packages/magento-recently-viewed-products/plugins/RegisterProductAsRecentlyViewed.tsx b/packages/magento-recently-viewed-products/plugins/RegisterProductAsRecentlyViewed.tsx index c177717313..7d0b5912fd 100644 --- a/packages/magento-recently-viewed-products/plugins/RegisterProductAsRecentlyViewed.tsx +++ b/packages/magento-recently-viewed-products/plugins/RegisterProductAsRecentlyViewed.tsx @@ -5,7 +5,7 @@ import { ProductPageMetaFragment, } from '@graphcommerce/magento-product' import { useConfigurableSelectedVariant } from '@graphcommerce/magento-product-configurable/hooks' -import type { ReactPlugin } from '@graphcommerce/next-config' +import type { IfConfig, ReactPlugin } from '@graphcommerce/next-config' import { useEventCallback } from '@mui/material' import { useRouter } from 'next/router' import { useEffect } from 'react' @@ -13,6 +13,7 @@ import { RecentlyViewedProductsDocument } from '../graphql/RecentlyViewedProduct export const component = 'ProductPageMeta' export const exported = '@graphcommerce/magento-product/components/ProductPageMeta/ProductPageMeta' +export const ifConfig: IfConfig = 'recentlyViewedProducts.enabled' type PluginType = ReactPlugin @@ -53,7 +54,7 @@ function ViewHandling(props: { product: ProductPageMetaFragment }) { const items = [ { __typename: 'RecentlyViewedProduct' as const, parentSku, sku }, ...viewedSkus, - ].splice(0, import.meta.graphCommerce.recentlyViewedProductsCount || 10) + ].splice(0, import.meta.graphCommerce.recentlyViewedProducts?.maxCount || 10) client.writeQuery({ query: RecentlyViewedProductsDocument, diff --git a/packagesDev/next-config/dist/generated/config.js b/packagesDev/next-config/dist/generated/config.js index 9d598689ea..bffe36df38 100644 --- a/packagesDev/next-config/dist/generated/config.js +++ b/packagesDev/next-config/dist/generated/config.js @@ -32,6 +32,9 @@ _export(exports, { }, MagentoConfigurableVariantValuesSchema: function() { return MagentoConfigurableVariantValuesSchema; + }, + RecentlyViewedProductsConfgSchema: function() { + return RecentlyViewedProductsConfgSchema; } }); const _zod = require("zod"); @@ -72,7 +75,7 @@ function GraphCommerceConfigSchema() { productFiltersLayout: ProductFiltersLayoutSchema.nullish(), productFiltersPro: _zod.z.boolean().nullish(), productRoute: _zod.z.string().nullish(), - recentlyViewedProductsCount: _zod.z.number().nullish(), + recentlyViewedProducts: RecentlyViewedProductsConfgSchema().nullish(), robotsAllow: _zod.z.boolean().nullish(), storefront: _zod.z.array(GraphCommerceStorefrontConfigSchema()), wishlistHideForGuests: _zod.z.boolean().nullish(), @@ -109,3 +112,9 @@ function MagentoConfigurableVariantValuesSchema() { url: _zod.z.boolean().nullish() }); } +function RecentlyViewedProductsConfgSchema() { + return _zod.z.object({ + enabled: _zod.z.boolean().nullish(), + maxCount: _zod.z.number().nullish() + }); +} diff --git a/packagesDev/next-config/src/generated/config.ts b/packagesDev/next-config/src/generated/config.ts index a8a61836fb..a1990e31dc 100644 --- a/packagesDev/next-config/src/generated/config.ts +++ b/packagesDev/next-config/src/generated/config.ts @@ -277,8 +277,8 @@ export type GraphCommerceConfig = { * Example: '/product/' */ productRoute?: InputMaybe; - /** Number of recently viewed products to be stored in localStorage */ - recentlyViewedProductsCount?: InputMaybe; + /** Settings for recently viewed products */ + recentlyViewedProducts?: InputMaybe; /** * Allow the site to be indexed by search engines. * If false, the robots.txt file will be set to disallow all. @@ -386,6 +386,13 @@ export type ProductFiltersLayout = | 'DEFAULT' | 'SIDEBAR'; +export type RecentlyViewedProductsConfg = { + /** Enable/disable recently viewed products */ + enabled?: InputMaybe; + /** Number of recently viewed products to be stored in localStorage */ + maxCount?: InputMaybe; +}; + type Properties = Required<{ [K in keyof T]: z.ZodType; @@ -428,7 +435,7 @@ export function GraphCommerceConfigSchema(): z.ZodObject> { + return z.object({ + enabled: z.boolean().nullish(), + maxCount: z.number().nullish() + }) +} From 95999f3232c39c440ffb3cb2c28a7be1b25fddc9 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 30 Oct 2023 15:41:44 +0100 Subject: [PATCH 29/47] Conditionally add AddProductsToCartForm when no AddProductsToCartContext is available --- .../components/ProductScroller/ProductScroller.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/magento-product/components/ProductScroller/ProductScroller.tsx b/packages/magento-product/components/ProductScroller/ProductScroller.tsx index c9cdacaa5d..2d9c733d57 100644 --- a/packages/magento-product/components/ProductScroller/ProductScroller.tsx +++ b/packages/magento-product/components/ProductScroller/ProductScroller.tsx @@ -76,8 +76,7 @@ export function ProductScroller(props: ProductScrollerProps) { const theme = useTheme() - if (!!useContext(AddProductsToCartContext) && process.env.NODE_ENV !== 'production') - throw new Error("Can't use ProductScroller inside of AddProductsToCartForm") + const Wrapper = useContext(AddProductsToCartContext) ? React.Fragment : AddProductsToCartForm if (!items) return null @@ -91,7 +90,7 @@ export function ProductScroller(props: ProductScrollerProps) { )} {(!!items.length || !!skeletonItemCount) && ( - + {!items.length && [...Array(skeletonItemCount).keys()].map((i) => ( @@ -110,7 +109,7 @@ export function ProductScroller(props: ProductScrollerProps) { /> ))} - + )} ) From 1ce0a2041dc17103f0f1096abd9d8a0d4695f2ca Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 30 Oct 2023 15:42:54 +0100 Subject: [PATCH 30/47] Improve codestyle --- .../hooks/useRecentlyViewedSkus.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx index 4f0cba20ef..77efa5989b 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedSkus.tsx @@ -3,7 +3,8 @@ import { RecentlyViewedProductsDocument } from '../graphql/RecentlyViewedProduct export type UseRecentlyViewedSkusProps = { exclude?: string[] } -export function useRecentlyViewedSkus({ exclude }: UseRecentlyViewedSkusProps = {}) { +export function useRecentlyViewedSkus(props: UseRecentlyViewedSkusProps = {}) { + const { exclude } = props const { data, loading, previousData } = useQuery(RecentlyViewedProductsDocument, { skip: !import.meta.graphCommerce.recentlyViewedProducts?.enabled, }) From 0dfd5bf44f61e74fbbb9a7f8f6d7da52525a6eb9 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 30 Oct 2023 16:41:17 +0100 Subject: [PATCH 31/47] Filter excluded SKUs from query result instead of from the query itself to prevent unnecessary queries when visiting recently viewed products --- .../hooks/useRecentlyViewedProducts.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx index b73d514add..079b2e4d13 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx @@ -6,7 +6,7 @@ import { useRecentlyViewedSkus, UseRecentlyViewedSkusProps } from './useRecently export type UseRecentlyViewedProductsProps = UseRecentlyViewedSkusProps export function useRecentlyViewedProducts(props: UseRecentlyViewedProductsProps) { const { exclude } = props - const { skus, loading } = useRecentlyViewedSkus({ exclude }) + let { skus, loading } = useRecentlyViewedSkus() const productList = useQuery(ProductListDocument, { variables: { @@ -21,6 +21,17 @@ export function useRecentlyViewedProducts(props: UseRecentlyViewedProductsProps) const productData = productList.data?.products?.items || productList.previousData?.products?.items || [] + + if (exclude) { + skus = skus.filter( + (item) => + item?.sku && + !exclude.includes(item.sku) && + item?.parentSku && + !exclude.includes(item.parentSku), + ) + } + // Sort products based on the time they were viewed. Last viewed item should be the first item in the array const products = skus .map((sku) => productData.find((p) => (p?.sku || '') === sku.sku)) From ce21f8531e7a0049607224c42485a2ccc5d21dcc Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Mon, 30 Oct 2023 16:43:40 +0100 Subject: [PATCH 32/47] Added lazy loading for recently viewed products query --- .../ProductScroller/ProductScroller.tsx | 107 +++++++++--------- .../components/RecentlyViewedProducts.tsx | 17 ++- .../hooks/useRecentlyViewedProducts.tsx | 6 +- .../package.json | 1 + 4 files changed, 72 insertions(+), 59 deletions(-) diff --git a/packages/magento-product/components/ProductScroller/ProductScroller.tsx b/packages/magento-product/components/ProductScroller/ProductScroller.tsx index 2d9c733d57..c7e0e5dd2d 100644 --- a/packages/magento-product/components/ProductScroller/ProductScroller.tsx +++ b/packages/magento-product/components/ProductScroller/ProductScroller.tsx @@ -10,7 +10,7 @@ import { TypographyProps, useTheme, } from '@mui/material' -import React, { useContext } from 'react' +import React, { forwardRef, useContext } from 'react' import { ProductListItemFragment } from '../../Api/ProductListItem.gql' import { AddProductsToCartContext, @@ -59,58 +59,63 @@ export type ProductScrollerProps = { addProductsToCartFormProps?: AddProductsToCartFormProps itemScrollerProps?: ItemScrollerProps } -export function ProductScroller(props: ProductScrollerProps) { - const { - title = '', - items, - productListRenderer, - imageOnly = false, - skeletonItemCount = 0, - skeleton, - sx = [], - containerProps, - titleProps, - itemScrollerProps, - addProductsToCartFormProps, - } = props +export const ProductScroller = forwardRef( + (props: ProductScrollerProps, ref) => { + const { + title = '', + items, + productListRenderer, + imageOnly = false, + skeletonItemCount = 0, + skeleton, + sx = [], + containerProps, + titleProps, + itemScrollerProps, + addProductsToCartFormProps, + } = props - const theme = useTheme() + const theme = useTheme() - const Wrapper = useContext(AddProductsToCartContext) ? React.Fragment : AddProductsToCartForm + const Wrapper = useContext(AddProductsToCartContext) ? React.Fragment : AddProductsToCartForm - if (!items) return null + if (!items) return null - return ( - - - {title && ( - - {title} - - )} - - {(!!items.length || !!skeletonItemCount) && ( - - - {!items.length && - [...Array(skeletonItemCount).keys()].map((i) => ( - - {skeleton || } - - ))} + return ( + + + {title && ( + + {title} + + )} + + {(!!items.length || !!skeletonItemCount) && ( + + + {!items.length && + [...Array(skeletonItemCount).keys()].map((i) => ( + + {skeleton || } + + ))} - {items.map((item) => ( - - ))} - - - )} - - ) -} + {items.map((item) => ( + + ))} + + + )} + + ) + }, +) diff --git a/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx index 824400bb21..a7a7c88059 100644 --- a/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx @@ -1,4 +1,6 @@ import { ProductListItemRenderer, ProductScroller } from '@graphcommerce/magento-product' +import { useInView } from 'framer-motion' +import { useRef } from 'react' import { UseRecentlyViewedProductsProps, useRecentlyViewedProducts, @@ -8,22 +10,27 @@ import { export type RecentlyViewedProductsProps = UseRecentlyViewedProductsProps & { title?: string productListRenderer: ProductListItemRenderer + loading?: 'lazy' | 'eager' } export function RecentlyViewedProducts(props: RecentlyViewedProductsProps) { - const { exclude, title, productListRenderer } = props + const { exclude, title, productListRenderer, loading = 'lazy' } = props + + const ref = useRef(null) + const isInView = useInView(ref, { margin: '300px', once: true }) const { skus } = useRecentlyViewedSkus({ exclude }) - const { products, loading } = useRecentlyViewedProducts({ exclude }) + const productList = useRecentlyViewedProducts({ exclude, skip: !isInView && loading === 'lazy' }) - if (!loading && !skus.length) { + if (!productList.loading && !skus.length) { return null } return ( ) } diff --git a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx index 079b2e4d13..e21e91d592 100644 --- a/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/hooks/useRecentlyViewedProducts.tsx @@ -3,9 +3,9 @@ import { ProductListDocument } from '@graphcommerce/magento-product' import { nonNullable } from '@graphcommerce/next-ui' import { useRecentlyViewedSkus, UseRecentlyViewedSkusProps } from './useRecentlyViewedSkus' -export type UseRecentlyViewedProductsProps = UseRecentlyViewedSkusProps +export type UseRecentlyViewedProductsProps = UseRecentlyViewedSkusProps & { skip?: boolean } export function useRecentlyViewedProducts(props: UseRecentlyViewedProductsProps) { - const { exclude } = props + const { exclude, skip = false } = props let { skus, loading } = useRecentlyViewedSkus() const productList = useQuery(ProductListDocument, { @@ -16,7 +16,7 @@ export function useRecentlyViewedProducts(props: UseRecentlyViewedProductsProps) }, }, }, - skip: loading || !skus.length, + skip: loading || !skus.length || skip, }) const productData = diff --git a/packages/magento-recently-viewed-products/package.json b/packages/magento-recently-viewed-products/package.json index 7b01373cb6..944b6d11e3 100644 --- a/packages/magento-recently-viewed-products/package.json +++ b/packages/magento-recently-viewed-products/package.json @@ -28,6 +28,7 @@ }, "peerDependencies": { "@mui/material": "^5.10.16", + "framer-motion": "^10.0.0", "next": "^13.2.0", "react": "^18.2.0", "react-dom": "^18.2.0" From e6ad2564e76aec8671007575ff05272b6859b899 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Wed, 1 Nov 2023 10:21:18 +0100 Subject: [PATCH 33/47] Update magento-recently-viewed-products package.json --- .../package.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/magento-recently-viewed-products/package.json b/packages/magento-recently-viewed-products/package.json index 944b6d11e3..1aed04231b 100644 --- a/packages/magento-recently-viewed-products/package.json +++ b/packages/magento-recently-viewed-products/package.json @@ -2,7 +2,7 @@ "name": "@graphcommerce/magento-recently-viewed-products", "homepage": "https://www.graphcommerce.org/", "repository": "github:graphcommerce-org/graphcommerce", - "version": "7.1.0-canary.8", + "version": "7.1.0-canary.30", "sideEffects": false, "prettier": "@graphcommerce/prettier-config-pwa", "eslintConfig": { @@ -12,19 +12,19 @@ } }, "dependencies": { - "@graphcommerce/graphql": "7.1.0-canary.8", - "@graphcommerce/graphql-mesh": "7.1.0-canary.8", - "@graphcommerce/magento-cart": "7.1.0-canary.8", - "@graphcommerce/magento-product-configurable": "7.1.0-canary.8", - "@graphcommerce/magento-product": "7.1.0-canary.8", - "@graphcommerce/next-config": "7.1.0-canary.8", - "@graphcommerce/next-ui": "7.1.0-canary.8" + "@graphcommerce/graphql": "7.1.0-canary.30", + "@graphcommerce/graphql-mesh": "7.1.0-canary.30", + "@graphcommerce/magento-cart": "7.1.0-canary.30", + "@graphcommerce/magento-product-configurable": "7.1.0-canary.30", + "@graphcommerce/magento-product": "7.1.0-canary.30", + "@graphcommerce/next-config": "7.1.0-canary.30", + "@graphcommerce/next-ui": "7.1.0-canary.30" }, "devDependencies": { - "@graphcommerce/eslint-config-pwa": "7.1.0-canary.8", - "@graphcommerce/next-config": "^7.1.0-canary.8", - "@graphcommerce/prettier-config-pwa": "7.1.0-canary.8", - "@graphcommerce/typescript-config-pwa": "7.1.0-canary.8" + "@graphcommerce/eslint-config-pwa": "7.1.0-canary.30", + "@graphcommerce/next-config": "^7.1.0-canary.30", + "@graphcommerce/prettier-config-pwa": "7.1.0-canary.30", + "@graphcommerce/typescript-config-pwa": "7.1.0-canary.30" }, "peerDependencies": { "@mui/material": "^5.10.16", From 5f4455b1cccddf1501f0279e5ca2d9277a07ff07 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 2 Nov 2023 11:24:48 +0100 Subject: [PATCH 34/47] feat(GCOM-535) Added ProductListItemSkeleton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split ProductListItem content into separate components to allow creating a ‘real’ product item and a skeleton item without duplicating code --- .changeset/tall-candles-watch.md | 6 + .../ProductListItems/productListRenderer.tsx | 7 +- .../ProductListItem/ProductDiscountLabel.tsx | 34 ++ .../ProductListItem/ProductListItem.tsx | 327 ++++++------------ .../ProductListItem/ProductListItemImage.tsx | 96 +++++ .../ProductListItemImageContainer.tsx | 97 ++++++ .../ProductListItemLinkOrDiv.tsx | 34 ++ .../ProductListItemTitleAndPrice.tsx | 64 ++++ .../components/ProductListItems/renderer.tsx | 7 +- .../ProductListPrice/ProductListPrice.tsx | 4 +- 10 files changed, 458 insertions(+), 218 deletions(-) create mode 100644 .changeset/tall-candles-watch.md create mode 100644 packages/magento-product/components/ProductListItem/ProductDiscountLabel.tsx create mode 100644 packages/magento-product/components/ProductListItem/ProductListItemImage.tsx create mode 100644 packages/magento-product/components/ProductListItem/ProductListItemImageContainer.tsx create mode 100644 packages/magento-product/components/ProductListItem/ProductListItemLinkOrDiv.tsx create mode 100644 packages/magento-product/components/ProductListItem/ProductListItemTitleAndPrice.tsx diff --git a/.changeset/tall-candles-watch.md b/.changeset/tall-candles-watch.md new file mode 100644 index 0000000000..28bf41b058 --- /dev/null +++ b/.changeset/tall-candles-watch.md @@ -0,0 +1,6 @@ +--- +'@graphcommerce/magento-graphcms': patch +'@graphcommerce/magento-product': patch +--- + +Added Skeleton render type to productListRenderer diff --git a/examples/magento-graphcms/components/ProductListItems/productListRenderer.tsx b/examples/magento-graphcms/components/ProductListItems/productListRenderer.tsx index 1b0315c5f2..fd705e8cec 100644 --- a/examples/magento-graphcms/components/ProductListItems/productListRenderer.tsx +++ b/examples/magento-graphcms/components/ProductListItems/productListRenderer.tsx @@ -1,4 +1,8 @@ -import { AddProductsToCartFab, ProductListItemRenderer } from '@graphcommerce/magento-product' +import { + AddProductsToCartFab, + ProductListItem, + ProductListItemRenderer, +} from '@graphcommerce/magento-product' import { ProductListItemBundle } from '@graphcommerce/magento-product-bundle' import { ProductListItemConfigurable } from '@graphcommerce/magento-product-configurable' import { ProductListItemDownloadable } from '@graphcommerce/magento-product-downloadable' @@ -9,6 +13,7 @@ import { ProductReviewSummary } from '@graphcommerce/magento-review' import { ProductWishlistChip } from '@graphcommerce/magento-wishlist' export const productListRenderer: ProductListItemRenderer = { + Skeleton: (props) => , SimpleProduct: (props) => { const { sku } = props return ( diff --git a/packages/magento-product/components/ProductListItem/ProductDiscountLabel.tsx b/packages/magento-product/components/ProductListItem/ProductDiscountLabel.tsx new file mode 100644 index 0000000000..48fe25ad5f --- /dev/null +++ b/packages/magento-product/components/ProductListItem/ProductDiscountLabel.tsx @@ -0,0 +1,34 @@ +import { useNumberFormat } from '@graphcommerce/next-ui' +import { Box, BoxProps } from '@mui/material' +import { ProductListItemFragment } from '../../Api/ProductListItem.gql' + +export type ProductDiscountLabelProps = Pick & + Omit + +export function ProductDiscountLabel(props: ProductDiscountLabelProps) { + const { price_range, ...boxProps } = props + const formatter = useNumberFormat({ style: 'percent', maximumFractionDigits: 1 }) + const discount = Math.floor(price_range.minimum_price.discount?.percent_off ?? 0) + + return ( + <> + {discount > 0 && ( + + {formatter.format(discount / -100)} + + )} + + ) +} diff --git a/packages/magento-product/components/ProductListItem/ProductListItem.tsx b/packages/magento-product/components/ProductListItem/ProductListItem.tsx index 21c39bc1d2..d07b2de4f4 100644 --- a/packages/magento-product/components/ProductListItem/ProductListItem.tsx +++ b/packages/magento-product/components/ProductListItem/ProductListItem.tsx @@ -1,24 +1,27 @@ -import { Image, ImageProps } from '@graphcommerce/image' -import { - responsiveVal, - extendableComponent, - useNumberFormat, - breakpointVal, -} from '@graphcommerce/next-ui' -import { Trans } from '@lingui/react' -import { - ButtonBase, - Typography, - Box, - styled, - SxProps, - Theme, - useEventCallback, -} from '@mui/material' +import { ImageProps } from '@graphcommerce/image' +import { extendableComponent } from '@graphcommerce/next-ui' +import { SxProps, Theme, useEventCallback, Skeleton } from '@mui/material' import React from 'react' import { ProductListItemFragment } from '../../Api/ProductListItem.gql' -import { useProductLink } from '../../hooks/useProductLink' +import { productLink } from '../../hooks/useProductLink' import { ProductListPrice } from '../ProductListPrice/ProductListPrice' +import { ProductDiscountLabel } from './ProductDiscountLabel' +import { + ProductListItemImageProps, + ProductListItemImage, + ProductListItemImageSkeleton, +} from './ProductListItemImage' +import { + ProductListItemImageAreaKeys, + ProductListsItemImageAreaProps, + ProductListItemImageAreas, + ProductImageContainer, +} from './ProductListItemImageContainer' +import * as ProductListItemLinkOrDiv from './ProductListItemLinkOrDiv' +import { + ProductListItemTitleAndPrice, + ProductListItemTitleAndPriceProps, +} from './ProductListItemTitleAndPrice' const { classes, selectors } = extendableComponent('ProductListItem', [ 'root', @@ -38,29 +41,30 @@ const { classes, selectors } = extendableComponent('ProductListItem', [ 'discount', ] as const) -export type OverlayAreaKeys = 'topLeft' | 'bottomLeft' | 'topRight' | 'bottomRight' - -export type OverlayAreas = Partial> - type StyleProps = { - aspectRatio?: [number, number] imageOnly?: boolean } -type BaseProps = { subTitle?: React.ReactNode; children?: React.ReactNode } & StyleProps & - OverlayAreas & - ProductListItemFragment & - Pick - -export type ProductListItemProps = BaseProps & { +type BaseProps = { + imageOnly?: boolean + children?: React.ReactNode sx?: SxProps - titleComponent?: React.ElementType + // eslint-disable-next-line react/no-unused-prop-types onClick?: (event: React.MouseEvent, item: ProductListItemFragment) => void -} +} & StyleProps & + Omit & + Omit & + Omit & + Pick -const StyledImage = styled(Image)({}) +// eslint-disable-next-line react/no-unused-prop-types +type SkeletonProps = BaseProps & { __typename: 'Skeleton' } -export function ProductListItem(props: ProductListItemProps) { +type ProductProps = BaseProps & ProductListItemFragment + +export type ProductListItemProps = ProductProps | SkeletonProps + +export function ProductListItemReal(props: ProductProps) { const { subTitle, topLeft, @@ -85,202 +89,97 @@ export function ProductListItem(props: ProductListItemProps) { (e: React.MouseEvent) => onClick?.(e, props), ) - const productLink = useProductLink(props) - const discount = Math.floor(price_range.minimum_price.discount?.percent_off ?? 0) - - const formatter = useNumberFormat({ style: 'percent', maximumFractionDigits: 1 }) - return ( - ({ - display: 'block', - position: 'relative', - height: '100%', - ...breakpointVal( - 'borderRadius', - theme.shape.borderRadius * 2, - theme.shape.borderRadius * 3, - theme.breakpoints.values, - ), - }), - ...(Array.isArray(sx) ? sx : [sx]), - ]} + - ({ - display: 'grid', - bgcolor: 'background.image', - ...breakpointVal( - 'borderRadius', - theme.shape.borderRadius * 2, - theme.shape.borderRadius * 3, - theme.breakpoints.values, - ), - overflow: 'hidden', - padding: responsiveVal(8, 12), - '& > picture': { - gridArea: `1 / 1 / 3 / 3`, - margin: `calc(${responsiveVal(8, 12)} * -1)`, - }, - })} - className={classes.imageContainer} - > - {small_image ? ( - - ) : ( - - - - )} + + {!imageOnly && ( - <> - - {discount > 0 && ( - - {formatter.format(discount / -100)} - - )} - {topLeft} - - - {topRight} - - - {bottomLeft} - - - {bottomRight} - - + + + {topLeft} + + } + /> )} - + {!imageOnly && ( <> - ({ - display: 'grid', - alignItems: 'baseline', - marginTop: theme.spacings.xs, - columnGap: 1, - gridTemplateAreas: { - xs: `"title title" "subtitle price"`, - md: `"title subtitle price"`, - }, - gridTemplateColumns: { xs: 'unset', md: 'auto auto 1fr' }, - justifyContent: 'space-between', - })} + - - {name} - - - {subTitle} - + + + {children} + + )} + + ) +} + +export function ProductListItemSkeleton(props: SkeletonProps) { + const { children, imageOnly = false, aspectRatio, titleComponent = 'h2', sx = [] } = props + + return ( + + + + - - + {!imageOnly && ( + <> + } + subTitle={} + > + + {children} )} - + + ) +} + +function isSkeleton(props: ProductListItemProps): props is SkeletonProps { + return props.__typename === 'Skeleton' +} +export function ProductListItem(props: ProductListItemProps) { + return isSkeleton(props) ? ( + + ) : ( + ) } ProductListItem.selectors = { ...selectors, ...ProductListPrice.selectors } + +/** @deprecated */ +export type OverlayAreaKeys = ProductListItemImageAreaKeys +/** @deprecated */ +export type OverlayAreas = ProductListsItemImageAreaProps diff --git a/packages/magento-product/components/ProductListItem/ProductListItemImage.tsx b/packages/magento-product/components/ProductListItem/ProductListItemImage.tsx new file mode 100644 index 0000000000..a5c705f741 --- /dev/null +++ b/packages/magento-product/components/ProductListItem/ProductListItemImage.tsx @@ -0,0 +1,96 @@ +import { Image, ImageProps } from '@graphcommerce/image' +import { Trans } from '@lingui/react' +import { Box, BoxProps, Skeleton, styled } from '@mui/material' + +const StyledImage = styled(Image)({}) + +function PlaceHolderContainer(props: BoxProps) { + return ( + + ) +} + +export type ProductListItemImageProps = { + aspectRatio?: [number, number] + classes: { + image?: string + placeholder?: string + } +} + +export function ProductListItemImageSkeleton(props: ProductListItemImageProps) { + const { aspectRatio = [4, 3], classes } = props + return ( + + + + ) +} + +type ImageOrPlaceholderProps = ProductListItemImageProps & + Omit & { + alt?: ImageProps['alt'] | null + src?: ImageProps['src'] | null + } + +export function ProductListItemImage(props: ImageOrPlaceholderProps) { + const { aspectRatio = [4, 3], classes, src, alt, sx = [], ...image } = props + + if (src) { + return ( + + ) + } + + return ( + + + + + + ) +} diff --git a/packages/magento-product/components/ProductListItem/ProductListItemImageContainer.tsx b/packages/magento-product/components/ProductListItem/ProductListItemImageContainer.tsx new file mode 100644 index 0000000000..066c1fec06 --- /dev/null +++ b/packages/magento-product/components/ProductListItem/ProductListItemImageContainer.tsx @@ -0,0 +1,97 @@ +import { responsiveVal, breakpointVal } from '@graphcommerce/next-ui' +import { Box, BoxProps } from '@mui/material' + +type ProductImageContainerProps = BoxProps + +export function ProductImageContainer(props: ProductImageContainerProps) { + const { sx = [] } = props + + return ( + ({ + display: 'grid', + bgcolor: 'background.image', + ...breakpointVal( + 'borderRadius', + theme.shape.borderRadius * 2, + theme.shape.borderRadius * 3, + theme.breakpoints.values, + ), + overflow: 'hidden', + padding: responsiveVal(8, 12), + '& > picture, & > .ProductListItem-placeholder': { + gridArea: `1 / 1 / 3 / 3`, + margin: `calc(${responsiveVal(8, 12)} * -1)`, + height: 'auto', + }, + }), + ...(Array.isArray(sx) ? sx : [sx]), + ]} + /> + ) +} + +export type ProductListItemImageAreaKeys = 'topLeft' | 'bottomLeft' | 'topRight' | 'bottomRight' +export type ProductListsItemImageAreaProps = Partial< + Record +> & { + classes: { + topLeft?: string + topRight?: string + bottomLeft?: string + bottomRight?: string + } +} + +export function ProductListItemImageAreas(props: ProductListsItemImageAreaProps) { + const { topLeft, topRight, bottomLeft, bottomRight, classes } = props + + return ( + <> + + {topLeft} + + + {topRight} + + + {bottomLeft} + + + {bottomRight} + + + ) +} diff --git a/packages/magento-product/components/ProductListItem/ProductListItemLinkOrDiv.tsx b/packages/magento-product/components/ProductListItem/ProductListItemLinkOrDiv.tsx new file mode 100644 index 0000000000..d0bbdb04ed --- /dev/null +++ b/packages/magento-product/components/ProductListItem/ProductListItemLinkOrDiv.tsx @@ -0,0 +1,34 @@ +import { breakpointVal } from '@graphcommerce/next-ui' +import { Box, BoxProps, ButtonBase, ButtonBaseProps, SxProps, Theme } from '@mui/material' + +type ProductListItemLinkProps = ButtonBaseProps<'a'> +type ProductListItemLinkOrDivProps = ProductListItemLinkProps | BoxProps + +function isLink(props: ProductListItemLinkOrDivProps): props is ProductListItemLinkProps { + return 'href' in props +} + +export function ProductListItemLinkOrDiv(props: ProductListItemLinkOrDivProps) { + const { sx = [] } = props + + const sxProps: SxProps = [ + (theme) => ({ + display: 'block', + position: 'relative', + height: '100%', + ...breakpointVal( + 'borderRadius', + theme.shape.borderRadius * 2, + theme.shape.borderRadius * 3, + theme.breakpoints.values, + ), + }), + ...(Array.isArray(sx) ? sx : [sx]), + ] + + return isLink(props) ? ( + + ) : ( + + ) +} diff --git a/packages/magento-product/components/ProductListItem/ProductListItemTitleAndPrice.tsx b/packages/magento-product/components/ProductListItem/ProductListItemTitleAndPrice.tsx new file mode 100644 index 0000000000..89dd182d4b --- /dev/null +++ b/packages/magento-product/components/ProductListItem/ProductListItemTitleAndPrice.tsx @@ -0,0 +1,64 @@ +import { Box, Typography } from '@mui/material' +import { productListPrice } from '../ProductListPrice' + +export type ProductListItemTitleAndPriceProps = { + titleComponent?: React.ElementType + title: React.ReactNode + subTitle?: React.ReactNode + children: React.ReactNode + classes: { titleContainer: string; title: string; subtitle: string } +} + +export function ProductListItemTitleAndPrice(props: ProductListItemTitleAndPriceProps) { + const { titleComponent = 'h2', classes, children, subTitle, title } = props + + return ( + ({ + display: 'grid', + alignItems: 'baseline', + marginTop: theme.spacings.xs, + columnGap: 1, + gridTemplateAreas: { + xs: `"title title" "subtitle price"`, + md: `"title subtitle price"`, + }, + gridTemplateColumns: { xs: 'unset', md: 'auto auto 1fr' }, + justifyContent: 'space-between', + })} + > + + {title} + + + {subTitle && ( + + {subTitle} + + )} + + + {children} + + + ) +} diff --git a/packages/magento-product/components/ProductListItems/renderer.tsx b/packages/magento-product/components/ProductListItems/renderer.tsx index 4dcaef8eb1..51ed03942f 100644 --- a/packages/magento-product/components/ProductListItems/renderer.tsx +++ b/packages/magento-product/components/ProductListItems/renderer.tsx @@ -1,10 +1,13 @@ import { TypeRenderer } from '@graphcommerce/next-ui' import { ProductListItemFragment } from '../../Api/ProductListItem.gql' -import { ProductListItem } from '../ProductListItem/ProductListItem' +import { ProductListItem, ProductListItemSkeleton } from '../ProductListItem/ProductListItem' -export type ProductListItemRenderer = TypeRenderer +type SkeletonType = { __typename: 'Skeleton'; uid: string } +export type ProductListItemType = ProductListItemFragment | SkeletonType +export type ProductListItemRenderer = TypeRenderer export const renderer: ProductListItemRenderer = { + Skeleton: ProductListItemSkeleton, SimpleProduct: ProductListItem, ConfigurableProduct: ProductListItem, BundleProduct: ProductListItem, diff --git a/packages/magento-product/components/ProductListPrice/ProductListPrice.tsx b/packages/magento-product/components/ProductListPrice/ProductListPrice.tsx index 9504b0d787..4371e4f6f9 100644 --- a/packages/magento-product/components/ProductListPrice/ProductListPrice.tsx +++ b/packages/magento-product/components/ProductListPrice/ProductListPrice.tsx @@ -3,11 +3,13 @@ import { extendableComponent } from '@graphcommerce/next-ui' import { Typography, TypographyProps, Box } from '@mui/material' import { ProductListPriceFragment } from './ProductListPrice.gql' -const { classes, selectors } = extendableComponent('ProductListPrice', [ +export const productListPrice = extendableComponent('ProductListPrice', [ 'root', 'discountPrice', ] as const) +const { classes, selectors } = productListPrice + export type ProductListPriceProps = ProductListPriceFragment & Pick export function ProductListPrice(props: ProductListPriceProps) { From 63256c78e58f988acb8715493434f624d795bdf3 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 2 Nov 2023 11:43:07 +0100 Subject: [PATCH 35/47] Use PascalCase for vendor prefixed css MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes error: “Using kebab-case for css properties in objects is not supported.” --- .../components/FormComponents/NumberFieldElement.tsx | 2 +- packages/next-ui/TextInputNumber/TextInputNumber.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ecommerce-ui/components/FormComponents/NumberFieldElement.tsx b/packages/ecommerce-ui/components/FormComponents/NumberFieldElement.tsx index c2df5a756f..bdcbef496f 100644 --- a/packages/ecommerce-ui/components/FormComponents/NumberFieldElement.tsx +++ b/packages/ecommerce-ui/components/FormComponents/NumberFieldElement.tsx @@ -81,7 +81,7 @@ export function NumberFieldElement(props: NumberFieldElem }, { '& input[type=number]': { - '-moz-appearance': 'textfield', + MozAppearance: 'textfield', }, '& .MuiOutlinedInput-root': { px: '2px', diff --git a/packages/next-ui/TextInputNumber/TextInputNumber.tsx b/packages/next-ui/TextInputNumber/TextInputNumber.tsx index 0193c2b853..85089b463f 100644 --- a/packages/next-ui/TextInputNumber/TextInputNumber.tsx +++ b/packages/next-ui/TextInputNumber/TextInputNumber.tsx @@ -103,7 +103,7 @@ export function TextInputNumber(props: TextInputNumberProps) { }, { '& input[type=number]': { - '-moz-appearance': 'textfield', + MozAppearance: 'textfield', }, '& .MuiOutlinedInput-root': { px: '3px', From 89035fd8ee61710da8e0fbaa170e97fb1162adc8 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 2 Nov 2023 11:46:29 +0100 Subject: [PATCH 36/47] Removed skeleton renderer from ProductScroller and implemented productListRenderer skeleton --- .../ProductScroller/ProductScroller.tsx | 45 ++----------------- .../components/RecentlyViewedProducts.tsx | 8 +++- 2 files changed, 9 insertions(+), 44 deletions(-) diff --git a/packages/magento-product/components/ProductScroller/ProductScroller.tsx b/packages/magento-product/components/ProductScroller/ProductScroller.tsx index c7e0e5dd2d..bae39a6d27 100644 --- a/packages/magento-product/components/ProductScroller/ProductScroller.tsx +++ b/packages/magento-product/components/ProductScroller/ProductScroller.tsx @@ -3,7 +3,6 @@ import { Box, Container, ContainerProps, - Skeleton, SxProps, Theme, Typography, @@ -11,48 +10,19 @@ import { useTheme, } from '@mui/material' import React, { forwardRef, useContext } from 'react' -import { ProductListItemFragment } from '../../Api/ProductListItem.gql' import { AddProductsToCartContext, AddProductsToCartForm, AddProductsToCartFormProps, } from '../AddProductsToCart' import { ProductListItemProps } from '../ProductListItem/ProductListItem' -import { ProductListItemRenderer } from '../ProductListItems/renderer' - -export function ProductScrollerItemSkeleton({ imageOnly = false }: { imageOnly?: boolean }) { - return ( - - - - {!imageOnly && ( - ({ - marginTop: theme.spacings.xs, - display: 'block', - color: 'text.primary', - overflowWrap: 'break-word', - wordBreak: 'break-all', - maxWidth: '100%', - gridArea: 'title', - fontWeight: 'fontWeightBold', - })} - > -   - - )} - - ) -} +import { ProductListItemRenderer, ProductListItemType } from '../ProductListItems/renderer' export type ProductScrollerProps = { title?: string - items: ProductListItemFragment[] + items: ProductListItemType[] productListRenderer: ProductListItemRenderer imageOnly?: ProductListItemProps['imageOnly'] - skeletonItemCount: number - skeleton?: React.ReactNode sx?: SxProps containerProps?: ContainerProps titleProps?: TypographyProps @@ -66,8 +36,6 @@ export const ProductScroller = forwardRef( items, productListRenderer, imageOnly = false, - skeletonItemCount = 0, - skeleton, sx = [], containerProps, titleProps, @@ -93,16 +61,9 @@ export const ProductScroller = forwardRef( )} - {(!!items.length || !!skeletonItemCount) && ( + {!!items.length && ( - {!items.length && - [...Array(skeletonItemCount).keys()].map((i) => ( - - {skeleton || } - - ))} - {items.map((item) => ( ({ + __typename: 'Skeleton' as const, + uid: i.toString(), + })) + return ( ) } From 34c0dfe543430103201890f98ab5bbe92127c306 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 2 Nov 2023 12:10:19 +0100 Subject: [PATCH 37/47] Added demo version of recently viewed products which uses SidebarSlider instead of ProductScroller --- .../demo-magento-graphcommerce/package.json | 5 +- .../demo/DemoRecentlyViewedProducts.tsx | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 packages/demo-magento-graphcommerce/plugins/demo/DemoRecentlyViewedProducts.tsx diff --git a/packages/demo-magento-graphcommerce/package.json b/packages/demo-magento-graphcommerce/package.json index e129e9c988..5f8c7433cb 100644 --- a/packages/demo-magento-graphcommerce/package.json +++ b/packages/demo-magento-graphcommerce/package.json @@ -21,12 +21,15 @@ }, "peerDependencies": { "@mui/material": "^5.10.16", + "framer-motion": "^10.0.0", "next": "^13.2.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, "dependencies": { "@graphcommerce/magento-product": "7.1.0-canary.30", - "@graphcommerce/magento-product-configurable": "7.1.0-canary.30" + "@graphcommerce/magento-product-configurable": "7.1.0-canary.30", + "@graphcommerce/magento-recently-viewed-products": "7.1.0-canary.30", + "@graphcommerce/next-ui": "7.1.0-canary.30" } } diff --git a/packages/demo-magento-graphcommerce/plugins/demo/DemoRecentlyViewedProducts.tsx b/packages/demo-magento-graphcommerce/plugins/demo/DemoRecentlyViewedProducts.tsx new file mode 100644 index 0000000000..34f3072960 --- /dev/null +++ b/packages/demo-magento-graphcommerce/plugins/demo/DemoRecentlyViewedProducts.tsx @@ -0,0 +1,55 @@ +import { + useRecentlyViewedProducts, + useRecentlyViewedSkus, + type RecentlyViewedProductsProps, +} from '@graphcommerce/magento-recently-viewed-products' +import type { IfConfig, PluginProps } from '@graphcommerce/next-config' +import { + SidebarSlider, + filterNonNullableKeys, + RenderType, + responsiveVal, +} from '@graphcommerce/next-ui' +import { Typography } from '@mui/material' +import { useInView } from 'framer-motion' +import { useRef } from 'react' + +export const component = 'RecentlyViewedProducts' +export const exported = '@graphcommerce/magento-recently-viewed-products' +export const ifConfig: IfConfig = 'demoMode' + +function DemoRecentlyViewedProducts(props: PluginProps) { + const { exclude, title, productListRenderer, loading = 'lazy' } = props + + const ref = useRef(null) + const isInView = useInView(ref, { margin: '300px', once: true }) + const { skus } = useRecentlyViewedSkus({ exclude }) + const productList = useRecentlyViewedProducts({ exclude, skip: !isInView && loading === 'lazy' }) + + if (!productList.loading && !skus.length) { + return null + } + + const loadingProducts = [...Array(skus.length - productList.products.length).keys()].map((i) => ({ + __typename: 'Skeleton' as const, + uid: i.toString(), + })) + + return ( + <> +
+ {title}}> + {filterNonNullableKeys([...loadingProducts, ...productList.products]).map((item) => ( + + ))} + + + ) +} +export const Plugin = DemoRecentlyViewedProducts From 2195a0c8bf560655b3809574e52606c2fe17aa7f Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 2 Nov 2023 14:16:12 +0100 Subject: [PATCH 38/47] feat(GCOM-535) Added 7 to 7.1 Hygraph migration script --- .changeset/lovely-moles-mix.md | 5 + docs/upgrading/graphcommerce-7-to-7.1.md | 6 + docs/upgrading/readme.md | 1 + packages/hygraph-cli/dist/migrationAction.js | 12 +- .../dist/migrations/graphcommerce7to7.1.js | 15 ++ packages/hygraph-cli/dist/migrations/index.js | 1 + .../src/migrations/graphcommerce7to7.1.ts | 15 ++ packages/hygraph-cli/src/migrations/index.ts | 1 + .../next-config/dist/generated/config.js | 169 +++++++----------- 9 files changed, 120 insertions(+), 105 deletions(-) create mode 100644 .changeset/lovely-moles-mix.md create mode 100644 docs/upgrading/graphcommerce-7-to-7.1.md create mode 100644 packages/hygraph-cli/dist/migrations/graphcommerce7to7.1.js create mode 100644 packages/hygraph-cli/src/migrations/graphcommerce7to7.1.ts diff --git a/.changeset/lovely-moles-mix.md b/.changeset/lovely-moles-mix.md new file mode 100644 index 0000000000..29e93308ea --- /dev/null +++ b/.changeset/lovely-moles-mix.md @@ -0,0 +1,5 @@ +--- +'@graphcommerce/hygraph-cli': patch +--- + +Added 7 to 7.1 Hygraph migration script diff --git a/docs/upgrading/graphcommerce-7-to-7.1.md b/docs/upgrading/graphcommerce-7-to-7.1.md new file mode 100644 index 0000000000..a1c151ceb5 --- /dev/null +++ b/docs/upgrading/graphcommerce-7-to-7.1.md @@ -0,0 +1,6 @@ +# Upgrading from GraphCommerce 7 to 7.1 + +## Upgrading your Hygraph schema + +Upgrade your Hygraph schema with the [Hygraph migration cli](../hygraph/cli.md). +Select `graphcommerce7to7_1` as version. diff --git a/docs/upgrading/readme.md b/docs/upgrading/readme.md index c7ff461cee..4d3195d466 100644 --- a/docs/upgrading/readme.md +++ b/docs/upgrading/readme.md @@ -108,6 +108,7 @@ After resolving the diff issues, manually process upgrade instructions: - [Upgrading to GraphCommerce 5 to 6](../upgrading/graphcommerce-5-to-6.md) - [Upgrading to GraphCommerce 6 to 7](../upgrading/graphcommerce-6-to-7.md) +- [Upgrading to GraphCommerce 7 to 7.1](../upgrading/graphcommerce-7-to-7.1.md) Run and validate your local environment: diff --git a/packages/hygraph-cli/dist/migrationAction.js b/packages/hygraph-cli/dist/migrationAction.js index 2d224cf30a..0cb4e0f8de 100644 --- a/packages/hygraph-cli/dist/migrationAction.js +++ b/packages/hygraph-cli/dist/migrationAction.js @@ -74,8 +74,14 @@ const actionMap = exports.client * component, you also need to pass the parentType, which is either 'model' or 'component'. */ const migrationAction = (schema, type, action, props, parentApiId, parentType) => { - // Check if the entity already exists + /** + * Check if the entity already exists. + * If an update or deletion is made, it does not matter if the entity already exists + */ const alreadyExists = () => { + if (action !== 'create') { + return false; + } switch (type) { case 'model': return schema.models.some((model) => model.apiId === props.apiId); @@ -99,12 +105,12 @@ const migrationAction = (schema, type, action, props, parentApiId, parentType) = break; } default: - return false; // or undefined or any other value you want if no match + return false; } return parent?.fields.some((field) => field.apiId === props.apiId); } default: { - return false; // or undefined or any other value you want if no match + return false; } } }; diff --git a/packages/hygraph-cli/dist/migrations/graphcommerce7to7.1.js b/packages/hygraph-cli/dist/migrations/graphcommerce7to7.1.js new file mode 100644 index 0000000000..2f4f4c6f40 --- /dev/null +++ b/packages/hygraph-cli/dist/migrations/graphcommerce7to7.1.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.graphcommerce7to7_1 = void 0; +const migrationAction_1 = require("../migrationAction"); +const graphcommerce7to7_1 = async (schema) => { + if (!migrationAction_1.client) { + return 0; + } + (0, migrationAction_1.migrationAction)(schema, 'enumeration', 'update', { + apiId: 'RowProductVariants', + valuesToCreate: [{ apiId: 'Recent', displayName: 'Recent' }], + }); + return migrationAction_1.client.run(true); +}; +exports.graphcommerce7to7_1 = graphcommerce7to7_1; diff --git a/packages/hygraph-cli/dist/migrations/index.js b/packages/hygraph-cli/dist/migrations/index.js index 359a8699ab..2ca36a87ca 100644 --- a/packages/hygraph-cli/dist/migrations/index.js +++ b/packages/hygraph-cli/dist/migrations/index.js @@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) { Object.defineProperty(exports, "__esModule", { value: true }); __exportStar(require("./graphcommerce5to6"), exports); __exportStar(require("./graphcommerce6to7"), exports); +__exportStar(require("./graphcommerce7to7.1"), exports); diff --git a/packages/hygraph-cli/src/migrations/graphcommerce7to7.1.ts b/packages/hygraph-cli/src/migrations/graphcommerce7to7.1.ts new file mode 100644 index 0000000000..9caea558e4 --- /dev/null +++ b/packages/hygraph-cli/src/migrations/graphcommerce7to7.1.ts @@ -0,0 +1,15 @@ +import { migrationAction, client } from '../migrationAction' +import { Schema } from '../types' + +export const graphcommerce7to7_1 = async (schema: Schema) => { + if (!client) { + return 0 + } + + migrationAction(schema, 'enumeration', 'update', { + apiId: 'RowProductVariants', + valuesToCreate: [{ apiId: 'Recent', displayName: 'Recent' }], + }) + + return client.run(true) +} diff --git a/packages/hygraph-cli/src/migrations/index.ts b/packages/hygraph-cli/src/migrations/index.ts index 1054c496f0..375a873d8b 100644 --- a/packages/hygraph-cli/src/migrations/index.ts +++ b/packages/hygraph-cli/src/migrations/index.ts @@ -1,2 +1,3 @@ export * from './graphcommerce5to6' export * from './graphcommerce6to7' +export * from './graphcommerce7to7.1' diff --git a/packagesDev/next-config/dist/generated/config.js b/packagesDev/next-config/dist/generated/config.js index bffe36df38..34ba254db7 100644 --- a/packagesDev/next-config/dist/generated/config.js +++ b/packagesDev/next-config/dist/generated/config.js @@ -1,120 +1,85 @@ -/* eslint-disable */ "use strict"; -Object.defineProperty(exports, "__esModule", { - value: true -}); -function _export(target, all) { - for(var name in all)Object.defineProperty(target, name, { - enumerable: true, - get: all[name] - }); -} -_export(exports, { - isDefinedNonNullAny: function() { - return isDefinedNonNullAny; - }, - definedNonNullAnySchema: function() { - return definedNonNullAnySchema; - }, - CompareVariantSchema: function() { - return CompareVariantSchema; - }, - ProductFiltersLayoutSchema: function() { - return ProductFiltersLayoutSchema; - }, - GraphCommerceConfigSchema: function() { - return GraphCommerceConfigSchema; - }, - GraphCommerceDebugConfigSchema: function() { - return GraphCommerceDebugConfigSchema; - }, - GraphCommerceStorefrontConfigSchema: function() { - return GraphCommerceStorefrontConfigSchema; - }, - MagentoConfigurableVariantValuesSchema: function() { - return MagentoConfigurableVariantValuesSchema; - }, - RecentlyViewedProductsConfgSchema: function() { - return RecentlyViewedProductsConfgSchema; - } -}); -const _zod = require("zod"); -const isDefinedNonNullAny = (v)=>v !== undefined && v !== null; -const definedNonNullAnySchema = _zod.z.any().refine((v)=>isDefinedNonNullAny(v)); -const CompareVariantSchema = _zod.z.enum([ - "CHECKBOX", - "ICON" -]); -const ProductFiltersLayoutSchema = _zod.z.enum([ - "DEFAULT", - "SIDEBAR" -]); +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RecentlyViewedProductsConfgSchema = exports.MagentoConfigurableVariantValuesSchema = exports.GraphCommerceStorefrontConfigSchema = exports.GraphCommerceDebugConfigSchema = exports.GraphCommerceConfigSchema = exports.ProductFiltersLayoutSchema = exports.CompareVariantSchema = exports.definedNonNullAnySchema = exports.isDefinedNonNullAny = void 0; +/* eslint-disable */ +const zod_1 = require("zod"); +const isDefinedNonNullAny = (v) => v !== undefined && v !== null; +exports.isDefinedNonNullAny = isDefinedNonNullAny; +exports.definedNonNullAnySchema = zod_1.z.any().refine((v) => (0, exports.isDefinedNonNullAny)(v)); +exports.CompareVariantSchema = zod_1.z.enum(['CHECKBOX', 'ICON']); +exports.ProductFiltersLayoutSchema = zod_1.z.enum(['DEFAULT', 'SIDEBAR']); function GraphCommerceConfigSchema() { - return _zod.z.object({ - canonicalBaseUrl: _zod.z.string().min(1), - cartDisplayPricesInclTax: _zod.z.boolean().nullish(), - compare: _zod.z.boolean().nullish(), - compareVariant: CompareVariantSchema.nullish(), - configurableVariantForSimple: _zod.z.boolean().nullish(), + return zod_1.z.object({ + canonicalBaseUrl: zod_1.z.string().min(1), + cartDisplayPricesInclTax: zod_1.z.boolean().nullish(), + compare: zod_1.z.boolean().nullish(), + compareVariant: exports.CompareVariantSchema.nullish(), + configurableVariantForSimple: zod_1.z.boolean().nullish(), configurableVariantValues: MagentoConfigurableVariantValuesSchema().nullish(), - crossSellsHideCartItems: _zod.z.boolean().nullish(), - crossSellsRedirectItems: _zod.z.boolean().nullish(), - customerRequireEmailConfirmation: _zod.z.boolean().nullish(), + crossSellsHideCartItems: zod_1.z.boolean().nullish(), + crossSellsRedirectItems: zod_1.z.boolean().nullish(), + customerRequireEmailConfirmation: zod_1.z.boolean().nullish(), debug: GraphCommerceDebugConfigSchema().nullish(), - demoMode: _zod.z.boolean().nullish(), - googleAnalyticsId: _zod.z.string().nullish(), - googleRecaptchaKey: _zod.z.string().nullish(), - googleTagmanagerId: _zod.z.string().nullish(), - hygraphEndpoint: _zod.z.string().min(1), - hygraphProjectId: _zod.z.string().nullish(), - hygraphWriteAccessEndpoint: _zod.z.string().nullish(), - hygraphWriteAccessToken: _zod.z.string().nullish(), - legacyProductRoute: _zod.z.boolean().nullish(), - limitSsg: _zod.z.boolean().nullish(), - magentoEndpoint: _zod.z.string().min(1), - previewSecret: _zod.z.string().nullish(), - productFiltersLayout: ProductFiltersLayoutSchema.nullish(), - productFiltersPro: _zod.z.boolean().nullish(), - productRoute: _zod.z.string().nullish(), + demoMode: zod_1.z.boolean().nullish(), + googleAnalyticsId: zod_1.z.string().nullish(), + googleRecaptchaKey: zod_1.z.string().nullish(), + googleTagmanagerId: zod_1.z.string().nullish(), + hygraphEndpoint: zod_1.z.string().min(1), + hygraphProjectId: zod_1.z.string().nullish(), + hygraphWriteAccessEndpoint: zod_1.z.string().nullish(), + hygraphWriteAccessToken: zod_1.z.string().nullish(), + legacyProductRoute: zod_1.z.boolean().nullish(), + limitSsg: zod_1.z.boolean().nullish(), + magentoEndpoint: zod_1.z.string().min(1), + previewSecret: zod_1.z.string().nullish(), + productFiltersLayout: exports.ProductFiltersLayoutSchema.nullish(), + productFiltersPro: zod_1.z.boolean().nullish(), + productRoute: zod_1.z.string().nullish(), recentlyViewedProducts: RecentlyViewedProductsConfgSchema().nullish(), - robotsAllow: _zod.z.boolean().nullish(), - storefront: _zod.z.array(GraphCommerceStorefrontConfigSchema()), - wishlistHideForGuests: _zod.z.boolean().nullish(), - wishlistIgnoreProductWishlistStatus: _zod.z.boolean().nullish(), - wishlistShowFeedbackMessage: _zod.z.boolean().nullish() + robotsAllow: zod_1.z.boolean().nullish(), + storefront: zod_1.z.array(GraphCommerceStorefrontConfigSchema()), + wishlistHideForGuests: zod_1.z.boolean().nullish(), + wishlistIgnoreProductWishlistStatus: zod_1.z.boolean().nullish(), + wishlistShowFeedbackMessage: zod_1.z.boolean().nullish() }); } +exports.GraphCommerceConfigSchema = GraphCommerceConfigSchema; function GraphCommerceDebugConfigSchema() { - return _zod.z.object({ - pluginStatus: _zod.z.boolean().nullish(), - webpackCircularDependencyPlugin: _zod.z.boolean().nullish(), - webpackDuplicatesPlugin: _zod.z.boolean().nullish() + return zod_1.z.object({ + pluginStatus: zod_1.z.boolean().nullish(), + webpackCircularDependencyPlugin: zod_1.z.boolean().nullish(), + webpackDuplicatesPlugin: zod_1.z.boolean().nullish() }); } +exports.GraphCommerceDebugConfigSchema = GraphCommerceDebugConfigSchema; function GraphCommerceStorefrontConfigSchema() { - return _zod.z.object({ - canonicalBaseUrl: _zod.z.string().nullish(), - cartDisplayPricesInclTax: _zod.z.boolean().nullish(), - defaultLocale: _zod.z.boolean().nullish(), - domain: _zod.z.string().nullish(), - googleAnalyticsId: _zod.z.string().nullish(), - googleRecaptchaKey: _zod.z.string().nullish(), - googleTagmanagerId: _zod.z.string().nullish(), - hygraphLocales: _zod.z.array(_zod.z.string().min(1)).nullish(), - linguiLocale: _zod.z.string().nullish(), - locale: _zod.z.string().min(1), - magentoStoreCode: _zod.z.string().min(1) + return zod_1.z.object({ + canonicalBaseUrl: zod_1.z.string().nullish(), + cartDisplayPricesInclTax: zod_1.z.boolean().nullish(), + defaultLocale: zod_1.z.boolean().nullish(), + domain: zod_1.z.string().nullish(), + googleAnalyticsId: zod_1.z.string().nullish(), + googleRecaptchaKey: zod_1.z.string().nullish(), + googleTagmanagerId: zod_1.z.string().nullish(), + hygraphLocales: zod_1.z.array(zod_1.z.string().min(1)).nullish(), + linguiLocale: zod_1.z.string().nullish(), + locale: zod_1.z.string().min(1), + magentoStoreCode: zod_1.z.string().min(1) }); } +exports.GraphCommerceStorefrontConfigSchema = GraphCommerceStorefrontConfigSchema; function MagentoConfigurableVariantValuesSchema() { - return _zod.z.object({ - content: _zod.z.boolean().nullish(), - gallery: _zod.z.boolean().nullish(), - url: _zod.z.boolean().nullish() + return zod_1.z.object({ + content: zod_1.z.boolean().nullish(), + gallery: zod_1.z.boolean().nullish(), + url: zod_1.z.boolean().nullish() }); } +exports.MagentoConfigurableVariantValuesSchema = MagentoConfigurableVariantValuesSchema; function RecentlyViewedProductsConfgSchema() { - return _zod.z.object({ - enabled: _zod.z.boolean().nullish(), - maxCount: _zod.z.number().nullish() + return zod_1.z.object({ + enabled: zod_1.z.boolean().nullish(), + maxCount: zod_1.z.number().nullish() }); } +exports.RecentlyViewedProductsConfgSchema = RecentlyViewedProductsConfgSchema; From b3efcd2baf981d10ca2d1120bd0c681d2295cbbc Mon Sep 17 00:00:00 2001 From: Paul Hachmang Date: Wed, 8 Nov 2023 12:26:00 +0100 Subject: [PATCH 39/47] Fix issue where the generated config docs were unclear. --- docs/framework/config.md | 112 ++++++------ .../demo-magento-graphcommerce/package.json | 6 +- .../Config.graphqls | 3 + .../dist/index.js | 40 +++-- .../src/index.ts | 44 +++-- .../next-config/dist/config/demoConfig.js | 1 + .../next-config/dist/generated/config.js | 169 +++++++++++------- .../next-config/src/config/demoConfig.ts | 3 + .../next-config/src/generated/config.ts | 1 + 9 files changed, 237 insertions(+), 142 deletions(-) diff --git a/docs/framework/config.md b/docs/framework/config.md index 90cb9c20c4..753ff685d3 100644 --- a/docs/framework/config.md +++ b/docs/framework/config.md @@ -1,4 +1,9 @@ +### CompareVariant (enum) + +- CHECKBOX +- ICON + # GraphCommerce configuration system Global GraphCommerce configuration can be configured in your `graphcommerce.config.js` file @@ -77,7 +82,7 @@ Below is a list of all possible configurations that can be set by GraphCommerce. ### GraphCommerceConfig -#### `canonicalBaseUrl: String!` +#### canonicalBaseUrl: string! The canonical base URL is used for SEO purposes. @@ -86,7 +91,7 @@ Examples: - https://example.com/en - https://example.com/en-US -#### `hygraphEndpoint: String!` +#### hygraphEndpoint: string! The HyGraph endpoint. @@ -94,33 +99,33 @@ The HyGraph endpoint. Project settings -> API Access -> High Performance Read-only Content API -#### `magentoEndpoint: String!` +#### magentoEndpoint: string! GraphQL Magento endpoint. Examples: - https://magento2.test/graphql -#### `storefront: [[GraphCommerceStorefrontConfig](#GraphCommerceStorefrontConfig)!]!` +#### storefront: [`GraphCommerceStorefrontConfig`](#GraphCommerceStorefrontConfig)![]! All storefront configuration for the project -#### `cartDisplayPricesInclTax: Boolean` +#### cartDisplayPricesInclTax: boolean Due to a limitation of the GraphQL API it is not possible to determine if a cart should be displayed including or excluding tax. When Magento's StoreConfig adds this value, this can be replaced. -#### `compare: Boolean` +#### compare: boolean Use compare functionality -#### `compareVariant: [CompareVariant](#CompareVariant) (default: ICON)` +#### compareVariant: [`CompareVariant`](#CompareVariant) = ICON By default the compare feature is denoted with a 'compare ICON' (2 arrows facing one another). This may be fine for experienced users, but for more clarity it's also possible to present the compare feature as a CHECKBOX accompanied by the 'Compare' label -#### `configurableVariantForSimple: Boolean (default: [object Object])` +#### configurableVariantForSimple: boolean = false If a simple product is part of a Configurable product page, should the simple product be rendered as a configured option of the configurable product page? @@ -133,25 +138,25 @@ Magento also returns the Simple product and the Configurable product the simple If that is the case we render the configurable product page instead of the simple product page but the options to select the simple product are pre-selected. -#### `configurableVariantValues: [MagentoConfigurableVariantValues](#MagentoConfigurableVariantValues) (default: [object Object])` +#### configurableVariantValues: [`MagentoConfigurableVariantValues`](#MagentoConfigurableVariantValues) = { content: true, url: true } When a user selects a variant, it will switch the values on the configurable page with the values of the configured variant. Enabling options here will allow switching of those variants. -#### `crossSellsHideCartItems: Boolean (default: [object Object])` +#### crossSellsHideCartItems: boolean = false Determines if cross sell items should be shown when the user already has the product in their cart. This will result in a product will popping off the screen when you add it to the cart. Default: 'false' -#### `crossSellsRedirectItems: Boolean (default: [object Object])` +#### crossSellsRedirectItems: boolean = false Determines if, after adding a cross-sell item to the cart, the user should be redirected to the cross-sell items of the product they just added. Default: 'false' -#### `customerRequireEmailConfirmation: Boolean` +#### customerRequireEmailConfirmation: boolean Due to a limitation in the GraphQL API of Magento 2, we need to know if the customer requires email confirmation. @@ -159,11 +164,11 @@ customer requires email confirmation. This value should match Magento 2's configuration value for `customer/create_account/confirm` and should be removed once we can query -#### `debug: [GraphCommerceDebugConfig](#GraphCommerceDebugConfig)` +#### debug: [`GraphCommerceDebugConfig`](#GraphCommerceDebugConfig) Debug configuration for GraphCommerce -#### `demoMode: Boolean (default: true)` +#### demoMode: boolean = true Enables some demo specific code that is probably not useful for a project: @@ -171,7 +176,7 @@ Enables some demo specific code that is probably not useful for a project: - Adds "dominant_color" attribute swatches to the product list items. - Creates a big list items in the product list. -#### `googleAnalyticsId: String` +#### googleAnalyticsId: string See https://support.google.com/analytics/answer/9539598?hl=en @@ -179,7 +184,7 @@ Provide a value to enable Google Analytics for your store. To override the value for a specific locale, configure in i18n config. -#### `googleRecaptchaKey: String` +#### googleRecaptchaKey: string Google reCAPTCHA site key. When using reCAPTCHA, this value is required, even if you are configuring different values for each locale. @@ -189,17 +194,17 @@ Get a site key and a secret key from https://developers.google.com/recaptcha/doc The secret key should be added in the Magento admin panel (Stores > Configuration > Security > Google ReCAPTCHA Storefront > reCAPTCHA v3 Invisible) ReCAPTCHA can then be enabled/disabled for the different forms, separately (Stores > Configuration > Security > Google ReCAPTCHA Storefront > Storefront) -#### `googleTagmanagerId: String` +#### googleTagmanagerId: string The Google Tagmanager ID to be used on the site. This value is required even if you are configuring different values for each locale. -#### `hygraphProjectId: String` +#### hygraphProjectId: string Hygraph Project ID. **Only used for migrations.** -#### `hygraphWriteAccessEndpoint: String` +#### hygraphWriteAccessEndpoint: string Content API. **Only used for migrations.** @@ -207,7 +212,7 @@ Content API. **Only used for migrations.** Project settings -> API Access -> Content API -#### `hygraphWriteAccessToken: String` +#### hygraphWriteAccessToken: string Hygraph Management SDK Authorization Token. **Only used for migrations.** @@ -239,7 +244,7 @@ GC_HYGRAPH_WRITE_ACCESS_TOKEN="AccessTokenFromHygraph" yarn graphcommerce hygraph-migrate ``` -#### `legacyProductRoute: Boolean` +#### legacyProductRoute: boolean On older versions of GraphCommerce products would use a product type specific route. @@ -247,49 +252,49 @@ This should only be set to true if you use the /product/[url] AND /product/confi @deprecated Will be removed in a future version. [migration](../upgrading/graphcommerce-5-to-6.md#product-routing-changes) -#### `limitSsg: Boolean` +#### limitSsg: boolean Limit the static generation of SSG when building -#### `previewSecret: String` +#### previewSecret: string To enable next.js' preview mode, configure the secret you'd like to use. -#### `productFiltersLayout: [ProductFiltersLayout](#ProductFiltersLayout) (default: DEFAULT)` +#### productFiltersLayout: [`ProductFiltersLayout`](#ProductFiltersLayout) = DEFAULT Layout how the filters are rendered. DEFAULT: Will be rendered as horzontal chips on desktop and mobile SIDEBAR: Will be rendered as a sidebar on desktop and horizontal chips on mobile -#### `productFiltersPro: Boolean` +#### productFiltersPro: boolean Product filters with better UI for mobile and desktop. -#### `productRoute: String` +#### productRoute: string By default we route products to /p/[url] but you can change this to /product/[url] if you wish. Default: '/p/' Example: '/product/' -#### `recentlyViewedProducts: [RecentlyViewedProductsConfg](#RecentlyViewedProductsConfg)` +#### recentlyViewedProducts: [`RecentlyViewedProductsConfg`](#RecentlyViewedProductsConfg) Settings for recently viewed products -#### `robotsAllow: Boolean` +#### robotsAllow: boolean Allow the site to be indexed by search engines. If false, the robots.txt file will be set to disallow all. -#### `wishlistHideForGuests: Boolean` +#### wishlistHideForGuests: boolean Hide the wishlist functionality for guests. -#### `wishlistIgnoreProductWishlistStatus: Boolean` +#### wishlistIgnoreProductWishlistStatus: boolean Ignores whether a product is already in the wishlist, makes the toggle an add only. -#### `wishlistShowFeedbackMessage: Boolean` +#### wishlistShowFeedbackMessage: boolean Show a message when the product is added to the wishlist. @@ -297,18 +302,18 @@ Show a message when the product is added to the wishlist. Debug configuration for GraphCommerce -#### `pluginStatus: Boolean` +#### pluginStatus: boolean Reports which plugins are enabled or disabled. -#### `webpackCircularDependencyPlugin: Boolean` +#### webpackCircularDependencyPlugin: boolean Cyclic dependencies can cause memory issues and other strange bugs. This plugin will warn you when it detects a cyclic dependency. When running into memory issues, it can be useful to enable this plugin. -#### `webpackDuplicatesPlugin: Boolean` +#### webpackDuplicatesPlugin: boolean When updating packages it can happen that the same package is included with different versions in the same project. @@ -320,11 +325,11 @@ Issues that this can cause are: All storefront configuration for the project -#### `locale: String!` +#### locale: string! Must be a locale string https://www.unicode.org/reports/tr35/tr35-59/tr35.html#Identifiers -#### `magentoStoreCode: String!` +#### magentoStoreCode: string! Magento store code. @@ -335,7 +340,7 @@ Examples: - en-us - b2b-us -#### `canonicalBaseUrl: String` +#### canonicalBaseUrl: string The canonical base URL is used for SEO purposes. @@ -344,39 +349,39 @@ Examples: - https://example.com/en - https://example.com/en-US -#### `cartDisplayPricesInclTax: Boolean` +#### cartDisplayPricesInclTax: boolean Due to a limitation of the GraphQL API it is not possible to determine if a cart should be displayed including or excluding tax. -#### `defaultLocale: Boolean` +#### defaultLocale: boolean There can only be one entry with defaultLocale set to true. - If there are more, the first one is used. - If there is none, the first entry is used. -#### `domain: String` +#### domain: string Domain configuration, must be a domain https://tools.ietf.org/html/rfc3986 -#### `googleAnalyticsId: String` +#### googleAnalyticsId: string Configure different Google Analytics IDs for different locales. To disable for a specific locale, set the value to null. -#### `googleRecaptchaKey: String` +#### googleRecaptchaKey: string Locale specific google reCAPTCHA key. -#### `googleTagmanagerId: String` +#### googleTagmanagerId: string The Google Tagmanager ID to be used per locale. -#### `hygraphLocales: [String!]` +#### hygraphLocales: string![] Add a gcms-locales header to make sure queries return in a certain language, can be an array to define fallbacks. -#### `linguiLocale: String` +#### linguiLocale: string Specify a custom locale for to load translations. @@ -384,27 +389,34 @@ Specify a custom locale for to load translations. Options to configure which values will be replaced when a variant is selected on the product page. -#### `content: Boolean` +#### content: boolean Use the name, description, short description and meta data from the configured variant -#### `gallery: Boolean` +#### gallery: boolean This option enables the automatic update of product gallery images on the product page when a variant is selected, provided that the gallery images for the selected variant differ from the currently displayed images. -#### `url: Boolean` +#### url: boolean When a variant is selected the URL of the product will be changed in the address bar. This only happens when the actual variant is can be accessed by the URL. +### ProductFiltersLayout (enum) + +- DEFAULT +- SIDEBAR + ### RecentlyViewedProductsConfg -#### `enabled: Boolean` +Settings for recently viewed products + +#### enabled: boolean Enable/disable recently viewed products -#### `maxCount: Int` +#### maxCount: number Number of recently viewed products to be stored in localStorage \ No newline at end of file diff --git a/packages/demo-magento-graphcommerce/package.json b/packages/demo-magento-graphcommerce/package.json index 5f8c7433cb..6eae487cfb 100644 --- a/packages/demo-magento-graphcommerce/package.json +++ b/packages/demo-magento-graphcommerce/package.json @@ -27,9 +27,11 @@ "react-dom": "^18.2.0" }, "dependencies": { + "@graphcommerce/next-ui": "7.1.0-canary.30" + }, + "optionalDependencies": { "@graphcommerce/magento-product": "7.1.0-canary.30", "@graphcommerce/magento-product-configurable": "7.1.0-canary.30", - "@graphcommerce/magento-recently-viewed-products": "7.1.0-canary.30", - "@graphcommerce/next-ui": "7.1.0-canary.30" + "@graphcommerce/magento-recently-viewed-products": "7.1.0-canary.30" } } diff --git a/packages/magento-recently-viewed-products/Config.graphqls b/packages/magento-recently-viewed-products/Config.graphqls index c15d66fae8..5e4b2491e6 100644 --- a/packages/magento-recently-viewed-products/Config.graphqls +++ b/packages/magento-recently-viewed-products/Config.graphqls @@ -1,3 +1,6 @@ +""" +Settings for recently viewed products +""" input RecentlyViewedProductsConfg { """ Enable/disable recently viewed products diff --git a/packagesDev/graphql-codegen-markdown-docs/dist/index.js b/packagesDev/graphql-codegen-markdown-docs/dist/index.js index c07e9306e7..b450229090 100644 --- a/packagesDev/graphql-codegen-markdown-docs/dist/index.js +++ b/packagesDev/graphql-codegen-markdown-docs/dist/index.js @@ -17,7 +17,13 @@ config) => { } return node.description ? `\n\n${node.description}` : ''; }; - const possibleScalars = ['Boolean', 'String', 'Int', 'Float', 'ID']; + const possibleScalars = { + Boolean: 'boolean', + String: 'string', + Int: 'number', + Float: 'number', + ID: 'string', + }; const content = (0, graphql_1.visit)(astNode, { Document: { leave: (node) => `${node.definitions @@ -26,21 +32,32 @@ config) => { }, Name: { leave: (node) => node.value }, NamedType: { - leave: (node) => possibleScalars.includes(node.name) ? node.name : `[${node.name}](#${node.name})`, + leave: (node) => { + return possibleScalars[node.name] ?? `[\`${node.name}\`](#${node.name})`; + }, }, StringValue: { leave: (node) => node.value }, - BooleanValue: { leave: (node) => node.value }, + BooleanValue: { + leave: (node) => (node.value ? 'true' : 'false'), + }, EnumValue: { leave: (node) => node.value }, IntValue: { leave: (node) => node.value }, + ObjectValue: { + leave: (node) => { + const fields = node.fields.join(', ') ?? ''; + return `{ ${fields} }`; + }, + }, FloatValue: { leave: (node) => node.value }, - ListType: { leave: (node) => `[${node.type}]` }, + ListType: { leave: (node) => `${node.type}[]` }, + ObjectField: { leave: (node) => `${node.name}: ${node.value}` }, NonNullType: { leave: (node) => `${node.type}!`, }, InputValueDefinition: { leave: (node) => { - const defaultValue = node.defaultValue ? ` (default: ${node.defaultValue})` : ''; - return `\`${node.name}: ${node.type}${defaultValue}\`${descriptionText(node)}`; + const defaultValue = node.defaultValue ? ` = ${node.defaultValue}` : ''; + return `${node.name}: ${node.type}${defaultValue}${descriptionText(node)}`; }, }, InputObjectTypeDefinition: { @@ -50,19 +67,20 @@ config) => { fields: [...(node.fields ?? [])].sort((a, b) => a.type.kind === 'NonNullType' && b.type.kind !== 'NonNullType' ? -1 : 1), }), leave: (node) => { - const title = descriptionText(node).trimStart().startsWith('#') - ? `${descriptionText(node).trimStart()}\n\n### ${node.name}` - : `### ${node.name}${descriptionText(node)}`; + const text = descriptionText(node); + const title = text.trimStart().startsWith('#') + ? `${text.trimStart()}\n\n### ${node.name}` + : `### ${node.name}${text}`; return `\n${title}\n${node.fields?.map((f) => `\n#### ${f}`).join('\n')}`; }, }, EnumValueDefinition: { - leave: (node) => `${node.name} # ${node.description}`, + leave: (node) => `${node.name} ${node.description ? `: ${node.description}` : ''}`, }, EnumTypeDefinition: { leave: (node) => { enumStings.set(node.name, node.values?.join('\n') || ''); - return ''; + return `\n### ${node.name} (enum) ${node.description ? `\n\n${node.description}` : ''}\n\n${node.values?.map((v) => `- ${v}`)?.join('\n')}`; }, }, }); diff --git a/packagesDev/graphql-codegen-markdown-docs/src/index.ts b/packagesDev/graphql-codegen-markdown-docs/src/index.ts index 148ced1ff4..0595eca086 100644 --- a/packagesDev/graphql-codegen-markdown-docs/src/index.ts +++ b/packagesDev/graphql-codegen-markdown-docs/src/index.ts @@ -25,7 +25,13 @@ export const plugin: PluginFunction = { + Boolean: 'boolean', + String: 'string', + Int: 'number', + Float: 'number', + ID: 'string', + } const content = visit(astNode, { Document: { @@ -36,22 +42,32 @@ export const plugin: PluginFunction node.value }, NamedType: { - leave: (node) => - possibleScalars.includes(node.name) ? node.name : `[${node.name}](#${node.name})`, + leave: (node) => { + return possibleScalars[node.name] ?? `[\`${node.name}\`](#${node.name})` + }, }, // String, Boolean, GraphCommerceDebugConfig, etc. StringValue: { leave: (node) => node.value }, - BooleanValue: { leave: (node) => node.value }, + BooleanValue: { + leave: (node) => (node.value ? 'true' : 'false'), + }, EnumValue: { leave: (node) => node.value }, IntValue: { leave: (node) => node.value }, + ObjectValue: { + leave: (node) => { + const fields = node.fields.join(', ') ?? '' + return `{ ${fields} }` + }, + }, FloatValue: { leave: (node) => node.value }, - ListType: { leave: (node) => `[${node.type}]` }, + ListType: { leave: (node) => `${node.type}[]` }, + ObjectField: { leave: (node) => `${node.name}: ${node.value}` }, NonNullType: { leave: (node) => `${node.type}!`, }, InputValueDefinition: { leave: (node) => { - const defaultValue = node.defaultValue ? ` (default: ${node.defaultValue})` : '' - return `\`${node.name}: ${node.type}${defaultValue}\`${descriptionText(node)}` + const defaultValue = node.defaultValue ? ` = ${node.defaultValue}` : '' + return `${node.name}: ${node.type}${defaultValue}${descriptionText(node)}` }, }, InputObjectTypeDefinition: { @@ -63,20 +79,24 @@ export const plugin: PluginFunction { - const title = descriptionText(node).trimStart().startsWith('#') - ? `${descriptionText(node).trimStart()}\n\n### ${node.name}` - : `### ${node.name}${descriptionText(node)}` + const text = descriptionText(node) + const title = text.trimStart().startsWith('#') + ? `${text.trimStart()}\n\n### ${node.name}` + : `### ${node.name}${text}` return `\n${title}\n${node.fields?.map((f) => `\n#### ${f}`).join('\n')}` }, }, EnumValueDefinition: { - leave: (node) => `${node.name} # ${node.description}`, + leave: (node) => `${node.name} ${node.description ? `: ${node.description}` : ''}`, }, EnumTypeDefinition: { leave: (node) => { enumStings.set(node.name, node.values?.join('\n') || '') - return '' + + return `\n### ${node.name} (enum) ${ + node.description ? `\n\n${node.description}` : '' + }\n\n${node.values?.map((v) => `- ${v}`)?.join('\n')}` }, }, }) diff --git a/packagesDev/next-config/dist/config/demoConfig.js b/packagesDev/next-config/dist/config/demoConfig.js index a0c8b36686..74f5e34dd6 100644 --- a/packagesDev/next-config/dist/config/demoConfig.js +++ b/packagesDev/next-config/dist/config/demoConfig.js @@ -27,4 +27,5 @@ exports.demoConfig = { compare: true, configurableVariantForSimple: true, configurableVariantValues: { url: true, content: true, gallery: true }, + recentlyViewedProducts: { enabled: true, maxCount: 20 }, }; diff --git a/packagesDev/next-config/dist/generated/config.js b/packagesDev/next-config/dist/generated/config.js index 34ba254db7..bffe36df38 100644 --- a/packagesDev/next-config/dist/generated/config.js +++ b/packagesDev/next-config/dist/generated/config.js @@ -1,85 +1,120 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.RecentlyViewedProductsConfgSchema = exports.MagentoConfigurableVariantValuesSchema = exports.GraphCommerceStorefrontConfigSchema = exports.GraphCommerceDebugConfigSchema = exports.GraphCommerceConfigSchema = exports.ProductFiltersLayoutSchema = exports.CompareVariantSchema = exports.definedNonNullAnySchema = exports.isDefinedNonNullAny = void 0; -/* eslint-disable */ -const zod_1 = require("zod"); -const isDefinedNonNullAny = (v) => v !== undefined && v !== null; -exports.isDefinedNonNullAny = isDefinedNonNullAny; -exports.definedNonNullAnySchema = zod_1.z.any().refine((v) => (0, exports.isDefinedNonNullAny)(v)); -exports.CompareVariantSchema = zod_1.z.enum(['CHECKBOX', 'ICON']); -exports.ProductFiltersLayoutSchema = zod_1.z.enum(['DEFAULT', 'SIDEBAR']); +/* eslint-disable */ "use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + isDefinedNonNullAny: function() { + return isDefinedNonNullAny; + }, + definedNonNullAnySchema: function() { + return definedNonNullAnySchema; + }, + CompareVariantSchema: function() { + return CompareVariantSchema; + }, + ProductFiltersLayoutSchema: function() { + return ProductFiltersLayoutSchema; + }, + GraphCommerceConfigSchema: function() { + return GraphCommerceConfigSchema; + }, + GraphCommerceDebugConfigSchema: function() { + return GraphCommerceDebugConfigSchema; + }, + GraphCommerceStorefrontConfigSchema: function() { + return GraphCommerceStorefrontConfigSchema; + }, + MagentoConfigurableVariantValuesSchema: function() { + return MagentoConfigurableVariantValuesSchema; + }, + RecentlyViewedProductsConfgSchema: function() { + return RecentlyViewedProductsConfgSchema; + } +}); +const _zod = require("zod"); +const isDefinedNonNullAny = (v)=>v !== undefined && v !== null; +const definedNonNullAnySchema = _zod.z.any().refine((v)=>isDefinedNonNullAny(v)); +const CompareVariantSchema = _zod.z.enum([ + "CHECKBOX", + "ICON" +]); +const ProductFiltersLayoutSchema = _zod.z.enum([ + "DEFAULT", + "SIDEBAR" +]); function GraphCommerceConfigSchema() { - return zod_1.z.object({ - canonicalBaseUrl: zod_1.z.string().min(1), - cartDisplayPricesInclTax: zod_1.z.boolean().nullish(), - compare: zod_1.z.boolean().nullish(), - compareVariant: exports.CompareVariantSchema.nullish(), - configurableVariantForSimple: zod_1.z.boolean().nullish(), + return _zod.z.object({ + canonicalBaseUrl: _zod.z.string().min(1), + cartDisplayPricesInclTax: _zod.z.boolean().nullish(), + compare: _zod.z.boolean().nullish(), + compareVariant: CompareVariantSchema.nullish(), + configurableVariantForSimple: _zod.z.boolean().nullish(), configurableVariantValues: MagentoConfigurableVariantValuesSchema().nullish(), - crossSellsHideCartItems: zod_1.z.boolean().nullish(), - crossSellsRedirectItems: zod_1.z.boolean().nullish(), - customerRequireEmailConfirmation: zod_1.z.boolean().nullish(), + crossSellsHideCartItems: _zod.z.boolean().nullish(), + crossSellsRedirectItems: _zod.z.boolean().nullish(), + customerRequireEmailConfirmation: _zod.z.boolean().nullish(), debug: GraphCommerceDebugConfigSchema().nullish(), - demoMode: zod_1.z.boolean().nullish(), - googleAnalyticsId: zod_1.z.string().nullish(), - googleRecaptchaKey: zod_1.z.string().nullish(), - googleTagmanagerId: zod_1.z.string().nullish(), - hygraphEndpoint: zod_1.z.string().min(1), - hygraphProjectId: zod_1.z.string().nullish(), - hygraphWriteAccessEndpoint: zod_1.z.string().nullish(), - hygraphWriteAccessToken: zod_1.z.string().nullish(), - legacyProductRoute: zod_1.z.boolean().nullish(), - limitSsg: zod_1.z.boolean().nullish(), - magentoEndpoint: zod_1.z.string().min(1), - previewSecret: zod_1.z.string().nullish(), - productFiltersLayout: exports.ProductFiltersLayoutSchema.nullish(), - productFiltersPro: zod_1.z.boolean().nullish(), - productRoute: zod_1.z.string().nullish(), + demoMode: _zod.z.boolean().nullish(), + googleAnalyticsId: _zod.z.string().nullish(), + googleRecaptchaKey: _zod.z.string().nullish(), + googleTagmanagerId: _zod.z.string().nullish(), + hygraphEndpoint: _zod.z.string().min(1), + hygraphProjectId: _zod.z.string().nullish(), + hygraphWriteAccessEndpoint: _zod.z.string().nullish(), + hygraphWriteAccessToken: _zod.z.string().nullish(), + legacyProductRoute: _zod.z.boolean().nullish(), + limitSsg: _zod.z.boolean().nullish(), + magentoEndpoint: _zod.z.string().min(1), + previewSecret: _zod.z.string().nullish(), + productFiltersLayout: ProductFiltersLayoutSchema.nullish(), + productFiltersPro: _zod.z.boolean().nullish(), + productRoute: _zod.z.string().nullish(), recentlyViewedProducts: RecentlyViewedProductsConfgSchema().nullish(), - robotsAllow: zod_1.z.boolean().nullish(), - storefront: zod_1.z.array(GraphCommerceStorefrontConfigSchema()), - wishlistHideForGuests: zod_1.z.boolean().nullish(), - wishlistIgnoreProductWishlistStatus: zod_1.z.boolean().nullish(), - wishlistShowFeedbackMessage: zod_1.z.boolean().nullish() + robotsAllow: _zod.z.boolean().nullish(), + storefront: _zod.z.array(GraphCommerceStorefrontConfigSchema()), + wishlistHideForGuests: _zod.z.boolean().nullish(), + wishlistIgnoreProductWishlistStatus: _zod.z.boolean().nullish(), + wishlistShowFeedbackMessage: _zod.z.boolean().nullish() }); } -exports.GraphCommerceConfigSchema = GraphCommerceConfigSchema; function GraphCommerceDebugConfigSchema() { - return zod_1.z.object({ - pluginStatus: zod_1.z.boolean().nullish(), - webpackCircularDependencyPlugin: zod_1.z.boolean().nullish(), - webpackDuplicatesPlugin: zod_1.z.boolean().nullish() + return _zod.z.object({ + pluginStatus: _zod.z.boolean().nullish(), + webpackCircularDependencyPlugin: _zod.z.boolean().nullish(), + webpackDuplicatesPlugin: _zod.z.boolean().nullish() }); } -exports.GraphCommerceDebugConfigSchema = GraphCommerceDebugConfigSchema; function GraphCommerceStorefrontConfigSchema() { - return zod_1.z.object({ - canonicalBaseUrl: zod_1.z.string().nullish(), - cartDisplayPricesInclTax: zod_1.z.boolean().nullish(), - defaultLocale: zod_1.z.boolean().nullish(), - domain: zod_1.z.string().nullish(), - googleAnalyticsId: zod_1.z.string().nullish(), - googleRecaptchaKey: zod_1.z.string().nullish(), - googleTagmanagerId: zod_1.z.string().nullish(), - hygraphLocales: zod_1.z.array(zod_1.z.string().min(1)).nullish(), - linguiLocale: zod_1.z.string().nullish(), - locale: zod_1.z.string().min(1), - magentoStoreCode: zod_1.z.string().min(1) + return _zod.z.object({ + canonicalBaseUrl: _zod.z.string().nullish(), + cartDisplayPricesInclTax: _zod.z.boolean().nullish(), + defaultLocale: _zod.z.boolean().nullish(), + domain: _zod.z.string().nullish(), + googleAnalyticsId: _zod.z.string().nullish(), + googleRecaptchaKey: _zod.z.string().nullish(), + googleTagmanagerId: _zod.z.string().nullish(), + hygraphLocales: _zod.z.array(_zod.z.string().min(1)).nullish(), + linguiLocale: _zod.z.string().nullish(), + locale: _zod.z.string().min(1), + magentoStoreCode: _zod.z.string().min(1) }); } -exports.GraphCommerceStorefrontConfigSchema = GraphCommerceStorefrontConfigSchema; function MagentoConfigurableVariantValuesSchema() { - return zod_1.z.object({ - content: zod_1.z.boolean().nullish(), - gallery: zod_1.z.boolean().nullish(), - url: zod_1.z.boolean().nullish() + return _zod.z.object({ + content: _zod.z.boolean().nullish(), + gallery: _zod.z.boolean().nullish(), + url: _zod.z.boolean().nullish() }); } -exports.MagentoConfigurableVariantValuesSchema = MagentoConfigurableVariantValuesSchema; function RecentlyViewedProductsConfgSchema() { - return zod_1.z.object({ - enabled: zod_1.z.boolean().nullish(), - maxCount: zod_1.z.number().nullish() + return _zod.z.object({ + enabled: _zod.z.boolean().nullish(), + maxCount: _zod.z.number().nullish() }); } -exports.RecentlyViewedProductsConfgSchema = RecentlyViewedProductsConfgSchema; diff --git a/packagesDev/next-config/src/config/demoConfig.ts b/packagesDev/next-config/src/config/demoConfig.ts index 973c4a455f..e17119d6aa 100644 --- a/packagesDev/next-config/src/config/demoConfig.ts +++ b/packagesDev/next-config/src/config/demoConfig.ts @@ -24,10 +24,13 @@ export const demoConfig: PartialDeep; From 438effb18222427213196ca31ad8252990f43199 Mon Sep 17 00:00:00 2001 From: Paul Hachmang Date: Wed, 8 Nov 2023 15:15:54 +0100 Subject: [PATCH 40/47] Cleanup the RecentlyViewedProducs --- docs/framework/config.md | 36 +++++++------------ packages/magento-product/Config.graphqls | 2 +- .../Config.graphqls | 4 +-- .../dist/index.js | 30 +++++++++------- .../src/index.ts | 31 ++++++++-------- .../next-config/dist/generated/config.js | 8 ++--- .../next-config/src/generated/config.ts | 8 ++--- 7 files changed, 57 insertions(+), 62 deletions(-) diff --git a/docs/framework/config.md b/docs/framework/config.md index 753ff685d3..4462f08b98 100644 --- a/docs/framework/config.md +++ b/docs/framework/config.md @@ -1,9 +1,4 @@ -### CompareVariant (enum) - -- CHECKBOX -- ICON - # GraphCommerce configuration system Global GraphCommerce configuration can be configured in your `graphcommerce.config.js` file @@ -82,7 +77,7 @@ Below is a list of all possible configurations that can be set by GraphCommerce. ### GraphCommerceConfig -#### canonicalBaseUrl: string! +#### canonicalBaseUrl: string (required) The canonical base URL is used for SEO purposes. @@ -91,7 +86,7 @@ Examples: - https://example.com/en - https://example.com/en-US -#### hygraphEndpoint: string! +#### hygraphEndpoint: string (required) The HyGraph endpoint. @@ -99,14 +94,14 @@ The HyGraph endpoint. Project settings -> API Access -> High Performance Read-only Content API -#### magentoEndpoint: string! +#### magentoEndpoint: string (required) GraphQL Magento endpoint. Examples: - https://magento2.test/graphql -#### storefront: [`GraphCommerceStorefrontConfig`](#GraphCommerceStorefrontConfig)![]! +#### storefront: [GraphCommerceStorefrontConfig](#GraphCommerceStorefrontConfig)[] (required) All storefront configuration for the project @@ -120,7 +115,7 @@ When Magento's StoreConfig adds this value, this can be replaced. Use compare functionality -#### compareVariant: [`CompareVariant`](#CompareVariant) = ICON +#### compareVariant: 'CHECKBOX' | 'ICON' = 'ICON' By default the compare feature is denoted with a 'compare ICON' (2 arrows facing one another). This may be fine for experienced users, but for more clarity it's also possible to present the compare feature as a CHECKBOX accompanied by the 'Compare' label @@ -138,7 +133,7 @@ Magento also returns the Simple product and the Configurable product the simple If that is the case we render the configurable product page instead of the simple product page but the options to select the simple product are pre-selected. -#### configurableVariantValues: [`MagentoConfigurableVariantValues`](#MagentoConfigurableVariantValues) = { content: true, url: true } +#### configurableVariantValues: [MagentoConfigurableVariantValues](#MagentoConfigurableVariantValues) = { content: true, url: true } When a user selects a variant, it will switch the values on the configurable page with the values of the configured variant. @@ -164,7 +159,7 @@ customer requires email confirmation. This value should match Magento 2's configuration value for `customer/create_account/confirm` and should be removed once we can query -#### debug: [`GraphCommerceDebugConfig`](#GraphCommerceDebugConfig) +#### debug: [GraphCommerceDebugConfig](#GraphCommerceDebugConfig) Debug configuration for GraphCommerce @@ -260,7 +255,7 @@ Limit the static generation of SSG when building To enable next.js' preview mode, configure the secret you'd like to use. -#### productFiltersLayout: [`ProductFiltersLayout`](#ProductFiltersLayout) = DEFAULT +#### productFiltersLayout: 'DEFAULT' | 'SIDEBAR' = 'DEFAULT' Layout how the filters are rendered. DEFAULT: Will be rendered as horzontal chips on desktop and mobile @@ -277,7 +272,7 @@ By default we route products to /p/[url] but you can change this to /product/[ur Default: '/p/' Example: '/product/' -#### recentlyViewedProducts: [`RecentlyViewedProductsConfg`](#RecentlyViewedProductsConfg) +#### recentlyViewedProducts: [RecentlyViewedProductsConfig](#RecentlyViewedProductsConfig) Settings for recently viewed products @@ -325,11 +320,11 @@ Issues that this can cause are: All storefront configuration for the project -#### locale: string! +#### locale: string (required) Must be a locale string https://www.unicode.org/reports/tr35/tr35-59/tr35.html#Identifiers -#### magentoStoreCode: string! +#### magentoStoreCode: string (required) Magento store code. @@ -377,7 +372,7 @@ Locale specific google reCAPTCHA key. The Google Tagmanager ID to be used per locale. -#### hygraphLocales: string![] +#### hygraphLocales: string[] Add a gcms-locales header to make sure queries return in a certain language, can be an array to define fallbacks. @@ -404,12 +399,7 @@ When a variant is selected the URL of the product will be changed in the address This only happens when the actual variant is can be accessed by the URL. -### ProductFiltersLayout (enum) - -- DEFAULT -- SIDEBAR - -### RecentlyViewedProductsConfg +### RecentlyViewedProductsConfig Settings for recently viewed products diff --git a/packages/magento-product/Config.graphqls b/packages/magento-product/Config.graphqls index ba68dc59b0..81e9a707ab 100644 --- a/packages/magento-product/Config.graphqls +++ b/packages/magento-product/Config.graphqls @@ -37,7 +37,7 @@ extend input GraphCommerceConfig { Default: 'false' """ - crossSellsRedirectItems: Boolean = false + crossSellsRedirectItems: Boolean = false """ Determines if cross sell items should be shown when the user already has the product in their cart. This will result in a product will popping off the screen when you add it to the cart. diff --git a/packages/magento-recently-viewed-products/Config.graphqls b/packages/magento-recently-viewed-products/Config.graphqls index 5e4b2491e6..7c5a995bc8 100644 --- a/packages/magento-recently-viewed-products/Config.graphqls +++ b/packages/magento-recently-viewed-products/Config.graphqls @@ -1,7 +1,7 @@ """ Settings for recently viewed products """ -input RecentlyViewedProductsConfg { +input RecentlyViewedProductsConfig { """ Enable/disable recently viewed products """ @@ -16,5 +16,5 @@ extend input GraphCommerceConfig { """ Settings for recently viewed products """ - recentlyViewedProducts: RecentlyViewedProductsConfg + recentlyViewedProducts: RecentlyViewedProductsConfig } diff --git a/packagesDev/graphql-codegen-markdown-docs/dist/index.js b/packagesDev/graphql-codegen-markdown-docs/dist/index.js index b450229090..7c0ff3cd5d 100644 --- a/packagesDev/graphql-codegen-markdown-docs/dist/index.js +++ b/packagesDev/graphql-codegen-markdown-docs/dist/index.js @@ -24,7 +24,7 @@ config) => { Float: 'number', ID: 'string', }; - const content = (0, graphql_1.visit)(astNode, { + let content = (0, graphql_1.visit)(astNode, { Document: { leave: (node) => `${node.definitions .filter(Boolean) @@ -32,15 +32,13 @@ config) => { }, Name: { leave: (node) => node.value }, NamedType: { - leave: (node) => { - return possibleScalars[node.name] ?? `[\`${node.name}\`](#${node.name})`; - }, + leave: (node) => possibleScalars[node.name] ?? `[${node.name}](#${node.name})`, }, StringValue: { leave: (node) => node.value }, BooleanValue: { leave: (node) => (node.value ? 'true' : 'false'), }, - EnumValue: { leave: (node) => node.value }, + EnumValue: { leave: (node) => `'${node.value}'` }, IntValue: { leave: (node) => node.value }, ObjectValue: { leave: (node) => { @@ -49,10 +47,12 @@ config) => { }, }, FloatValue: { leave: (node) => node.value }, - ListType: { leave: (node) => `${node.type}[]` }, + ListType: { + leave: (node) => `${node.type.replace(' (required)', '')}[]`, + }, ObjectField: { leave: (node) => `${node.name}: ${node.value}` }, NonNullType: { - leave: (node) => `${node.type}!`, + leave: (node) => `${node.type} (required)`, }, InputValueDefinition: { leave: (node) => { @@ -64,7 +64,9 @@ config) => { enter: (node) => ({ ...node, // Move required fields to the top. - fields: [...(node.fields ?? [])].sort((a, b) => a.type.kind === 'NonNullType' && b.type.kind !== 'NonNullType' ? -1 : 1), + fields: [...(node.fields ?? [])].sort((a, b) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison + a.type.kind === 'NonNullType' && b.type.kind !== 'NonNullType' ? -1 : 1), }), leave: (node) => { const text = descriptionText(node); @@ -74,16 +76,18 @@ config) => { return `\n${title}\n${node.fields?.map((f) => `\n#### ${f}`).join('\n')}`; }, }, - EnumValueDefinition: { - leave: (node) => `${node.name} ${node.description ? `: ${node.description}` : ''}`, - }, + EnumValueDefinition: { leave: (node) => node.name }, EnumTypeDefinition: { leave: (node) => { - enumStings.set(node.name, node.values?.join('\n') || ''); - return `\n### ${node.name} (enum) ${node.description ? `\n\n${node.description}` : ''}\n\n${node.values?.map((v) => `- ${v}`)?.join('\n')}`; + if (node.values) + enumStings.set(node.name, node.values.map((v) => `'${v.trim()}'`).join(' | ')); + return ''; }, }, }); + enumStings.forEach((value, key) => { + content = content.replaceAll(`[${key}](#${key})`, value); + }); return { content }; }; exports.plugin = plugin; diff --git a/packagesDev/graphql-codegen-markdown-docs/src/index.ts b/packagesDev/graphql-codegen-markdown-docs/src/index.ts index 0595eca086..c72606dc03 100644 --- a/packagesDev/graphql-codegen-markdown-docs/src/index.ts +++ b/packagesDev/graphql-codegen-markdown-docs/src/index.ts @@ -33,7 +33,7 @@ export const plugin: PluginFunction(astNode, { + let content = visit(astNode, { Document: { leave: (node) => `${node.definitions @@ -42,15 +42,13 @@ export const plugin: PluginFunction node.value }, NamedType: { - leave: (node) => { - return possibleScalars[node.name] ?? `[\`${node.name}\`](#${node.name})` - }, + leave: (node) => possibleScalars[node.name] ?? `[${node.name}](#${node.name})`, }, // String, Boolean, GraphCommerceDebugConfig, etc. StringValue: { leave: (node) => node.value }, BooleanValue: { leave: (node) => (node.value ? 'true' : 'false'), }, - EnumValue: { leave: (node) => node.value }, + EnumValue: { leave: (node) => `'${node.value}'` }, IntValue: { leave: (node) => node.value }, ObjectValue: { leave: (node) => { @@ -59,10 +57,12 @@ export const plugin: PluginFunction node.value }, - ListType: { leave: (node) => `${node.type}[]` }, + ListType: { + leave: (node) => `${node.type.replace(' (required)', '')}[]`, + }, ObjectField: { leave: (node) => `${node.name}: ${node.value}` }, NonNullType: { - leave: (node) => `${node.type}!`, + leave: (node) => `${node.type} (required)`, }, InputValueDefinition: { leave: (node) => { @@ -75,6 +75,7 @@ export const plugin: PluginFunction + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison a.type.kind === 'NonNullType' && b.type.kind !== 'NonNullType' ? -1 : 1, ), }), @@ -87,19 +88,19 @@ export const plugin: PluginFunction `\n#### ${f}`).join('\n')}` }, }, - EnumValueDefinition: { - leave: (node) => `${node.name} ${node.description ? `: ${node.description}` : ''}`, - }, + EnumValueDefinition: { leave: (node) => node.name }, EnumTypeDefinition: { leave: (node) => { - enumStings.set(node.name, node.values?.join('\n') || '') - - return `\n### ${node.name} (enum) ${ - node.description ? `\n\n${node.description}` : '' - }\n\n${node.values?.map((v) => `- ${v}`)?.join('\n')}` + if (node.values) + enumStings.set(node.name, node.values.map((v) => `'${v.trim()}'`).join(' | ')) + return '' }, }, }) + enumStings.forEach((value, key) => { + content = content.replaceAll(`[${key}](#${key})`, value) + }) + return { content } } diff --git a/packagesDev/next-config/dist/generated/config.js b/packagesDev/next-config/dist/generated/config.js index bffe36df38..dfc332495f 100644 --- a/packagesDev/next-config/dist/generated/config.js +++ b/packagesDev/next-config/dist/generated/config.js @@ -33,8 +33,8 @@ _export(exports, { MagentoConfigurableVariantValuesSchema: function() { return MagentoConfigurableVariantValuesSchema; }, - RecentlyViewedProductsConfgSchema: function() { - return RecentlyViewedProductsConfgSchema; + RecentlyViewedProductsConfigSchema: function() { + return RecentlyViewedProductsConfigSchema; } }); const _zod = require("zod"); @@ -75,7 +75,7 @@ function GraphCommerceConfigSchema() { productFiltersLayout: ProductFiltersLayoutSchema.nullish(), productFiltersPro: _zod.z.boolean().nullish(), productRoute: _zod.z.string().nullish(), - recentlyViewedProducts: RecentlyViewedProductsConfgSchema().nullish(), + recentlyViewedProducts: RecentlyViewedProductsConfigSchema().nullish(), robotsAllow: _zod.z.boolean().nullish(), storefront: _zod.z.array(GraphCommerceStorefrontConfigSchema()), wishlistHideForGuests: _zod.z.boolean().nullish(), @@ -112,7 +112,7 @@ function MagentoConfigurableVariantValuesSchema() { url: _zod.z.boolean().nullish() }); } -function RecentlyViewedProductsConfgSchema() { +function RecentlyViewedProductsConfigSchema() { return _zod.z.object({ enabled: _zod.z.boolean().nullish(), maxCount: _zod.z.number().nullish() diff --git a/packagesDev/next-config/src/generated/config.ts b/packagesDev/next-config/src/generated/config.ts index ed7edac448..adc86782c5 100644 --- a/packagesDev/next-config/src/generated/config.ts +++ b/packagesDev/next-config/src/generated/config.ts @@ -278,7 +278,7 @@ export type GraphCommerceConfig = { */ productRoute?: InputMaybe; /** Settings for recently viewed products */ - recentlyViewedProducts?: InputMaybe; + recentlyViewedProducts?: InputMaybe; /** * Allow the site to be indexed by search engines. * If false, the robots.txt file will be set to disallow all. @@ -387,7 +387,7 @@ export type ProductFiltersLayout = | 'SIDEBAR'; /** Settings for recently viewed products */ -export type RecentlyViewedProductsConfg = { +export type RecentlyViewedProductsConfig = { /** Enable/disable recently viewed products */ enabled?: InputMaybe; /** Number of recently viewed products to be stored in localStorage */ @@ -436,7 +436,7 @@ export function GraphCommerceConfigSchema(): z.ZodObject> { +export function RecentlyViewedProductsConfigSchema(): z.ZodObject> { return z.object({ enabled: z.boolean().nullish(), maxCount: z.number().nullish() From 2e46389edcd506c490cd7273be384e5c42df4a9e Mon Sep 17 00:00:00 2001 From: Paul Hachmang Date: Wed, 8 Nov 2023 15:21:16 +0100 Subject: [PATCH 41/47] changeset --- .changeset/stupid-ears-wink.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/stupid-ears-wink.md diff --git a/.changeset/stupid-ears-wink.md b/.changeset/stupid-ears-wink.md new file mode 100644 index 0000000000..99d2cee5bb --- /dev/null +++ b/.changeset/stupid-ears-wink.md @@ -0,0 +1,5 @@ +--- +'@graphcommerce/graphql-codegen-markdown-docs': patch +--- + +Render framework/config.md more nicely, so that we follow a more typescript-esque style, inline enums. From eb29cbef56f8f7275ffe6760ef5e9f8d2598c7c4 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Wed, 15 Nov 2023 11:06:41 +0100 Subject: [PATCH 42/47] Added recently viewed products to product pages --- .changeset/fifty-taxis-speak.md | 5 +++++ examples/magento-graphcms/locales/de.po | 3 +++ examples/magento-graphcms/locales/en.po | 3 +++ examples/magento-graphcms/locales/es.po | 3 +++ examples/magento-graphcms/locales/fr.po | 3 +++ examples/magento-graphcms/locales/it.po | 3 +++ examples/magento-graphcms/locales/nl.po | 3 +++ examples/magento-graphcms/pages/p/[url].tsx | 9 +++++++++ 8 files changed, 32 insertions(+) create mode 100644 .changeset/fifty-taxis-speak.md diff --git a/.changeset/fifty-taxis-speak.md b/.changeset/fifty-taxis-speak.md new file mode 100644 index 0000000000..a20b684170 --- /dev/null +++ b/.changeset/fifty-taxis-speak.md @@ -0,0 +1,5 @@ +--- +'@graphcommerce/magento-graphcms': patch +--- + +Added recently viewed products to product pages diff --git a/examples/magento-graphcms/locales/de.po b/examples/magento-graphcms/locales/de.po index 2d06328fad..75fce29b5a 100644 --- a/examples/magento-graphcms/locales/de.po +++ b/examples/magento-graphcms/locales/de.po @@ -526,6 +526,9 @@ msgstr "Produkt nicht verfügbar in {allLabels}" msgid "Products" msgstr "Produkte" +msgid "Recently viewed products" +msgstr "Kürzlich angesehene Produkte" + msgid "Region" msgstr "Region" diff --git a/examples/magento-graphcms/locales/en.po b/examples/magento-graphcms/locales/en.po index 4abd9b5670..fedfed2c66 100644 --- a/examples/magento-graphcms/locales/en.po +++ b/examples/magento-graphcms/locales/en.po @@ -526,6 +526,9 @@ msgstr "Product not available in {allLabels}" msgid "Products" msgstr "Products" +msgid "Recently viewed products" +msgstr "Recently viewed products" + msgid "Region" msgstr "Region" diff --git a/examples/magento-graphcms/locales/es.po b/examples/magento-graphcms/locales/es.po index bc3f4c4a15..32637cfba9 100644 --- a/examples/magento-graphcms/locales/es.po +++ b/examples/magento-graphcms/locales/es.po @@ -526,6 +526,9 @@ msgstr "Producto no disponible en {allLabels}" msgid "Products" msgstr "Productos" +msgid "Recently viewed products" +msgstr "Productos vistos recientemente" + msgid "Region" msgstr "Región" diff --git a/examples/magento-graphcms/locales/fr.po b/examples/magento-graphcms/locales/fr.po index 0a0b7ed8f2..a1f003ac87 100644 --- a/examples/magento-graphcms/locales/fr.po +++ b/examples/magento-graphcms/locales/fr.po @@ -526,6 +526,9 @@ msgstr "Produit non disponible dans {allLabels}" msgid "Products" msgstr "Produits" +msgid "Recently viewed products" +msgstr "Derniers produits consultés" + msgid "Region" msgstr "Région" diff --git a/examples/magento-graphcms/locales/it.po b/examples/magento-graphcms/locales/it.po index d31477e4f9..36d9bed046 100644 --- a/examples/magento-graphcms/locales/it.po +++ b/examples/magento-graphcms/locales/it.po @@ -526,6 +526,9 @@ msgstr "Prodotto non disponibile in {allLabels}" msgid "Products" msgstr "Prodotti" +msgid "Recently viewed products" +msgstr "Prodotti visionati recentemente" + msgid "Region" msgstr "Regione" diff --git a/examples/magento-graphcms/locales/nl.po b/examples/magento-graphcms/locales/nl.po index 3b0f9d9b4f..34468a40a1 100644 --- a/examples/magento-graphcms/locales/nl.po +++ b/examples/magento-graphcms/locales/nl.po @@ -526,6 +526,9 @@ msgstr "Product niet beschikbaar in {allLabels}" msgid "Products" msgstr "Producten" +msgid "Recently viewed products" +msgstr "Recent bekeken producten" + msgid "Region" msgstr "Regio" diff --git a/examples/magento-graphcms/pages/p/[url].tsx b/examples/magento-graphcms/pages/p/[url].tsx index 1a3612f469..11ea9a6cea 100644 --- a/examples/magento-graphcms/pages/p/[url].tsx +++ b/examples/magento-graphcms/pages/p/[url].tsx @@ -30,6 +30,7 @@ import { defaultConfigurableOptionsSelection, } from '@graphcommerce/magento-product-configurable' import { DownloadableProductOptions } from '@graphcommerce/magento-product-downloadable' +import { RecentlyViewedProducts } from '@graphcommerce/magento-recently-viewed-products' import { jsonLdProductReview, ProductReviewChip } from '@graphcommerce/magento-review' import { redirectOrNotFound, Money, StoreConfigDocument } from '@graphcommerce/magento-store' import { ProductWishlistChipDetail } from '@graphcommerce/magento-wishlist' @@ -41,6 +42,7 @@ import { LayoutDocument, LayoutNavigation, LayoutNavigationProps, + productListRenderer, RowProduct, RowRenderer, Usps, @@ -48,6 +50,7 @@ import { import { UspsDocument, UspsQuery } from '../../components/Usps/Usps.gql' import { ProductPage2Document, ProductPage2Query } from '../../graphql/ProductPage2.gql' import { graphqlSharedClient, graphqlSsrClient } from '../../lib/graphql/graphqlSsrClient' +import { i18n } from '@lingui/core' type Props = HygraphPagesQuery & UspsQuery & @@ -185,6 +188,12 @@ function ProductPage(props: Props) { }} /> )} + + ) } From 21fcc2a63ee25390e506e5b94a9b1e9a02504169 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Wed, 15 Nov 2023 11:16:51 +0100 Subject: [PATCH 43/47] =?UTF-8?q?Don=E2=80=99t=20render=20recently=20viewe?= =?UTF-8?q?d=20products=20when=20it=20is=20disabled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/demo/DemoRecentlyViewedProducts.tsx | 5 ++++- .../components/RecentlyViewedProducts.tsx | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/demo-magento-graphcommerce/plugins/demo/DemoRecentlyViewedProducts.tsx b/packages/demo-magento-graphcommerce/plugins/demo/DemoRecentlyViewedProducts.tsx index 34f3072960..949008baa8 100644 --- a/packages/demo-magento-graphcommerce/plugins/demo/DemoRecentlyViewedProducts.tsx +++ b/packages/demo-magento-graphcommerce/plugins/demo/DemoRecentlyViewedProducts.tsx @@ -26,7 +26,10 @@ function DemoRecentlyViewedProducts(props: PluginProps Date: Wed, 15 Nov 2023 11:17:27 +0100 Subject: [PATCH 44/47] Enable recently viewed products by default in example config --- examples/magento-graphcms/graphcommerce.config.js.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/magento-graphcms/graphcommerce.config.js.example b/examples/magento-graphcms/graphcommerce.config.js.example index f58536feeb..c39eefd3c3 100644 --- a/examples/magento-graphcms/graphcommerce.config.js.example +++ b/examples/magento-graphcms/graphcommerce.config.js.example @@ -10,6 +10,9 @@ const config = { magentoEndpoint: 'https://backend.reachdigital.dev/graphql', canonicalBaseUrl: 'https://graphcommerce.vercel.app', storefront: [{ locale: 'en', magentoStoreCode: 'en_US' }], + recentlyViewedProducts: { + enabled: true, + }, } module.exports = config From acd40f336502bcf0728677f0231e221838a497bd Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Wed, 15 Nov 2023 11:33:17 +0100 Subject: [PATCH 45/47] Removed recently viewed products for Hygraph --- .changeset/lovely-moles-mix.md | 5 ----- docs/upgrading/graphcommerce-7-to-7.1.md | 6 ------ docs/upgrading/readme.md | 1 - .../components/GraphCMS/RowProduct/RowProduct.tsx | 2 -- .../GraphCMS/RowProduct/variant/Recent.tsx | 15 --------------- .../GraphCMS/RowProduct/variant/index.tsx | 1 - .../src/migrations/graphcommerce7to7.1.ts | 15 --------------- packages/hygraph-cli/src/migrations/index.ts | 1 - 8 files changed, 46 deletions(-) delete mode 100644 .changeset/lovely-moles-mix.md delete mode 100644 docs/upgrading/graphcommerce-7-to-7.1.md delete mode 100644 examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx delete mode 100644 packages/hygraph-cli/src/migrations/graphcommerce7to7.1.ts diff --git a/.changeset/lovely-moles-mix.md b/.changeset/lovely-moles-mix.md deleted file mode 100644 index 29e93308ea..0000000000 --- a/.changeset/lovely-moles-mix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@graphcommerce/hygraph-cli': patch ---- - -Added 7 to 7.1 Hygraph migration script diff --git a/docs/upgrading/graphcommerce-7-to-7.1.md b/docs/upgrading/graphcommerce-7-to-7.1.md deleted file mode 100644 index a1c151ceb5..0000000000 --- a/docs/upgrading/graphcommerce-7-to-7.1.md +++ /dev/null @@ -1,6 +0,0 @@ -# Upgrading from GraphCommerce 7 to 7.1 - -## Upgrading your Hygraph schema - -Upgrade your Hygraph schema with the [Hygraph migration cli](../hygraph/cli.md). -Select `graphcommerce7to7_1` as version. diff --git a/docs/upgrading/readme.md b/docs/upgrading/readme.md index 4d3195d466..c7ff461cee 100644 --- a/docs/upgrading/readme.md +++ b/docs/upgrading/readme.md @@ -108,7 +108,6 @@ After resolving the diff issues, manually process upgrade instructions: - [Upgrading to GraphCommerce 5 to 6](../upgrading/graphcommerce-5-to-6.md) - [Upgrading to GraphCommerce 6 to 7](../upgrading/graphcommerce-6-to-7.md) -- [Upgrading to GraphCommerce 7 to 7.1](../upgrading/graphcommerce-7-to-7.1.md) Run and validate your local environment: diff --git a/examples/magento-graphcms/components/GraphCMS/RowProduct/RowProduct.tsx b/examples/magento-graphcms/components/GraphCMS/RowProduct/RowProduct.tsx index 75451489ea..ce6e3e4d88 100644 --- a/examples/magento-graphcms/components/GraphCMS/RowProduct/RowProduct.tsx +++ b/examples/magento-graphcms/components/GraphCMS/RowProduct/RowProduct.tsx @@ -5,7 +5,6 @@ import { Feature, FeatureBoxed, Grid, - Recent, Related, Reviews, Specs, @@ -28,7 +27,6 @@ const defaultRenderer: Partial = { Feature, FeatureBoxed, Grid, - Recent, Related, Reviews, Upsells, diff --git a/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx b/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx deleted file mode 100644 index 9d42e28268..0000000000 --- a/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/Recent.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { RecentlyViewedProducts } from '@graphcommerce/magento-recently-viewed-products' -import { productListRenderer } from '../../../ProductListItems' -import { RowProductFragment } from '../RowProduct.gql' - -type RecentProps = RowProductFragment & { sku?: string | null | undefined } - -export function Recent({ title, sku }: RecentProps) { - return ( - - ) -} diff --git a/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/index.tsx b/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/index.tsx index ca42031c30..a7123ddae5 100644 --- a/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/index.tsx +++ b/examples/magento-graphcms/components/GraphCMS/RowProduct/variant/index.tsx @@ -2,7 +2,6 @@ export * from './Backstory' export * from './Feature' export * from './FeatureBoxed' export * from './Grid' -export * from './Recent' export * from './Related' export * from './Reviews' export * from './Specs' diff --git a/packages/hygraph-cli/src/migrations/graphcommerce7to7.1.ts b/packages/hygraph-cli/src/migrations/graphcommerce7to7.1.ts deleted file mode 100644 index 9caea558e4..0000000000 --- a/packages/hygraph-cli/src/migrations/graphcommerce7to7.1.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { migrationAction, client } from '../migrationAction' -import { Schema } from '../types' - -export const graphcommerce7to7_1 = async (schema: Schema) => { - if (!client) { - return 0 - } - - migrationAction(schema, 'enumeration', 'update', { - apiId: 'RowProductVariants', - valuesToCreate: [{ apiId: 'Recent', displayName: 'Recent' }], - }) - - return client.run(true) -} diff --git a/packages/hygraph-cli/src/migrations/index.ts b/packages/hygraph-cli/src/migrations/index.ts index 375a873d8b..1054c496f0 100644 --- a/packages/hygraph-cli/src/migrations/index.ts +++ b/packages/hygraph-cli/src/migrations/index.ts @@ -1,3 +1,2 @@ export * from './graphcommerce5to6' export * from './graphcommerce6to7' -export * from './graphcommerce7to7.1' From 383efae01a052d2ec7fc0206a0ad0b479ee0a9d8 Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Wed, 15 Nov 2023 15:28:17 +0100 Subject: [PATCH 46/47] Fixed links not using Next Router in ProductListItem --- .../components/ProductListItem/ProductListItem.tsx | 10 +++++----- .../ProductListItem/ProductListItemLinkOrDiv.tsx | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/magento-product/components/ProductListItem/ProductListItem.tsx b/packages/magento-product/components/ProductListItem/ProductListItem.tsx index d07b2de4f4..f518251e5d 100644 --- a/packages/magento-product/components/ProductListItem/ProductListItem.tsx +++ b/packages/magento-product/components/ProductListItem/ProductListItem.tsx @@ -17,7 +17,7 @@ import { ProductListItemImageAreas, ProductImageContainer, } from './ProductListItemImageContainer' -import * as ProductListItemLinkOrDiv from './ProductListItemLinkOrDiv' +import { ProductListItemLinkOrDiv } from './ProductListItemLinkOrDiv' import { ProductListItemTitleAndPrice, ProductListItemTitleAndPriceProps, @@ -90,7 +90,7 @@ export function ProductListItemReal(props: ProductProps) { ) return ( - )} - + ) } @@ -144,7 +144,7 @@ export function ProductListItemSkeleton(props: SkeletonProps) { const { children, imageOnly = false, aspectRatio, titleComponent = 'h2', sx = [] } = props return ( - + @@ -162,7 +162,7 @@ export function ProductListItemSkeleton(props: SkeletonProps) { {children} )} - + ) } diff --git a/packages/magento-product/components/ProductListItem/ProductListItemLinkOrDiv.tsx b/packages/magento-product/components/ProductListItem/ProductListItemLinkOrDiv.tsx index d0bbdb04ed..c778f8654d 100644 --- a/packages/magento-product/components/ProductListItem/ProductListItemLinkOrDiv.tsx +++ b/packages/magento-product/components/ProductListItem/ProductListItemLinkOrDiv.tsx @@ -1,7 +1,7 @@ -import { breakpointVal } from '@graphcommerce/next-ui' +import { NextLink, breakpointVal } from '@graphcommerce/next-ui' import { Box, BoxProps, ButtonBase, ButtonBaseProps, SxProps, Theme } from '@mui/material' -type ProductListItemLinkProps = ButtonBaseProps<'a'> +type ProductListItemLinkProps = ButtonBaseProps type ProductListItemLinkOrDivProps = ProductListItemLinkProps | BoxProps function isLink(props: ProductListItemLinkOrDivProps): props is ProductListItemLinkProps { @@ -27,7 +27,7 @@ export function ProductListItemLinkOrDiv(props: ProductListItemLinkOrDivProps) { ] return isLink(props) ? ( - + ) : ( ) From 2d01d2d99213fc3cbb4a607f599e6234b5ce07df Mon Sep 17 00:00:00 2001 From: Bram van der Holst Date: Thu, 16 Nov 2023 17:34:16 +0100 Subject: [PATCH 47/47] Allow React node as title --- examples/magento-graphcms/pages/p/[url].tsx | 3 +-- .../components/ProductScroller/ProductScroller.tsx | 2 +- .../components/RecentlyViewedProducts.tsx | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/magento-graphcms/pages/p/[url].tsx b/examples/magento-graphcms/pages/p/[url].tsx index 11ea9a6cea..da5d1fad36 100644 --- a/examples/magento-graphcms/pages/p/[url].tsx +++ b/examples/magento-graphcms/pages/p/[url].tsx @@ -50,7 +50,6 @@ import { import { UspsDocument, UspsQuery } from '../../components/Usps/Usps.gql' import { ProductPage2Document, ProductPage2Query } from '../../graphql/ProductPage2.gql' import { graphqlSharedClient, graphqlSsrClient } from '../../lib/graphql/graphqlSsrClient' -import { i18n } from '@lingui/core' type Props = HygraphPagesQuery & UspsQuery & @@ -190,7 +189,7 @@ function ProductPage(props: Props) { )} } exclude={[product.sku]} productListRenderer={productListRenderer} /> diff --git a/packages/magento-product/components/ProductScroller/ProductScroller.tsx b/packages/magento-product/components/ProductScroller/ProductScroller.tsx index bae39a6d27..ac71148684 100644 --- a/packages/magento-product/components/ProductScroller/ProductScroller.tsx +++ b/packages/magento-product/components/ProductScroller/ProductScroller.tsx @@ -19,7 +19,7 @@ import { ProductListItemProps } from '../ProductListItem/ProductListItem' import { ProductListItemRenderer, ProductListItemType } from '../ProductListItems/renderer' export type ProductScrollerProps = { - title?: string + title?: React.ReactNode items: ProductListItemType[] productListRenderer: ProductListItemRenderer imageOnly?: ProductListItemProps['imageOnly'] diff --git a/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx b/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx index 2aa1c89949..4141c88b82 100644 --- a/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx +++ b/packages/magento-recently-viewed-products/components/RecentlyViewedProducts.tsx @@ -8,7 +8,7 @@ import { } from '../hooks' export type RecentlyViewedProductsProps = UseRecentlyViewedProductsProps & { - title?: string + title?: React.ReactNode productListRenderer: ProductListItemRenderer loading?: 'lazy' | 'eager' }