diff --git a/components/cart/CartItem/CartItem.tsx b/components/cart/CartItem/CartItem.tsx index 846d1d49e..db886b7a7 100644 --- a/components/cart/CartItem/CartItem.tsx +++ b/components/cart/CartItem/CartItem.tsx @@ -5,7 +5,7 @@ import Link from 'next/link' import s from './CartItem.module.css' import { Trash, Plus, Minus } from '@components/icons' import { useUI } from '@components/ui/context' -import type { LineItem } from '@framework/types' +import type { LineItem } from '@framework/types/cart' import usePrice from '@framework/product/use-price' import useUpdateItem from '@framework/cart/use-update-item' import useRemoveItem from '@framework/cart/use-remove-item' diff --git a/components/common/Footer/Footer.tsx b/components/common/Footer/Footer.tsx index 75b2806ef..af14b150b 100644 --- a/components/common/Footer/Footer.tsx +++ b/components/common/Footer/Footer.tsx @@ -2,7 +2,7 @@ import { FC } from 'react' import cn from 'classnames' import Link from 'next/link' import { useRouter } from 'next/router' -import type { Page } from '@framework/common/get-all-pages' +import type { Page } from '@framework/types/page' import getSlug from '@lib/get-slug' import { Github, Vercel } from '@components/icons' import { Logo, Container } from '@components/ui' diff --git a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx index 423048f75..422458a95 100644 --- a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx +++ b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx @@ -1,6 +1,6 @@ import { FC } from 'react' import Link from 'next/link' -import type { Product } from '@commerce/types' +import type { Product } from '@framework/types/product' import { Grid } from '@components/ui' import { ProductCard } from '@components/product' import s from './HomeAllProductsGrid.module.css' diff --git a/components/common/Layout/Layout.tsx b/components/common/Layout/Layout.tsx index 54749c46b..d162aae75 100644 --- a/components/common/Layout/Layout.tsx +++ b/components/common/Layout/Layout.tsx @@ -11,7 +11,7 @@ import CartSidebarView from '@components/cart/CartSidebarView' import LoginView from '@components/auth/LoginView' import { CommerceProvider } from '@framework' -import type { Page } from '@framework/common/get-all-pages' +import type { Page } from '@framework/types/page' const Loading = () => (
diff --git a/components/common/UserNav/UserNav.tsx b/components/common/UserNav/UserNav.tsx index 4d00970a9..7a13f86bf 100644 --- a/components/common/UserNav/UserNav.tsx +++ b/components/common/UserNav/UserNav.tsx @@ -1,7 +1,7 @@ import { FC } from 'react' import Link from 'next/link' import cn from 'classnames' -import type { LineItem } from '@framework/types' +import type { LineItem } from '@framework/types/cart' import useCart from '@framework/cart/use-cart' import useCustomer from '@framework/customer/use-customer' import { Avatar } from '@components/common' diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx index ade53380c..0b0ad3df0 100644 --- a/components/product/ProductCard/ProductCard.tsx +++ b/components/product/ProductCard/ProductCard.tsx @@ -1,7 +1,7 @@ import { FC } from 'react' import cn from 'classnames' import Link from 'next/link' -import type { Product } from '@commerce/types' +import type { Product } from '@framework/types/product' import s from './ProductCard.module.css' import Image, { ImageProps } from 'next/image' import WishlistButton from '@components/wishlist/WishlistButton' diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index 3b09fa39a..96cad2e92 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -5,7 +5,7 @@ import { FC, useEffect, useState } from 'react' import s from './ProductView.module.css' import { Swatch, ProductSlider } from '@components/product' import { Button, Container, Text, useUI } from '@components/ui' -import type { Product } from '@commerce/types' +import type { Product } from '@framework/types/product' import usePrice from '@framework/product/use-price' import { useAddItem } from '@framework/cart' import { getVariant, SelectedOptions } from '../helpers' diff --git a/components/product/Swatch/Swatch.tsx b/components/product/Swatch/Swatch.tsx index 34244321f..c38803b5b 100644 --- a/components/product/Swatch/Swatch.tsx +++ b/components/product/Swatch/Swatch.tsx @@ -47,7 +47,7 @@ const Swatch: FC & Props> = ({ )} - {variant === 'size' ? label : null} + {variant !== 'color' ? label : null} ) } diff --git a/components/product/helpers.ts b/components/product/helpers.ts index a0ceb7aa5..4e9d0f591 100644 --- a/components/product/helpers.ts +++ b/components/product/helpers.ts @@ -1,4 +1,4 @@ -import type { Product } from '@commerce/types' +import type { Product } from '@framework/types/product' export type SelectedOptions = Record export function getVariant(product: Product, opts: SelectedOptions) { diff --git a/components/wishlist/WishlistButton/WishlistButton.tsx b/components/wishlist/WishlistButton/WishlistButton.tsx index 6dc59b900..7f91e39c0 100644 --- a/components/wishlist/WishlistButton/WishlistButton.tsx +++ b/components/wishlist/WishlistButton/WishlistButton.tsx @@ -6,7 +6,7 @@ import useAddItem from '@framework/wishlist/use-add-item' import useCustomer from '@framework/customer/use-customer' import useWishlist from '@framework/wishlist/use-wishlist' import useRemoveItem from '@framework/wishlist/use-remove-item' -import type { Product, ProductVariant } from '@commerce/types' +import type { Product, ProductVariant } from '@framework/types/product' type Props = { productId: Product['id'] diff --git a/components/wishlist/WishlistCard/WishlistCard.tsx b/components/wishlist/WishlistCard/WishlistCard.tsx index 1568d9e7e..84d2698e2 100644 --- a/components/wishlist/WishlistCard/WishlistCard.tsx +++ b/components/wishlist/WishlistCard/WishlistCard.tsx @@ -7,7 +7,7 @@ import { Trash } from '@components/icons' import { Button, Text } from '@components/ui' import { useUI } from '@components/ui/context' -import type { Product } from '@commerce/types' +import type { Product } from '@framework/types/product' import usePrice from '@framework/product/use-price' import useAddItem from '@framework/cart/use-add-item' import useRemoveItem from '@framework/wishlist/use-remove-item' @@ -18,9 +18,9 @@ interface Props { const WishlistCard: FC = ({ product }) => { const { price } = usePrice({ - amount: product.prices?.price?.value, - baseAmount: product.prices?.retailPrice?.value, - currencyCode: product.prices?.price?.currencyCode!, + amount: product.price?.value, + baseAmount: product.price?.retailPrice, + currencyCode: product.price?.currencyCode!, }) // @ts-ignore Wishlist is not always enabled const removeItem = useRemoveItem({ wishlist: { includeProducts: true } }) diff --git a/framework/bigcommerce/api/endpoints/cart/add-item.ts b/framework/bigcommerce/api/endpoints/cart/add-item.ts index b13e07d15..52ef1223d 100644 --- a/framework/bigcommerce/api/endpoints/cart/add-item.ts +++ b/framework/bigcommerce/api/endpoints/cart/add-item.ts @@ -1,4 +1,4 @@ -import { normalizeCart } from '@framework/lib/normalize' +import { normalizeCart } from '../../../lib/normalize' import { parseCartItem } from '../../utils/parse-item' import getCartCookie from '../../utils/get-cart-cookie' import type { CartEndpoint } from '.' diff --git a/framework/bigcommerce/api/endpoints/cart/get-cart.ts b/framework/bigcommerce/api/endpoints/cart/get-cart.ts index 110efc873..d3bb309e2 100644 --- a/framework/bigcommerce/api/endpoints/cart/get-cart.ts +++ b/framework/bigcommerce/api/endpoints/cart/get-cart.ts @@ -1,7 +1,7 @@ -import { normalizeCart } from '@framework/lib/normalize' +import { normalizeCart } from '../../../lib/normalize' import { BigcommerceApiError } from '../../utils/errors' import getCartCookie from '../../utils/get-cart-cookie' -import type { BigcommerceCart } from '../../../types' +import type { BigcommerceCart } from '../../../types/cart' import type { CartEndpoint } from '.' // Return current cart info diff --git a/framework/bigcommerce/api/endpoints/cart/remove-item.ts b/framework/bigcommerce/api/endpoints/cart/remove-item.ts index c6844978a..baf10c80f 100644 --- a/framework/bigcommerce/api/endpoints/cart/remove-item.ts +++ b/framework/bigcommerce/api/endpoints/cart/remove-item.ts @@ -1,4 +1,4 @@ -import { normalizeCart } from '@framework/lib/normalize' +import { normalizeCart } from '../../../lib/normalize' import getCartCookie from '../../utils/get-cart-cookie' import type { CartEndpoint } from '.' diff --git a/framework/bigcommerce/api/endpoints/cart/update-item.ts b/framework/bigcommerce/api/endpoints/cart/update-item.ts index 1222921fe..113553fad 100644 --- a/framework/bigcommerce/api/endpoints/cart/update-item.ts +++ b/framework/bigcommerce/api/endpoints/cart/update-item.ts @@ -1,4 +1,4 @@ -import { normalizeCart } from '@framework/lib/normalize' +import { normalizeCart } from '../../../lib/normalize' import { parseCartItem } from '../../utils/parse-item' import getCartCookie from '../../utils/get-cart-cookie' import type { CartEndpoint } from '.' diff --git a/framework/bigcommerce/api/utils/parse-item.ts b/framework/bigcommerce/api/utils/parse-item.ts index 7c8cd4728..14c9ac53d 100644 --- a/framework/bigcommerce/api/utils/parse-item.ts +++ b/framework/bigcommerce/api/utils/parse-item.ts @@ -1,5 +1,5 @@ -import type { ItemBody as WishlistItemBody } from '../wishlist' -import type { CartItemBody, OptionSelections } from '../../types' +import type { WishlistItemBody } from '../../types/wishlist' +import type { CartItemBody, OptionSelections } from '../../types/cart' type BCWishlistItemBody = { product_id: number diff --git a/framework/bigcommerce/cart/use-update-item.tsx b/framework/bigcommerce/cart/use-update-item.tsx index 6d014cc24..3ae2af02a 100644 --- a/framework/bigcommerce/cart/use-update-item.tsx +++ b/framework/bigcommerce/cart/use-update-item.tsx @@ -6,7 +6,7 @@ import type { } from '@commerce/utils/types' import { ValidationError } from '@commerce/utils/errors' import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item' -import type { LineItem, UpdateItemHook } from '../types' +import type { LineItem, UpdateItemHook } from '../types/cart' import { handler as removeItemHandler } from './use-remove-item' import useCart from './use-cart' diff --git a/framework/bigcommerce/lib/normalize.ts b/framework/bigcommerce/lib/normalize.ts index cc7606099..44b00ced6 100644 --- a/framework/bigcommerce/lib/normalize.ts +++ b/framework/bigcommerce/lib/normalize.ts @@ -1,5 +1,5 @@ -import type { Product } from '@commerce/types' -import type { Cart, BigcommerceCart, LineItem } from '../types' +import type { Product } from '../types/product' +import type { Cart, BigcommerceCart, LineItem } from '../types/cart' import update from './immutability' function normalizeProductOption(productOption: any) { diff --git a/framework/bigcommerce/product/use-search.tsx b/framework/bigcommerce/product/use-search.tsx index c9ac8f9a0..de4e1ac48 100644 --- a/framework/bigcommerce/product/use-search.tsx +++ b/framework/bigcommerce/product/use-search.tsx @@ -9,6 +9,7 @@ export type SearchProductsInput = { categoryId?: number brandId?: number sort?: string + locale?: string } export const handler: SWRHook = { diff --git a/framework/commerce/api/index.ts b/framework/commerce/api/index.ts index 8a08b92ee..8b44bea33 100644 --- a/framework/commerce/api/index.ts +++ b/framework/commerce/api/index.ts @@ -148,6 +148,7 @@ export const createEndpoint = >( export interface CommerceAPIConfig { locale?: string + locales?: string[] commerceUrl: string apiToken: string cartCookie: string diff --git a/framework/commerce/index.tsx b/framework/commerce/index.tsx index 07bf74a22..5c006f976 100644 --- a/framework/commerce/index.tsx +++ b/framework/commerce/index.tsx @@ -6,35 +6,53 @@ import { useMemo, useRef, } from 'react' + +import type { + AddItemHook, + GetCartHook, + RemoveItemHook, + UpdateItemHook, +} from '@framework/types/cart' + +import { + AddItemHook as WishlistAddItemHook, + GetWishlistHook, + RemoveItemHook as WishlistRemoveItemHook, +} from '@framework/types/wishlist' + +import { CustomerHook } from '@framework/types/customer' +import { LoginHook } from '@framework/types/login' +import { LogoutHook } from '@framework/types/logout' +import { SearchProductsHook } from '@framework/types/product' +import { SignupHook } from '@framework/types/signup' + import { Fetcher, SWRHook, MutationHook } from './utils/types' -import type { FetchCartInput } from './cart/use-cart' -import type { Cart, Wishlist, Customer, SearchProductsData } from './types' const Commerce = createContext | {}>({}) export type Provider = CommerceConfig & { fetcher: Fetcher cart?: { - useCart?: SWRHook - useAddItem?: MutationHook - useUpdateItem?: MutationHook - useRemoveItem?: MutationHook + useCart?: SWRHook + useAddItem?: MutationHook + useUpdateItem?: MutationHook + useRemoveItem?: MutationHook } wishlist?: { - useWishlist?: SWRHook - useAddItem?: MutationHook - useRemoveItem?: MutationHook + useWishlist?: SWRHook + useAddItem?: MutationHook + useRemoveItem?: MutationHook } customer?: { - useCustomer?: SWRHook + useCustomer?: SWRHook } products?: { - useSearch?: SWRHook + useSearch?: SWRHook } auth?: { - useSignup?: MutationHook - useLogin?: MutationHook - useLogout?: MutationHook + useSignup?: MutationHook + useLogin?: MutationHook + useLogout?: MutationHook } } diff --git a/framework/commerce/types/product.ts b/framework/commerce/types/product.ts index 2ac45389e..26b57f49c 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -14,6 +14,8 @@ export type ProductPrice = { } export type ProductOption = { + __typename: 'MultipleChoiceOption' + id: string displayName: string values: ProductOptionValues[] } @@ -47,6 +49,7 @@ export type SearchProductsBody = { categoryId?: string brandId?: string sort?: string + locale?: string } export type ProductTypes = { diff --git a/framework/shopify/api/index.ts b/framework/shopify/api/index.ts index ad32577a4..28c7d34b3 100644 --- a/framework/shopify/api/index.ts +++ b/framework/shopify/api/index.ts @@ -4,7 +4,12 @@ import { getCommerceApi as commerceApi, } from '@commerce/api' -import { API_URL, API_TOKEN, SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '../const' +import { + API_URL, + API_TOKEN, + SHOPIFY_CUSTOMER_TOKEN_COOKIE, + SHOPIFY_CHECKOUT_ID_COOKIE, +} from '../const' import fetchGraphqlApi from './utils/fetch-graphql-api' @@ -29,7 +34,7 @@ const config: ShopifyConfig = { commerceUrl: API_URL, apiToken: API_TOKEN, customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE, - cartCookie: process.env.SHOPIFY_CART_COOKIE ?? 'shopify_checkoutId', + cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, cartCookieMaxAge: ONE_DAY * 30, fetch: fetchGraphqlApi, } @@ -46,6 +51,5 @@ export type ShopifyAPI

= CommerceAPI

export function getCommerceApi

( customProvider: P = provider as any ): ShopifyAPI

{ - console.log(customProvider) return commerceApi(customProvider) } diff --git a/framework/shopify/api/operations/get-all-pages.ts b/framework/shopify/api/operations/get-all-pages.ts index 50f2bfd1b..3dd4cf6fe 100644 --- a/framework/shopify/api/operations/get-all-pages.ts +++ b/framework/shopify/api/operations/get-all-pages.ts @@ -2,9 +2,14 @@ import type { OperationContext, OperationOptions, } from '@commerce/api/operations' -import { GetAllPagesQuery, GetAllPagesQueryVariables } from '@framework/schema' +import { + GetAllPagesQuery, + GetAllPagesQueryVariables, + PageEdge, +} from '@framework/schema' +import { normalizePages } from '@framework/utils' import type { ShopifyConfig, Provider } from '..' -import { GetAllPagesOperation } from '../../types/page' +import type { GetAllPagesOperation, Page } from '../../types/page' import getAllPagesQuery from '../../utils/queries/get-all-pages-query' export default function getAllPagesOperation({ @@ -25,21 +30,36 @@ export default function getAllPagesOperation({ async function getAllPages({ query = getAllPagesQuery, config, + variables, }: { url?: string config?: Partial + variables?: GetAllPagesQueryVariables preview?: boolean query?: string } = {}): Promise { - const cfg = commerce.getConfig(config) + const { fetch, locale, locales = ['en-US'] } = commerce.getConfig(config) - const { data } = await cfg.fetch< - GetAllPagesQuery, - GetAllPagesQueryVariables - >(query) + const { data } = await fetch( + query, + { + variables, + }, + { + ...(locale && { + headers: { + 'Accept-Language': locale, + }, + }), + } + ) return { - pages: data.pages.edges, + pages: locales.reduce( + (arr, locale) => + arr.concat(normalizePages(data.pages.edges as PageEdge[], locale)), + [] + ), } } diff --git a/framework/shopify/api/operations/get-all-products.ts b/framework/shopify/api/operations/get-all-products.ts index 71114c948..6b8bd1f5e 100644 --- a/framework/shopify/api/operations/get-all-products.ts +++ b/framework/shopify/api/operations/get-all-products.ts @@ -39,12 +39,22 @@ export default function getAllProductsOperation({ config?: Partial preview?: boolean } = {}): Promise { - const cfg = commerce.getConfig(config) + const { fetch, locale } = commerce.getConfig(config) - const { data } = await cfg.fetch< + const { data } = await fetch< GetAllProductsQuery, GetAllProductsQueryVariables - >(query, { variables }) + >( + query, + { variables }, + { + ...(locale && { + headers: { + 'Accept-Language': locale, + }, + }), + } + ) return { products: data.products.edges.map(({ node }) => diff --git a/framework/shopify/api/operations/get-page.ts b/framework/shopify/api/operations/get-page.ts index eef8ff88d..1a8dc9481 100644 --- a/framework/shopify/api/operations/get-page.ts +++ b/framework/shopify/api/operations/get-page.ts @@ -35,11 +35,23 @@ export default function getPageOperation({ config?: Partial preview?: boolean }): Promise { - const cfg = commerce.getConfig(config) + const { fetch, locale } = commerce.getConfig(config) const { data: { node: page }, - } = await cfg.fetch(query) + } = await fetch( + query, + { + variables, + }, + { + ...(locale && { + headers: { + 'Accept-Language': locale, + }, + }), + } + ) return page ? { page } : {} } diff --git a/framework/shopify/api/operations/get-product.ts b/framework/shopify/api/operations/get-product.ts index c628696f7..f7d6b05e0 100644 --- a/framework/shopify/api/operations/get-product.ts +++ b/framework/shopify/api/operations/get-product.ts @@ -20,13 +20,23 @@ export default function getProductOperation({ config?: ShopifyConfig variables?: GetProductBySlugQueryVariables } = {}): Promise { - config = commerce.getConfig(config) + const { fetch, locale } = commerce.getConfig(config) const { data: { productByHandle }, - } = await config.fetch(query, { - variables, - }) + } = await fetch( + query, + { + variables, + }, + { + ...(locale && { + headers: { + 'Accept-Language': locale, + }, + }), + } + ) return { ...(productByHandle && { diff --git a/framework/shopify/api/operations/get-site-info.ts b/framework/shopify/api/operations/get-site-info.ts index f7a626c94..071d68aff 100644 --- a/framework/shopify/api/operations/get-site-info.ts +++ b/framework/shopify/api/operations/get-site-info.ts @@ -26,20 +26,31 @@ export default function getSiteInfoOperation({ async function getSiteInfo({ query = getSiteInfoQuery, config, + variables, }: { query?: string config?: Partial preview?: boolean + variables?: GetSiteInfoQueryVariables } = {}): Promise { const cfg = commerce.getConfig(config) const categories = await getCategories(cfg) const brands = await getBrands(cfg) - - const { data } = await cfg.fetch< - GetSiteInfoQuery, - GetSiteInfoQueryVariables - >(query) + /* + const { fetch, locale } = cfg + const { data } = await fetch( + query, + { variables }, + { + ...(locale && { + headers: { + 'Accept-Language': locale, + }, + }), + } + ) + */ return { categories, diff --git a/framework/shopify/cart/use-add-item.tsx b/framework/shopify/cart/use-add-item.tsx index cce0950e9..5f0809d01 100644 --- a/framework/shopify/cart/use-add-item.tsx +++ b/framework/shopify/cart/use-add-item.tsx @@ -2,18 +2,19 @@ import { useCallback } from 'react' import type { MutationHook } from '@commerce/utils/types' import { CommerceError } from '@commerce/utils/errors' import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' +import type { AddItemHook } from '../types/cart' import useCart from './use-cart' + import { checkoutLineItemAddMutation, getCheckoutId, checkoutToCart, } from '../utils' -import { Cart, CartItemBody } from '../types' import { Mutation, MutationCheckoutLineItemsAddArgs } from '../schema' export default useAddItem as UseAddItem -export const handler: MutationHook = { +export const handler: MutationHook = { fetchOptions: { query: checkoutLineItemAddMutation, }, diff --git a/framework/shopify/cart/use-cart.tsx b/framework/shopify/cart/use-cart.tsx index 5f77360bb..a7cfe9416 100644 --- a/framework/shopify/cart/use-cart.tsx +++ b/framework/shopify/cart/use-cart.tsx @@ -1,22 +1,14 @@ import { useMemo } from 'react' -import useCommerceCart, { - FetchCartInput, - UseCart, -} from '@commerce/cart/use-cart' +import useCommerceCart, { UseCart } from '@commerce/cart/use-cart' -import { Cart } from '../types' import { SWRHook } from '@commerce/utils/types' import { checkoutCreate, checkoutToCart } from '../utils' import getCheckoutQuery from '../utils/queries/get-checkout-query' +import { GetCartHook } from '../types/cart' export default useCommerceCart as UseCart -export const handler: SWRHook< - Cart | null, - {}, - FetchCartInput, - { isEmpty?: boolean } -> = { +export const handler: SWRHook = { fetchOptions: { query: getCheckoutQuery, }, diff --git a/framework/shopify/cart/use-remove-item.tsx b/framework/shopify/cart/use-remove-item.tsx index 8db38eac2..25b78dcf9 100644 --- a/framework/shopify/cart/use-remove-item.tsx +++ b/framework/shopify/cart/use-remove-item.tsx @@ -3,31 +3,29 @@ import type { MutationHookContext, HookFetcherContext, } from '@commerce/utils/types' -import { RemoveCartItemBody } from '@commerce/types' import { ValidationError } from '@commerce/utils/errors' -import useRemoveItem, { - RemoveItemInput as RemoveItemInputBase, - UseRemoveItem, -} from '@commerce/cart/use-remove-item' +import useRemoveItem, { UseRemoveItem } from '@commerce/cart/use-remove-item' +import type { Cart, LineItem, RemoveItemHook } from '../types/cart' import useCart from './use-cart' + +export type RemoveItemFn = T extends LineItem + ? (input?: RemoveItemActionInput) => Promise + : (input: RemoveItemActionInput) => Promise + +export type RemoveItemActionInput = T extends LineItem + ? Partial + : RemoveItemHook['actionInput'] + +export default useRemoveItem as UseRemoveItem + import { checkoutLineItemRemoveMutation, getCheckoutId, checkoutToCart, } from '../utils' -import { Cart, LineItem } from '../types' + import { Mutation, MutationCheckoutLineItemsRemoveArgs } from '../schema' -export type RemoveItemFn = T extends LineItem - ? (input?: RemoveItemInput) => Promise - : (input: RemoveItemInput) => Promise - -export type RemoveItemInput = T extends LineItem - ? Partial - : RemoveItemInputBase - -export default useRemoveItem as UseRemoveItem - export const handler = { fetchOptions: { query: checkoutLineItemRemoveMutation, @@ -36,16 +34,14 @@ export const handler = { input: { itemId }, options, fetch, - }: HookFetcherContext) { + }: HookFetcherContext) { const data = await fetch({ ...options, variables: { checkoutId: getCheckoutId(), lineItemIds: [itemId] }, }) return checkoutToCart(data.checkoutLineItemsRemove) }, - useHook: ({ - fetch, - }: MutationHookContext) => < + useHook: ({ fetch }: MutationHookContext) => < T extends LineItem | undefined = undefined >( ctx: { item?: T } = {} diff --git a/framework/shopify/cart/use-update-item.tsx b/framework/shopify/cart/use-update-item.tsx index 49dd6be14..3f1cf4315 100644 --- a/framework/shopify/cart/use-update-item.tsx +++ b/framework/shopify/cart/use-update-item.tsx @@ -5,21 +5,21 @@ import type { MutationHookContext, } from '@commerce/utils/types' import { ValidationError } from '@commerce/utils/errors' -import useUpdateItem, { - UpdateItemInput as UpdateItemInputBase, - UseUpdateItem, -} from '@commerce/cart/use-update-item' +import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item' import useCart from './use-cart' import { handler as removeItemHandler } from './use-remove-item' -import type { Cart, LineItem, UpdateCartItemBody } from '../types' -import { checkoutToCart } from '../utils' -import { getCheckoutId, checkoutLineItemUpdateMutation } from '../utils' +import type { UpdateItemHook, LineItem } from '../types/cart' +import { + getCheckoutId, + checkoutLineItemUpdateMutation, + checkoutToCart, +} from '../utils' import { Mutation, MutationCheckoutLineItemsUpdateArgs } from '../schema' -export type UpdateItemInput = T extends LineItem - ? Partial> - : UpdateItemInputBase +export type UpdateItemActionInput = T extends LineItem + ? Partial + : UpdateItemHook['actionInput'] export default useUpdateItem as UseUpdateItem @@ -31,7 +31,7 @@ export const handler = { input: { itemId, item }, options, fetch, - }: HookFetcherContext) { + }: HookFetcherContext) { if (Number.isInteger(item.quantity)) { // Also allow the update hook to remove an item if the quantity is lower than 1 if (item.quantity! < 1) { @@ -64,9 +64,7 @@ export const handler = { return checkoutToCart(checkoutLineItemsUpdate) }, - useHook: ({ - fetch, - }: MutationHookContext) => < + useHook: ({ fetch }: MutationHookContext) => < T extends LineItem | undefined = undefined >( ctx: { @@ -78,7 +76,7 @@ export const handler = { const { mutate } = useCart() as any return useCallback( - debounce(async (input: UpdateItemInput) => { + debounce(async (input: UpdateItemActionInput) => { const itemId = input.id ?? item?.id const productId = input.productId ?? item?.productId const variantId = input.productId ?? item?.variantId diff --git a/framework/shopify/customer/use-customer.tsx b/framework/shopify/customer/use-customer.tsx index 7b600838e..be097fe80 100644 --- a/framework/shopify/customer/use-customer.tsx +++ b/framework/shopify/customer/use-customer.tsx @@ -1,18 +1,19 @@ import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' -import { Customer } from '@commerce/types' +import type { CustomerHook } from '../types/customer' import { SWRHook } from '@commerce/utils/types' import { getCustomerQuery, getCustomerToken } from '../utils' +import { GetCustomerQuery, GetCustomerQueryVariables } from '../schema' export default useCustomer as UseCustomer -export const handler: SWRHook = { +export const handler: SWRHook = { fetchOptions: { query: getCustomerQuery, }, async fetcher({ options, fetch }) { const customerAccessToken = getCustomerToken() if (customerAccessToken) { - const data = await fetch({ + const data = await fetch({ ...options, variables: { customerAccessToken: getCustomerToken() }, }) diff --git a/framework/shopify/fetcher.ts b/framework/shopify/fetcher.ts index a69150503..9e57333c6 100644 --- a/framework/shopify/fetcher.ts +++ b/framework/shopify/fetcher.ts @@ -8,13 +8,17 @@ const fetcher: Fetcher = async ({ variables, query, }) => { + const { locale, ...vars } = variables return handleFetchResponse( await fetch(url, { method, - body: JSON.stringify({ query, variables }), + body: JSON.stringify({ query, variables: vars }), headers: { 'X-Shopify-Storefront-Access-Token': API_TOKEN!, 'Content-Type': 'application/json', + ...(locale && { + 'Accept-Language': locale, + }), }, }) ) diff --git a/framework/shopify/product/use-search.tsx b/framework/shopify/product/use-search.tsx index 16ac8b249..9588b65a2 100644 --- a/framework/shopify/product/use-search.tsx +++ b/framework/shopify/product/use-search.tsx @@ -4,9 +4,11 @@ import useSearch, { UseSearch } from '@commerce/product/use-search' import { CollectionEdge, GetAllProductsQuery, + GetProductsFromCollectionQueryVariables, Product as ShopifyProduct, ProductEdge, } from '../schema' + import { getAllProductsQuery, getCollectionProductsQuery, @@ -14,27 +16,19 @@ import { normalizeProduct, } from '../utils' -import { Product } from '@commerce/types' - -export default useSearch as UseSearch +import type { SearchProductsHook } from '../types/product' export type SearchProductsInput = { search?: string - categoryId?: string - brandId?: string + categoryId?: number + brandId?: number sort?: string + locale?: string } -export type SearchProductsData = { - products: Product[] - found: boolean -} +export default useSearch as UseSearch -export const handler: SWRHook< - SearchProductsData, - SearchProductsInput, - SearchProductsInput -> = { +export const handler: SWRHook = { fetchOptions: { query: getAllProductsQuery, }, @@ -46,7 +40,10 @@ export const handler: SWRHook< // change the query to getCollectionProductsQuery when categoryId is set if (categoryId) { - const data = await fetch({ + const data = await fetch< + CollectionEdge, + GetProductsFromCollectionQueryVariables + >({ query: getCollectionProductsQuery, method, variables, @@ -81,6 +78,7 @@ export const handler: SWRHook< ['categoryId', input.categoryId], ['brandId', input.brandId], ['sort', input.sort], + ['locale', input.locale], ], swrOptions: { revalidateOnFocus: false, diff --git a/framework/shopify/provider.ts b/framework/shopify/provider.ts index 00db5c1d3..3cd24817b 100644 --- a/framework/shopify/provider.ts +++ b/framework/shopify/provider.ts @@ -24,4 +24,4 @@ export const shopifyProvider = { auth: { useLogin, useLogout, useSignup }, } -export type ShopifyProvider = typeof shopifyProvider +export type ShopifyProvider = any diff --git a/framework/shopify/types/cart.ts b/framework/shopify/types/cart.ts index d792243d8..09410740a 100644 --- a/framework/shopify/types/cart.ts +++ b/framework/shopify/types/cart.ts @@ -10,23 +10,10 @@ export type ShopifyCart = {} export type Cart = Core.Cart & { lineItems: Core.LineItem[] + url?: string } -export type OptionSelections = { - option_id: number - option_value: number | string -} - -export type CartItemBody = Core.CartItemBody & { - productId: string // The product id is always required for BC - optionSelections?: OptionSelections -} - -export type CartTypes = { - cart: Cart - item: Core.LineItem - itemBody: CartItemBody -} +export type CartTypes = Core.CartTypes export type CartHooks = Core.CartHooks diff --git a/framework/shopify/types/checkout.ts b/framework/shopify/types/checkout.ts new file mode 100644 index 000000000..4e2412ef6 --- /dev/null +++ b/framework/shopify/types/checkout.ts @@ -0,0 +1 @@ +export * from '@commerce/types/checkout' diff --git a/framework/shopify/types/common.ts b/framework/shopify/types/common.ts new file mode 100644 index 000000000..b52c33a4d --- /dev/null +++ b/framework/shopify/types/common.ts @@ -0,0 +1 @@ +export * from '@commerce/types/common' diff --git a/framework/shopify/types/index.ts b/framework/shopify/types/index.ts index a0792d798..7ab0b7f64 100644 --- a/framework/shopify/types/index.ts +++ b/framework/shopify/types/index.ts @@ -1,2 +1,25 @@ -export * from '@commerce/types' -export * from './cart' +import * as Cart from './cart' +import * as Checkout from './checkout' +import * as Common from './common' +import * as Customer from './customer' +import * as Login from './login' +import * as Logout from './logout' +import * as Page from './page' +import * as Product from './product' +import * as Signup from './signup' +import * as Site from './site' +import * as Wishlist from './wishlist' + +export type { + Cart, + Checkout, + Common, + Customer, + Login, + Logout, + Page, + Product, + Signup, + Site, + Wishlist, +} diff --git a/framework/shopify/types/wishlist.ts b/framework/shopify/types/wishlist.ts new file mode 100644 index 000000000..8907fbf82 --- /dev/null +++ b/framework/shopify/types/wishlist.ts @@ -0,0 +1 @@ +export * from '@commerce/types/wishlist' diff --git a/framework/shopify/utils/get-categories.ts b/framework/shopify/utils/get-categories.ts index cce4b2ad7..f217ff49b 100644 --- a/framework/shopify/utils/get-categories.ts +++ b/framework/shopify/utils/get-categories.ts @@ -8,12 +8,25 @@ export type Category = { path: string } -const getCategories = async (config: ShopifyConfig): Promise => { - const { data } = await config.fetch(getSiteCollectionsQuery, { - variables: { - first: 250, +const getCategories = async ({ + fetch, + locale, +}: ShopifyConfig): Promise => { + const { data } = await fetch( + getSiteCollectionsQuery, + { + variables: { + first: 250, + }, }, - }) + { + ...(locale && { + headers: { + 'Accept-Language': locale, + }, + }), + } + ) return ( data.collections?.edges?.map( diff --git a/framework/shopify/utils/get-search-variables.ts b/framework/shopify/utils/get-search-variables.ts index c1b40ae5d..fadc698d6 100644 --- a/framework/shopify/utils/get-search-variables.ts +++ b/framework/shopify/utils/get-search-variables.ts @@ -1,12 +1,13 @@ import getSortVariables from './get-sort-variables' -import type { SearchProductsInput } from '../product/use-search' +import { SearchProductsBody } from '../types/product' export const getSearchVariables = ({ brandId, search, categoryId, sort, -}: SearchProductsInput) => { + locale, +}: SearchProductsBody) => { let query = '' if (search) { @@ -21,6 +22,9 @@ export const getSearchVariables = ({ categoryId, query, ...getSortVariables(sort, !!categoryId), + ...(locale && { + locale, + }), } } diff --git a/framework/shopify/utils/normalize.ts b/framework/shopify/utils/normalize.ts index 472723afe..b05344bca 100644 --- a/framework/shopify/utils/normalize.ts +++ b/framework/shopify/utils/normalize.ts @@ -1,4 +1,6 @@ -import { Product } from '@commerce/types' +import type { Page } from '../types/page' +import type { Product } from '../types/product' +import type { Cart, LineItem } from '../types/cart' import { Product as ShopifyProduct, @@ -9,10 +11,10 @@ import { ProductVariantConnection, MoneyV2, ProductOption, + Page as ShopifyPage, + PageEdge, } from '../schema' -import type { Cart, LineItem } from '../types' - const money = ({ amount, currencyCode }: MoneyV2) => { return { value: +amount, @@ -152,12 +154,18 @@ function normalizeLineItem({ discounts: [], options: // By default Shopify adds a default variant with default names, we're removing it. https://community.shopify.com/c/Shopify-APIs-SDKs/Adding-new-product-variant-is-automatically-adding-quot-Default/td-p/358095 - variant?.title == 'Default Title' - ? [] - : [ - { - value: variant?.title, - }, - ], + variant?.title == 'Default Title' ? [] : variant?.selectedOptions, } } + +export const normalizePage = ( + { title: name, handle, ...page }: ShopifyPage, + locale: string +): Page => ({ + ...page, + url: `/${locale}/${handle}`, + name, +}) + +export const normalizePages = (edges: PageEdge[], locale: string): Page[] => + edges?.map((edge) => normalizePage(edge.node, locale)) diff --git a/pages/[...pages].tsx b/pages/[...pages].tsx index 3e6ef65c9..7467a76b6 100644 --- a/pages/[...pages].tsx +++ b/pages/[...pages].tsx @@ -14,8 +14,9 @@ export async function getStaticProps({ preview, params, locale, + locales, }: GetStaticPropsContext<{ pages: string[] }>) { - const config = { locale } + const config = { locale, locales } const { pages } = await commerce.getAllPages({ preview, config }) const path = params?.pages.join('/') const slug = locale ? `${locale}/${path}` : path @@ -42,7 +43,8 @@ export async function getStaticProps({ } export async function getStaticPaths({ locales }: GetStaticPathsContext) { - const { pages } = await commerce.getAllPages() + const config = { locales } + const { pages } = await commerce.getAllPages({ config }) const [invalidPaths, log] = missingLocaleInPages() const paths = pages .map((page) => page.url) diff --git a/pages/blog.tsx b/pages/blog.tsx index c1bdc4624..6daf1297e 100644 --- a/pages/blog.tsx +++ b/pages/blog.tsx @@ -6,8 +6,9 @@ import { Container } from '@components/ui' export async function getStaticProps({ preview, locale, + locales, }: GetStaticPropsContext) { - const config = { locale } + const config = { locale, locales } const { pages } = await commerce.getAllPages({ config, preview }) return { props: { pages }, diff --git a/pages/cart.tsx b/pages/cart.tsx index d14a7bfd2..4e1358943 100644 --- a/pages/cart.tsx +++ b/pages/cart.tsx @@ -10,8 +10,9 @@ import { CartItem } from '@components/cart' export async function getStaticProps({ preview, locale, + locales, }: GetStaticPropsContext) { - const config = { locale } + const config = { locale, locales } const { pages } = await commerce.getAllPages({ config, preview }) return { props: { pages }, diff --git a/pages/index.tsx b/pages/index.tsx index 785da555f..86d7a9da4 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -8,8 +8,9 @@ import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next' export async function getStaticProps({ preview, locale, + locales, }: GetStaticPropsContext) { - const config = { locale } + const config = { locale, locales } const { products } = await commerce.getAllProducts({ variables: { first: 12 }, config, diff --git a/pages/orders.tsx b/pages/orders.tsx index c43ff9e5a..5a6a26d43 100644 --- a/pages/orders.tsx +++ b/pages/orders.tsx @@ -7,8 +7,9 @@ import { Container, Text } from '@components/ui' export async function getStaticProps({ preview, locale, + locales, }: GetStaticPropsContext) { - const config = { locale } + const config = { locale, locales } const { pages } = await commerce.getAllPages({ config, preview }) return { props: { pages }, diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx index bf71ac21e..5415e67f9 100644 --- a/pages/product/[slug].tsx +++ b/pages/product/[slug].tsx @@ -11,9 +11,10 @@ import { ProductView } from '@components/product' export async function getStaticProps({ params, locale, + locales, preview, }: GetStaticPropsContext<{ slug: string }>) { - const config = { locale } + const config = { locale, locales } const { pages } = await commerce.getAllPages({ config, preview }) const { product } = await commerce.getProduct({ variables: { slug: params!.slug }, diff --git a/pages/profile.tsx b/pages/profile.tsx index b73469fa5..b569025da 100644 --- a/pages/profile.tsx +++ b/pages/profile.tsx @@ -7,8 +7,9 @@ import { Container, Text } from '@components/ui' export async function getStaticProps({ preview, locale, + locales, }: GetStaticPropsContext) { - const config = { locale } + const config = { locale, locales } const { pages } = await commerce.getAllPages({ config, preview }) return { props: { pages }, diff --git a/pages/search.tsx b/pages/search.tsx index 53452b74a..f37b3ef0d 100644 --- a/pages/search.tsx +++ b/pages/search.tsx @@ -18,7 +18,7 @@ import { getDesignerPath, useSearchMeta, } from '@lib/search' -import { Product } from '@commerce/types' +import type { Product } from '@framework/types/product' // TODO(bc) Remove this. This should come from the API import getSlug from '@lib/get-slug' @@ -34,8 +34,9 @@ const SORT = Object.entries({ export async function getStaticProps({ preview, locale, + locales, }: GetStaticPropsContext) { - const config = { locale } + const config = { locale, locales } const { pages } = await commerce.getAllPages({ config, preview }) const { categories, brands } = await commerce.getSiteInfo({ config, preview }) return { @@ -55,7 +56,7 @@ export default function Search({ const [toggleFilter, setToggleFilter] = useState(false) const router = useRouter() - const { asPath } = router + const { asPath, locale } = router const { q, sort } = router.query // `q` can be included but because categories and designers can't be searched // in the same way of products, it's better to ignore the search input if one @@ -75,6 +76,7 @@ export default function Search({ categoryId: activeCategory?.entityId, brandId: activeBrand?.entityId, sort: typeof sort === 'string' ? sort : '', + locale, }) const handleClick = (event: any, filter: string) => { diff --git a/pages/wishlist.tsx b/pages/wishlist.tsx index 9927c536a..a667d33f8 100644 --- a/pages/wishlist.tsx +++ b/pages/wishlist.tsx @@ -11,6 +11,7 @@ import useWishlist from '@framework/wishlist/use-wishlist' export async function getStaticProps({ preview, locale, + locales, }: GetStaticPropsContext) { // Disabling page if Feature is not available if (!process.env.COMMERCE_WISHLIST_ENABLED) { @@ -19,7 +20,7 @@ export async function getStaticProps({ } } - const config = { locale } + const config = { locale, locales } const { pages } = await commerce.getAllPages({ config, preview }) return { props: {