From 4d85b43a3006d9db270da80ac9b6b543af337160 Mon Sep 17 00:00:00 2001 From: ghoskin Date: Mon, 14 Jun 2021 13:37:18 -0700 Subject: [PATCH 01/11] Update Swell Provider (#359) * fix update cart item * update types * update checkout * update get-page, cleanup types * revert change to incorrect file * cleanup Co-authored-by: Greg Hoskin --- framework/swell/api/checkout/index.ts | 20 ------ framework/swell/api/customers/login.ts | 1 - framework/swell/api/endpoints/cart.ts | 1 + .../swell/api/endpoints/catalog/products.ts | 1 + .../swell/api/endpoints/checkout/index.ts | 30 +++++++++ framework/swell/api/endpoints/customer.ts | 1 + framework/swell/api/endpoints/login.ts | 1 + framework/swell/api/endpoints/logout.ts | 1 + framework/swell/api/endpoints/signup.ts | 1 + framework/swell/api/endpoints/wishlist.ts | 1 + framework/swell/api/index.ts | 59 ++++++++--------- .../swell/api/operations/get-all-pages.ts | 45 +++++++++++++ .../api/operations/get-all-product-paths.ts | 48 ++++++++++++++ .../swell/api/operations/get-all-products.ts | 43 +++++++++++++ framework/swell/api/operations/get-page.ts | 63 ++++++++++++++----- framework/swell/api/operations/get-product.ts | 33 ++++++++++ .../swell/api/operations/get-site-info.ts | 37 +++++++++++ framework/swell/api/operations/login.ts | 46 ++++++++++++++ .../swell/api/utils/create-api-handler.ts | 58 ----------------- framework/swell/auth/use-login.tsx | 4 +- framework/swell/auth/use-logout.tsx | 3 +- framework/swell/auth/use-signup.tsx | 10 +-- framework/swell/cart/use-add-item.tsx | 6 +- framework/swell/cart/use-cart.tsx | 4 +- framework/swell/cart/use-remove-item.tsx | 60 ++++++------------ framework/swell/cart/use-update-item.tsx | 33 +++++----- framework/swell/cart/utils/checkout-create.ts | 2 +- framework/swell/cart/utils/fetcher.ts | 33 ---------- framework/swell/common/get-all-pages.ts | 37 ----------- framework/swell/common/get-page.ts | 33 ---------- framework/swell/common/get-site-info.ts | 31 --------- framework/swell/customer/use-customer.tsx | 27 +------- .../swell/product/get-all-collections.ts | 28 --------- .../swell/product/get-all-product-paths.ts | 39 ------------ framework/swell/product/get-all-products.ts | 36 ----------- framework/swell/product/get-product.ts | 32 ---------- framework/swell/product/index.ts | 2 + framework/swell/product/use-search.tsx | 18 +----- framework/swell/provider.ts | 9 ++- framework/swell/types.ts | 30 +++------ framework/swell/types/cart.ts | 1 + framework/swell/types/checkout.ts | 1 + framework/swell/types/common.ts | 1 + framework/swell/types/customer.ts | 1 + framework/swell/types/index.ts | 25 ++++++++ framework/swell/types/login.ts | 11 ++++ framework/swell/types/logout.ts | 1 + framework/swell/types/page.ts | 1 + framework/swell/types/product.ts | 1 + framework/swell/types/signup.ts | 1 + framework/swell/types/site.ts | 1 + framework/swell/types/wishlist.ts | 1 + framework/swell/utils/get-categories.ts | 2 +- framework/swell/utils/normalize.ts | 33 ++++++---- .../swell/swell-js.d.ts => swell-js.d.ts | 0 55 files changed, 503 insertions(+), 545 deletions(-) delete mode 100644 framework/swell/api/checkout/index.ts delete mode 100644 framework/swell/api/customers/login.ts create mode 100644 framework/swell/api/endpoints/cart.ts create mode 100644 framework/swell/api/endpoints/catalog/products.ts create mode 100644 framework/swell/api/endpoints/checkout/index.ts create mode 100644 framework/swell/api/endpoints/customer.ts create mode 100644 framework/swell/api/endpoints/login.ts create mode 100644 framework/swell/api/endpoints/logout.ts create mode 100644 framework/swell/api/endpoints/signup.ts create mode 100644 framework/swell/api/endpoints/wishlist.ts create mode 100644 framework/swell/api/operations/get-all-pages.ts create mode 100644 framework/swell/api/operations/get-all-product-paths.ts create mode 100644 framework/swell/api/operations/get-all-products.ts create mode 100644 framework/swell/api/operations/get-product.ts create mode 100644 framework/swell/api/operations/get-site-info.ts create mode 100644 framework/swell/api/operations/login.ts delete mode 100644 framework/swell/api/utils/create-api-handler.ts delete mode 100644 framework/swell/cart/utils/fetcher.ts delete mode 100644 framework/swell/common/get-all-pages.ts delete mode 100644 framework/swell/common/get-page.ts delete mode 100644 framework/swell/common/get-site-info.ts delete mode 100644 framework/swell/product/get-all-collections.ts delete mode 100644 framework/swell/product/get-all-product-paths.ts delete mode 100644 framework/swell/product/get-all-products.ts delete mode 100644 framework/swell/product/get-product.ts create mode 100644 framework/swell/product/index.ts create mode 100644 framework/swell/types/cart.ts create mode 100644 framework/swell/types/checkout.ts create mode 100644 framework/swell/types/common.ts create mode 100644 framework/swell/types/customer.ts create mode 100644 framework/swell/types/index.ts create mode 100644 framework/swell/types/login.ts create mode 100644 framework/swell/types/logout.ts create mode 100644 framework/swell/types/page.ts create mode 100644 framework/swell/types/product.ts create mode 100644 framework/swell/types/signup.ts create mode 100644 framework/swell/types/site.ts create mode 100644 framework/swell/types/wishlist.ts rename framework/swell/swell-js.d.ts => swell-js.d.ts (100%) diff --git a/framework/swell/api/checkout/index.ts b/framework/swell/api/checkout/index.ts deleted file mode 100644 index 0759e2abc..000000000 --- a/framework/swell/api/checkout/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import createApiHandler, { SwellApiHandler } from '../utils/create-api-handler' - -import { SWELL_CHECKOUT_URL_COOKIE } from '../../const' - -import { getConfig } from '..' - -const checkoutApi: SwellApiHandler = async (req, res, config) => { - config = getConfig() - - const { cookies } = req - const checkoutUrl = cookies[SWELL_CHECKOUT_URL_COOKIE] - - if (checkoutUrl) { - res.redirect(checkoutUrl) - } else { - res.redirect('/cart') - } -} - -export default createApiHandler(checkoutApi, {}, {}) diff --git a/framework/swell/api/customers/login.ts b/framework/swell/api/customers/login.ts deleted file mode 100644 index ea9b101e1..000000000 --- a/framework/swell/api/customers/login.ts +++ /dev/null @@ -1 +0,0 @@ -export default function () {} diff --git a/framework/swell/api/endpoints/cart.ts b/framework/swell/api/endpoints/cart.ts new file mode 100644 index 000000000..d09c976c3 --- /dev/null +++ b/framework/swell/api/endpoints/cart.ts @@ -0,0 +1 @@ +export default function (_commerce: any) {} diff --git a/framework/swell/api/endpoints/catalog/products.ts b/framework/swell/api/endpoints/catalog/products.ts new file mode 100644 index 000000000..d09c976c3 --- /dev/null +++ b/framework/swell/api/endpoints/catalog/products.ts @@ -0,0 +1 @@ +export default function (_commerce: any) {} diff --git a/framework/swell/api/endpoints/checkout/index.ts b/framework/swell/api/endpoints/checkout/index.ts new file mode 100644 index 000000000..ab17a3767 --- /dev/null +++ b/framework/swell/api/endpoints/checkout/index.ts @@ -0,0 +1,30 @@ +import { CommerceAPI, createEndpoint, GetAPISchema } from '@commerce/api' +import { CheckoutSchema } from '@commerce/types/checkout' +import { SWELL_CHECKOUT_URL_COOKIE } from '../../../const' +import checkoutEndpoint from '@commerce/api/endpoints/checkout' + +const checkout: CheckoutEndpoint['handlers']['checkout'] = async ({ + req, + res, + config, +}) => { + const { cookies } = req + const checkoutUrl = cookies[SWELL_CHECKOUT_URL_COOKIE] + + if (checkoutUrl) { + res.redirect(checkoutUrl) + } else { + res.redirect('/cart') + } +} +export const handlers: CheckoutEndpoint['handlers'] = { checkout } + +export type CheckoutAPI = GetAPISchema +export type CheckoutEndpoint = CheckoutAPI['endpoint'] + +const checkoutApi = createEndpoint({ + handler: checkoutEndpoint, + handlers, +}) + +export default checkoutApi diff --git a/framework/swell/api/endpoints/customer.ts b/framework/swell/api/endpoints/customer.ts new file mode 100644 index 000000000..d09c976c3 --- /dev/null +++ b/framework/swell/api/endpoints/customer.ts @@ -0,0 +1 @@ +export default function (_commerce: any) {} diff --git a/framework/swell/api/endpoints/login.ts b/framework/swell/api/endpoints/login.ts new file mode 100644 index 000000000..d09c976c3 --- /dev/null +++ b/framework/swell/api/endpoints/login.ts @@ -0,0 +1 @@ +export default function (_commerce: any) {} diff --git a/framework/swell/api/endpoints/logout.ts b/framework/swell/api/endpoints/logout.ts new file mode 100644 index 000000000..d09c976c3 --- /dev/null +++ b/framework/swell/api/endpoints/logout.ts @@ -0,0 +1 @@ +export default function (_commerce: any) {} diff --git a/framework/swell/api/endpoints/signup.ts b/framework/swell/api/endpoints/signup.ts new file mode 100644 index 000000000..d09c976c3 --- /dev/null +++ b/framework/swell/api/endpoints/signup.ts @@ -0,0 +1 @@ +export default function (_commerce: any) {} diff --git a/framework/swell/api/endpoints/wishlist.ts b/framework/swell/api/endpoints/wishlist.ts new file mode 100644 index 000000000..d09c976c3 --- /dev/null +++ b/framework/swell/api/endpoints/wishlist.ts @@ -0,0 +1 @@ +export default function (_commerce: any) {} diff --git a/framework/swell/api/index.ts b/framework/swell/api/index.ts index 1494af9c7..463c42fae 100644 --- a/framework/swell/api/index.ts +++ b/framework/swell/api/index.ts @@ -1,5 +1,8 @@ -import type { CommerceAPIConfig } from '@commerce/api' - +import { + CommerceAPI, + CommerceAPIConfig, + getCommerceApi as commerceApi, +} from '@commerce/api' import { SWELL_CHECKOUT_ID_COOKIE, SWELL_CUSTOMER_TOKEN_COOKIE, @@ -7,31 +10,19 @@ import { } from '../const' import fetchApi from './utils/fetch-swell-api' +import login from './operations/login' +import getAllPages from './operations/get-all-pages' +import getPage from './operations/get-page' +import getSiteInfo from './operations/get-site-info' +import getAllProductPaths from './operations/get-all-product-paths' +import getAllProducts from './operations/get-all-products' +import getProduct from './operations/get-product' export interface SwellConfig extends CommerceAPIConfig { fetch: any } -export class Config { - private config: SwellConfig - - constructor(config: SwellConfig) { - this.config = config - } - - getConfig(userConfig: Partial = {}) { - return Object.entries(userConfig).reduce( - (cfg, [key, value]) => Object.assign(cfg, { [key]: value }), - { ...this.config } - ) - } - - setConfig(newConfig: Partial) { - Object.assign(this.config, newConfig) - } -} - -const config = new Config({ +const config: SwellConfig = { locale: 'en-US', commerceUrl: '', apiToken: ''!, @@ -39,12 +30,24 @@ const config = new Config({ cartCookieMaxAge: SWELL_COOKIE_EXPIRE, fetch: fetchApi, customerCookie: SWELL_CUSTOMER_TOKEN_COOKIE, -}) - -export function getConfig(userConfig?: Partial) { - return config.getConfig(userConfig) } -export function setConfig(newConfig: Partial) { - return config.setConfig(newConfig) +const operations = { + login, + getAllPages, + getPage, + getSiteInfo, + getAllProductPaths, + getAllProducts, + getProduct, +} + +export const provider = { config, operations } + +export type Provider = typeof provider + +export function getCommerceApi

( + customProvider: P = provider as any +): CommerceAPI

{ + return commerceApi(customProvider) } diff --git a/framework/swell/api/operations/get-all-pages.ts b/framework/swell/api/operations/get-all-pages.ts new file mode 100644 index 000000000..6abaa155c --- /dev/null +++ b/framework/swell/api/operations/get-all-pages.ts @@ -0,0 +1,45 @@ +import { Provider, SwellConfig } from '..' +import type { OperationContext } from '@commerce/api/operations' +import type { Page } from '../../types/page' + +export type GetAllPagesResult< + T extends { pages: any[] } = { pages: Page[] } +> = T + +export default function getAllPagesOperation({ + commerce, +}: OperationContext) { + async function getAllPages(opts?: { + config?: Partial + preview?: boolean + }): Promise + + async function getAllPages(opts: { + url: string + config?: Partial + preview?: boolean + }): Promise> + + async function getAllPages({ + config: cfg, + preview, + }: { + url?: string + config?: Partial + preview?: boolean + } = {}): Promise { + const config = commerce.getConfig(cfg) + const { locale, fetch } = config + const data = await fetch('content', 'list', ['pages']) + const pages = + data?.results?.map(({ slug, ...rest }: { slug: string }) => ({ + url: `/${locale}/${slug}`, + ...rest, + })) ?? [] + return { + pages, + } + } + + return getAllPages +} diff --git a/framework/swell/api/operations/get-all-product-paths.ts b/framework/swell/api/operations/get-all-product-paths.ts new file mode 100644 index 000000000..4d95253e8 --- /dev/null +++ b/framework/swell/api/operations/get-all-product-paths.ts @@ -0,0 +1,48 @@ +import { SwellProduct } from '../../types' +import { SwellConfig, Provider } from '..' +import { OperationContext, OperationOptions } from '@commerce/api/operations' +import { GetAllProductPathsOperation } from '@commerce/types/product' + +export default function getAllProductPathsOperation({ + commerce, +}: OperationContext) { + async function getAllProductPaths< + T extends GetAllProductPathsOperation + >(opts?: { + variables?: T['variables'] + config?: SwellConfig + }): Promise + + async function getAllProductPaths( + opts: { + variables?: T['variables'] + config?: SwellConfig + } & OperationOptions + ): Promise + + async function getAllProductPaths({ + variables, + config: cfg, + }: { + query?: string + variables?: T['variables'] + config?: SwellConfig + } = {}): Promise { + const config = commerce.getConfig(cfg) + // RecursivePartial forces the method to check for every prop in the data, which is + // required in case there's a custom `query` + const { results } = await config.fetch('products', 'list', [ + { + limit: variables?.first, + }, + ]) + + return { + products: results?.map(({ slug: handle }: SwellProduct) => ({ + path: `/${handle}`, + })), + } + } + + return getAllProductPaths +} diff --git a/framework/swell/api/operations/get-all-products.ts b/framework/swell/api/operations/get-all-products.ts new file mode 100644 index 000000000..7e8e99a5c --- /dev/null +++ b/framework/swell/api/operations/get-all-products.ts @@ -0,0 +1,43 @@ +import { normalizeProduct } from '../../utils/normalize' +import { SwellProduct } from '../../types' +import { Product } from '@commerce/types/product' +import { Provider, SwellConfig } from '../' +import { OperationContext } from '@commerce/api/operations' + +export type ProductVariables = { first?: number } + +export default function getAllProductsOperation({ + commerce, +}: OperationContext) { + async function getAllProducts(opts?: { + variables?: ProductVariables + config?: Partial + preview?: boolean + }): Promise<{ products: Product[] }> + + async function getAllProducts({ + config: cfg, + variables = { first: 250 }, + }: { + query?: string + variables?: ProductVariables + config?: Partial + preview?: boolean + } = {}): Promise<{ products: Product[] | any[] }> { + const config = commerce.getConfig(cfg) + const { results } = await config.fetch('products', 'list', [ + { + limit: variables.first, + }, + ]) + const products = results.map((product: SwellProduct) => + normalizeProduct(product) + ) + + return { + products, + } + } + + return getAllProducts +} diff --git a/framework/swell/api/operations/get-page.ts b/framework/swell/api/operations/get-page.ts index b04002dda..99fbac04d 100644 --- a/framework/swell/api/operations/get-page.ts +++ b/framework/swell/api/operations/get-page.ts @@ -1,25 +1,54 @@ import { Page } from '../../schema' -import { SwellConfig, getConfig } from '..' +import { SwellConfig, Provider } from '..' +import { OperationContext, OperationOptions } from '@commerce/api/operations' +import { GetPageOperation } from '../../types/page' export type GetPageResult = T export type PageVariables = { - id: string + id: number } -async function getPage({ - url, - variables, - config, - preview, -}: { - url?: string - variables: PageVariables - config?: SwellConfig - preview?: boolean -}): Promise { - config = getConfig(config) - return {} -} +export default function getPageOperation({ + commerce, +}: OperationContext) { + async function getPage(opts: { + variables: T['variables'] + config?: Partial + preview?: boolean + }): Promise -export default getPage + async function getPage( + opts: { + variables: T['variables'] + config?: Partial + preview?: boolean + } & OperationOptions + ): Promise + + async function getPage({ + variables, + config, + }: { + query?: string + variables: T['variables'] + config?: Partial + preview?: boolean + }): Promise { + const { fetch, locale = 'en-US' } = commerce.getConfig(config) + const id = variables.id + const result = await fetch('content', 'get', ['pages', id]) + const page = result + + return { + page: page + ? { + ...page, + url: `/${locale}/${page.slug}`, + } + : null, + } + } + + return getPage +} diff --git a/framework/swell/api/operations/get-product.ts b/framework/swell/api/operations/get-product.ts new file mode 100644 index 000000000..c9a3d6f1d --- /dev/null +++ b/framework/swell/api/operations/get-product.ts @@ -0,0 +1,33 @@ +import { normalizeProduct } from '../../utils' + +import { Product } from '@commerce/types/product' +import { OperationContext } from '@commerce/api/operations' +import { Provider, SwellConfig } from '../' + +export default function getProductOperation({ + commerce, +}: OperationContext) { + async function getProduct({ + variables, + config: cfg, + }: { + query?: string + variables: { slug: string } + config?: Partial + preview?: boolean + }): Promise { + const config = commerce.getConfig(cfg) + + const product = await config.fetch('products', 'get', [variables.slug]) + + if (product && product.variants) { + product.variants = product.variants?.results + } + + return { + product: product ? normalizeProduct(product) : null, + } + } + + return getProduct +} diff --git a/framework/swell/api/operations/get-site-info.ts b/framework/swell/api/operations/get-site-info.ts new file mode 100644 index 000000000..36fcebf01 --- /dev/null +++ b/framework/swell/api/operations/get-site-info.ts @@ -0,0 +1,37 @@ +import getCategories from '../../utils/get-categories' +import getVendors, { Brands } from '../../utils/get-vendors' +import { Provider, SwellConfig } from '../' +import { OperationContext } from '@commerce/api/operations' +import { Category } from '@commerce/types/site' + +export type GetSiteInfoResult< + T extends { categories: any[]; brands: any[] } = { + categories: Category[] + brands: Brands + } +> = T + +export default function getSiteInfoOperation({ + commerce, +}: OperationContext) { + async function getSiteInfo({ + variables, + config: cfg, + }: { + query?: string + variables?: any + config?: Partial + preview?: boolean + } = {}): Promise { + const config = commerce.getConfig(cfg) + const categories = await getCategories(config) + const brands = await getVendors(config) + + return { + categories, + brands, + } + } + + return getSiteInfo +} diff --git a/framework/swell/api/operations/login.ts b/framework/swell/api/operations/login.ts new file mode 100644 index 000000000..33e1e2948 --- /dev/null +++ b/framework/swell/api/operations/login.ts @@ -0,0 +1,46 @@ +import type { ServerResponse } from 'http' +import type { + OperationContext, + OperationOptions, +} from '@commerce/api/operations' +import type { LoginOperation } from '../../types/login' +import { Provider, SwellConfig } from '..' + +export default function loginOperation({ + commerce, +}: OperationContext) { + async function login(opts: { + variables: T['variables'] + config?: Partial + res: ServerResponse + }): Promise + + async function login( + opts: { + variables: T['variables'] + config?: Partial + res: ServerResponse + } & OperationOptions + ): Promise + + async function login({ + variables, + res: response, + config: cfg, + }: { + query?: string + variables: T['variables'] + res: ServerResponse + config?: Partial + }): Promise { + const config = commerce.getConfig(cfg) + + const { data } = await config.fetch('account', 'login', [variables]) + + return { + result: data, + } + } + + return login +} diff --git a/framework/swell/api/utils/create-api-handler.ts b/framework/swell/api/utils/create-api-handler.ts deleted file mode 100644 index bd40a7ee4..000000000 --- a/framework/swell/api/utils/create-api-handler.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next' -import { SwellConfig, getConfig } from '..' - -export type SwellApiHandler< - T = any, - H extends SwellHandlers = {}, - Options extends {} = {} -> = ( - req: NextApiRequest, - res: NextApiResponse>, - config: SwellConfig, - handlers: H, - // Custom configs that may be used by a particular handler - options: Options -) => void | Promise - -export type SwellHandler = (options: { - req: NextApiRequest - res: NextApiResponse> - config: SwellConfig - body: Body -}) => void | Promise - -export type SwellHandlers = { - [k: string]: SwellHandler -} - -export type SwellApiResponse = { - data: T | null - errors?: { message: string; code?: string }[] -} - -export default function createApiHandler< - T = any, - H extends SwellHandlers = {}, - Options extends {} = {} ->( - handler: SwellApiHandler, - handlers: H, - defaultOptions: Options -) { - return function getApiHandler({ - config, - operations, - options, - }: { - config?: SwellConfig - operations?: Partial - options?: Options extends {} ? Partial : never - } = {}): NextApiHandler { - const ops = { ...operations, ...handlers } - const opts = { ...defaultOptions, ...options } - - return function apiHandler(req, res) { - return handler(req, res, getConfig(config), ops, opts) - } - } -} diff --git a/framework/swell/auth/use-login.tsx b/framework/swell/auth/use-login.tsx index 57c3ce921..587163d97 100644 --- a/framework/swell/auth/use-login.tsx +++ b/framework/swell/auth/use-login.tsx @@ -3,12 +3,12 @@ import type { MutationHook } from '@commerce/utils/types' import { CommerceError, ValidationError } from '@commerce/utils/errors' import useCustomer from '../customer/use-customer' import { - CustomerAccessTokenCreateInput, CustomerUserError, Mutation, MutationCheckoutCreateArgs, } from '../schema' import useLogin, { UseLogin } from '@commerce/auth/use-login' +import { LoginHook } from '../types/login' import { setCustomerToken } from '../utils' export default useLogin as UseLogin @@ -22,7 +22,7 @@ const getErrorMessage = ({ code, message }: CustomerUserError) => { return message } -export const handler: MutationHook = { +export const handler: MutationHook = { fetchOptions: { query: 'account', method: 'login', diff --git a/framework/swell/auth/use-logout.tsx b/framework/swell/auth/use-logout.tsx index ae17ba74e..7dc7411ec 100644 --- a/framework/swell/auth/use-logout.tsx +++ b/framework/swell/auth/use-logout.tsx @@ -3,10 +3,11 @@ import type { MutationHook } from '@commerce/utils/types' import useLogout, { UseLogout } from '@commerce/auth/use-logout' import useCustomer from '../customer/use-customer' import { getCustomerToken, setCustomerToken } from '../utils/customer-token' +import { LogoutHook } from '../types/logout' export default useLogout as UseLogout -export const handler: MutationHook = { +export const handler: MutationHook = { fetchOptions: { query: 'account', method: 'logout', diff --git a/framework/swell/auth/use-signup.tsx b/framework/swell/auth/use-signup.tsx index d417122fc..674b9861f 100644 --- a/framework/swell/auth/use-signup.tsx +++ b/framework/swell/auth/use-signup.tsx @@ -3,18 +3,12 @@ import type { MutationHook } from '@commerce/utils/types' import { CommerceError } from '@commerce/utils/errors' import useSignup, { UseSignup } from '@commerce/auth/use-signup' import useCustomer from '../customer/use-customer' -import { CustomerCreateInput } from '../schema' - +import { SignupHook } from '../types/signup' import handleLogin from '../utils/handle-login' export default useSignup as UseSignup -export const handler: MutationHook< - null, - {}, - CustomerCreateInput, - CustomerCreateInput -> = { +export const handler: MutationHook = { fetchOptions: { query: 'account', method: 'create', diff --git a/framework/swell/cart/use-add-item.tsx b/framework/swell/cart/use-add-item.tsx index 990514d42..e324a44d9 100644 --- a/framework/swell/cart/use-add-item.tsx +++ b/framework/swell/cart/use-add-item.tsx @@ -2,14 +2,14 @@ import type { MutationHook } from '@commerce/utils/types' import { CommerceError } from '@commerce/utils/errors' import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' import useCart from './use-cart' -import { Cart, CartItemBody } from '../types' import { checkoutToCart } from './utils' import { getCheckoutId } from '../utils' import { useCallback } from 'react' +import { AddItemHook } from '../types/cart' export default useAddItem as UseAddItem -export const handler: MutationHook = { +export const handler: MutationHook = { fetchOptions: { query: 'cart', method: 'addItem', @@ -24,7 +24,7 @@ export const handler: MutationHook = { }) } const variables: { - product_id: string + product_id: string | undefined variant_id?: string checkoutId?: string quantity?: number diff --git a/framework/swell/cart/use-cart.tsx b/framework/swell/cart/use-cart.tsx index 531286ee6..885f889f5 100644 --- a/framework/swell/cart/use-cart.tsx +++ b/framework/swell/cart/use-cart.tsx @@ -1,13 +1,13 @@ import useCart, { UseCart } from '@commerce/cart/use-cart' -import { Cart } from '@commerce/types' import { SWRHook } from '@commerce/utils/types' import { useMemo } from 'react' import { normalizeCart } from '../utils/normalize' import { checkoutCreate, checkoutToCart } from './utils' +import type { GetCartHook } from '@commerce/types/cart' export default useCart as UseCart -export const handler: SWRHook = { +export const handler: SWRHook = { fetchOptions: { query: 'cart', method: 'get', diff --git a/framework/swell/cart/use-remove-item.tsx b/framework/swell/cart/use-remove-item.tsx index 8dc1ea713..7ef3af7cd 100644 --- a/framework/swell/cart/use-remove-item.tsx +++ b/framework/swell/cart/use-remove-item.tsx @@ -1,29 +1,21 @@ import { useCallback } from 'react' - import type { MutationHookContext, HookFetcherContext, } from '@commerce/utils/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 '@commerce/types/cart' import useCart from './use-cart' import { checkoutToCart } from './utils' -import { Cart, LineItem } from '../types' -import { RemoveCartItemBody } from '@commerce/types' export type RemoveItemFn = T extends LineItem - ? (input?: RemoveItemInput) => Promise - : (input: RemoveItemInput) => Promise + ? (input?: RemoveItemActionInput) => Promise + : (input: RemoveItemActionInput) => Promise -export type RemoveItemInput = T extends LineItem - ? Partial - : RemoveItemInputBase +export type RemoveItemActionInput = T extends LineItem + ? Partial + : RemoveItemHook['actionInput'] export default useRemoveItem as UseRemoveItem @@ -36,36 +28,22 @@ export const handler = { input: { itemId }, options, fetch, - }: HookFetcherContext) { - const response = await fetch({ - ...options, - variables: [itemId], - }) + }: HookFetcherContext) { + const response = await fetch({ ...options, variables: [itemId] }) + return checkoutToCart(response) }, - useHook: ({ - fetch, - }: MutationHookContext) => < - T extends LineItem | undefined = undefined - >( - ctx: { item?: T } = {} - ) => { - const { item } = ctx + useHook: ({ fetch }: MutationHookContext) => () => { const { mutate } = useCart() - const removeItem: RemoveItemFn = async (input) => { - const itemId = input?.id ?? item?.id - if (!itemId) { - throw new ValidationError({ - message: 'Invalid input used for this operation', - }) - } + return useCallback( + async function removeItem(input) { + const data = await fetch({ input: { itemId: input.id } }) + await mutate(data, false) - const data = await fetch({ input: { itemId } }) - await mutate(data, false) - return data - } - - return useCallback(removeItem as RemoveItemFn, [fetch, mutate]) + return data + }, + [fetch, mutate] + ) }, } diff --git a/framework/swell/cart/use-update-item.tsx b/framework/swell/cart/use-update-item.tsx index b1031b2e7..631a394f6 100644 --- a/framework/swell/cart/use-update-item.tsx +++ b/framework/swell/cart/use-update-item.tsx @@ -2,25 +2,30 @@ import { useCallback } from 'react' import debounce from 'lodash.debounce' import type { HookFetcherContext, + MutationHook, 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, { +// 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 { CartItemBody, LineItem } from '@commerce/types/cart' import { checkoutToCart } from './utils' - -export type UpdateItemInput = T extends LineItem - ? Partial> - : UpdateItemInputBase +import { UpdateItemHook } from '../types/cart' +// export type UpdateItemInput = T extends LineItem +// ? Partial> +// : UpdateItemInputBase export default useUpdateItem as UseUpdateItem +export type UpdateItemActionInput = T extends LineItem + ? Partial + : UpdateItemHook['actionInput'] + export const handler = { fetchOptions: { query: 'cart', @@ -30,7 +35,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) { @@ -52,9 +57,7 @@ export const handler = { return checkoutToCart(response) }, - useHook: ({ - fetch, - }: MutationHookContext) => < + useHook: ({ fetch }: MutationHookContext) => < T extends LineItem | undefined = undefined >( ctx: { @@ -66,7 +69,7 @@ export const handler = { const { mutate, data: cartData } = useCart() as any return useCallback( - debounce(async (input: UpdateItemInput) => { + debounce(async (input: UpdateItemActionInput) => { const firstLineItem = cartData.lineItems[0] const itemId = item?.id || firstLineItem.id const productId = item?.productId || firstLineItem.productId diff --git a/framework/swell/cart/utils/checkout-create.ts b/framework/swell/cart/utils/checkout-create.ts index 5ee3833c5..a4b82d849 100644 --- a/framework/swell/cart/utils/checkout-create.ts +++ b/framework/swell/cart/utils/checkout-create.ts @@ -9,7 +9,7 @@ export const checkoutCreate = async (fetch: any) => { }) if (!cart) { - const cart = await fetch({ + await fetch({ query: 'cart', method: 'setItems', variables: [[]], diff --git a/framework/swell/cart/utils/fetcher.ts b/framework/swell/cart/utils/fetcher.ts deleted file mode 100644 index 2e7ae15d3..000000000 --- a/framework/swell/cart/utils/fetcher.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { HookFetcherFn } from '@commerce/utils/types' -import { Cart } from '@commerce/types' -// import { checkoutCreate, checkoutToCart } from '.' -import { FetchCartInput } from '@commerce/cart/use-cart' -import { data } from 'autoprefixer' -import { normalizeCart } from '../../utils' - -const fetcher: HookFetcherFn = async ({ - options, - // input: { cartId: checkoutId }, - fetch, -}) => { - let checkout - - // if (checkoutId) { - const data = await fetch({ - query: 'cart', - method: 'get', - // variables: { category: categoryId }, - }) - // checkout = data.node - // } - - // if (checkout?.completedAt || !checkoutId) { - // checkout = await checkoutCreate(fetch) - // } - - // TODO: Fix this type - // return checkoutToCart({ checkout } as any) - return normalizeCart(data) -} - -export default fetcher diff --git a/framework/swell/common/get-all-pages.ts b/framework/swell/common/get-all-pages.ts deleted file mode 100644 index 8d0b9cf36..000000000 --- a/framework/swell/common/get-all-pages.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { getConfig, SwellConfig } from '../api' - -type Variables = { - first?: number -} - -type ReturnType = { - pages: Page[] -} - -export type Page = { - id: string - name: string - url: string - sort_order?: number - body: string -} - -const getAllPages = async (options?: { - variables?: Variables - config: SwellConfig - preview?: boolean -}): Promise => { - let { config, variables = { first: 250 } } = options ?? {} - config = getConfig(config) - const { locale, fetch } = config - const data = await fetch('content', 'list', ['pages']) - const pages = - data?.results?.map(({ slug, ...rest }: { slug: string }) => ({ - url: `/${locale}/${slug}`, - ...rest, - })) ?? [] - - return { pages } -} - -export default getAllPages diff --git a/framework/swell/common/get-page.ts b/framework/swell/common/get-page.ts deleted file mode 100644 index dca317a19..000000000 --- a/framework/swell/common/get-page.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { getConfig, SwellConfig } from '../api' -import { Page } from './get-all-pages' - -type Variables = { - id: string -} - -export type GetPageResult = T - -const getPage = async (options: { - variables: Variables - config: SwellConfig - preview?: boolean -}): Promise => { - let { config, variables } = options ?? {} - - config = getConfig(config) - const { locale } = config - const { id } = variables - const result = await config.fetch('content', 'get', ['pages', id]) - const page = result - - return { - page: page - ? { - ...page, - url: `/${locale}/${page.slug}`, - } - : null, - } -} - -export default getPage diff --git a/framework/swell/common/get-site-info.ts b/framework/swell/common/get-site-info.ts deleted file mode 100644 index c7a06c52e..000000000 --- a/framework/swell/common/get-site-info.ts +++ /dev/null @@ -1,31 +0,0 @@ -import getCategories from '../utils/get-categories' -import getVendors, { Brands } from '../utils/get-vendors' -import { Category } from '@commerce/types' -import { getConfig, SwellConfig } from '../api' - -export type GetSiteInfoResult< - T extends { categories: any[]; brands: any[] } = { - categories: Category[] - brands: Brands - } -> = T - -const getSiteInfo = async (options?: { - variables?: any - config: SwellConfig - preview?: boolean -}): Promise => { - let { config } = options ?? {} - - config = getConfig(config) - - const categories = await getCategories(config) - const brands = await getVendors(config) - - return { - categories, - brands, - } -} - -export default getSiteInfo diff --git a/framework/swell/customer/use-customer.tsx b/framework/swell/customer/use-customer.tsx index 632065d5a..50e85d3f6 100644 --- a/framework/swell/customer/use-customer.tsx +++ b/framework/swell/customer/use-customer.tsx @@ -1,11 +1,11 @@ import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' -import { Customer } from '@commerce/types' import { SWRHook } from '@commerce/utils/types' import { normalizeCustomer } from '../utils/normalize' +import type { CustomerHook } from '../types/customer' export default useCustomer as UseCustomer -export const handler: SWRHook = { +export const handler: SWRHook = { fetchOptions: { query: 'account', method: 'get', @@ -25,26 +25,3 @@ export const handler: SWRHook = { }) }, } - -// const handler = (): { data: Customer } => { -// const swell = getContext(); -// const response = swell.account.get(); -// const { firstName, lastName, email, company, customerGroupId, notes, phone, -// entityId, addressCount, attributeCount, storeCredit } = response; -// return { -// data: { -// firstName, -// lastName, -// email, -// company, -// customerGroupId, -// notes, -// phone, -// entityId, -// addressCount, -// attributeCount, -// storeCredit -// } -// } -// } -// export default handler; diff --git a/framework/swell/product/get-all-collections.ts b/framework/swell/product/get-all-collections.ts deleted file mode 100644 index 6b82ce449..000000000 --- a/framework/swell/product/get-all-collections.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { CollectionEdge } from '../schema' -import { getConfig, SwellConfig } from '../api' - -const getAllCollections = async (options?: { - variables?: any - config: SwellConfig - preview?: boolean -}) => { - let { config, variables = { limit: 25 } } = options ?? {} - config = getConfig(config) - - const response = await config.fetch('categories', 'list', { variables }) - const edges = response.results ?? [] - - const categories = edges.map( - ({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({ - entityId, - name, - path: `/${handle}`, - }) - ) - - return { - categories, - } -} - -export default getAllCollections diff --git a/framework/swell/product/get-all-product-paths.ts b/framework/swell/product/get-all-product-paths.ts deleted file mode 100644 index 933eb73bc..000000000 --- a/framework/swell/product/get-all-product-paths.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { SwellProduct } from '../types' -import { getConfig, SwellConfig } from '../api' - -type ProductPath = { - path: string -} - -export type ProductPathNode = { - node: ProductPath -} - -type ReturnType = { - products: ProductPathNode[] -} - -const getAllProductPaths = async (options?: { - variables?: any - config?: SwellConfig - preview?: boolean -}): Promise => { - let { config, variables = [{ limit: 100 }] } = options ?? {} - config = getConfig(config) - - const { results } = await config.fetch('products', 'list', [ - { - limit: variables.first, - }, - ]) - - return { - products: results?.map(({ slug: handle }: SwellProduct) => ({ - node: { - path: `/${handle}`, - }, - })), - } -} - -export default getAllProductPaths diff --git a/framework/swell/product/get-all-products.ts b/framework/swell/product/get-all-products.ts deleted file mode 100644 index c0746efca..000000000 --- a/framework/swell/product/get-all-products.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { getConfig, SwellConfig } from '../api' -import { normalizeProduct } from '../utils/normalize' -import { Product } from '@commerce/types' -import { SwellProduct } from '../types' - -type Variables = { - first?: number - field?: string -} - -type ReturnType = { - products: Product[] -} - -const getAllProducts = async (options: { - variables?: Variables - config?: SwellConfig - preview?: boolean -}): Promise => { - let { config, variables = { first: 250 } } = options ?? {} - config = getConfig(config) - const { results } = await config.fetch('products', 'list', [ - { - limit: variables.first, - }, - ]) - const products = results.map((product: SwellProduct) => - normalizeProduct(product) - ) - - return { - products, - } -} - -export default getAllProducts diff --git a/framework/swell/product/get-product.ts b/framework/swell/product/get-product.ts deleted file mode 100644 index 0d75a57cd..000000000 --- a/framework/swell/product/get-product.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { GraphQLFetcherResult } from '@commerce/api' -import { getConfig, SwellConfig } from '../api' -import { normalizeProduct } from '../utils' - -type Variables = { - slug: string -} - -type ReturnType = { - product: any -} - -const getProduct = async (options: { - variables: Variables - config: SwellConfig - preview?: boolean -}): Promise => { - let { config, variables } = options ?? {} - config = getConfig(config) - - const product = await config.fetch('products', 'get', [variables.slug]) - - if (product && product.variants) { - product.variants = product.variants?.results - } - - return { - product: product ? normalizeProduct(product) : null, - } -} - -export default getProduct diff --git a/framework/swell/product/index.ts b/framework/swell/product/index.ts new file mode 100644 index 000000000..426a3edcd --- /dev/null +++ b/framework/swell/product/index.ts @@ -0,0 +1,2 @@ +export { default as usePrice } from './use-price' +export { default as useSearch } from './use-search' diff --git a/framework/swell/product/use-search.tsx b/framework/swell/product/use-search.tsx index ce116caa3..bdcca3ff2 100644 --- a/framework/swell/product/use-search.tsx +++ b/framework/swell/product/use-search.tsx @@ -1,11 +1,8 @@ import { SWRHook } from '@commerce/utils/types' import useSearch, { UseSearch } from '@commerce/product/use-search' - import { normalizeProduct } from '../utils' - -import { Product } from '@commerce/types' - import { SwellProduct } from '../types' +import type { SearchProductsHook } from '../types/product' export default useSearch as UseSearch @@ -16,18 +13,9 @@ export type SearchProductsInput = { sort?: string } -export type SearchProductsData = { - products: Product[] - found: boolean -} - -export const handler: SWRHook< - SearchProductsData, - SearchProductsInput, - SearchProductsInput -> = { +export const handler: SWRHook = { fetchOptions: { - query: 'products', // String(Math.random()), + query: 'products', method: 'list', }, async fetcher({ input, options, fetch }) { diff --git a/framework/swell/provider.ts b/framework/swell/provider.ts index 0bcbd7888..aa7be31d4 100644 --- a/framework/swell/provider.ts +++ b/framework/swell/provider.ts @@ -1,3 +1,5 @@ +import { Provider } from '@commerce' + import { SWELL_CHECKOUT_URL_COOKIE, STORE_DOMAIN } from './const' import { handler as useCart } from './cart/use-cart' @@ -14,18 +16,15 @@ import { handler as useSignup } from './auth/use-signup' import fetcher from './fetcher' -export const swellProvider = { +export const swellProvider: Provider = { locale: 'en-us', cartCookie: SWELL_CHECKOUT_URL_COOKIE, - storeDomain: STORE_DOMAIN, + // storeDomain: STORE_DOMAIN, fetcher, cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, customer: { useCustomer }, products: { useSearch }, auth: { useLogin, useLogout, useSignup }, - features: { - wishlist: false, - }, } export type SwellProvider = typeof swellProvider diff --git a/framework/swell/types.ts b/framework/swell/types.ts index 71848d4a4..ad8ee3b68 100644 --- a/framework/swell/types.ts +++ b/framework/swell/types.ts @@ -1,4 +1,5 @@ -import * as Core from '@commerce/types' +import * as Core from '@commerce/types/cart' +import { Customer } from '@commerce/types' import { CheckoutLineItem } from './schema' export type SwellImage = { @@ -43,12 +44,18 @@ export type SwellVariant = { name: string price?: number stock_status?: string + __type?: 'MultipleChoiceOption' | undefined +} + +export interface SwellProductOptionValue { + id: string + label: string + hexColors?: string[] } export interface ProductOptionValue { label: string hexColors?: string[] - id: string } export type ProductOptions = { @@ -73,10 +80,7 @@ export interface SwellProduct { variants: any[] } -export interface SwellCustomer extends Core.Customer { - first_name: string - last_name: string -} +export type SwellCustomer = any export type SwellCheckout = { id: string @@ -106,17 +110,3 @@ export type CartItemBody = Core.CartItemBody & { productId: string // The product id is always required for BC optionSelections?: OptionSelections } - -export type GetCartHandlerBody = Core.GetCartHandlerBody - -export type AddCartItemBody = Core.AddCartItemBody - -export type AddCartItemHandlerBody = Core.AddCartItemHandlerBody - -export type UpdateCartItemBody = Core.UpdateCartItemBody - -export type UpdateCartItemHandlerBody = Core.UpdateCartItemHandlerBody - -export type RemoveCartItemBody = Core.RemoveCartItemBody - -export type RemoveCartItemHandlerBody = Core.RemoveCartItemHandlerBody diff --git a/framework/swell/types/cart.ts b/framework/swell/types/cart.ts new file mode 100644 index 000000000..6ed5c6c64 --- /dev/null +++ b/framework/swell/types/cart.ts @@ -0,0 +1 @@ +export * from '@commerce/types/cart' diff --git a/framework/swell/types/checkout.ts b/framework/swell/types/checkout.ts new file mode 100644 index 000000000..4e2412ef6 --- /dev/null +++ b/framework/swell/types/checkout.ts @@ -0,0 +1 @@ +export * from '@commerce/types/checkout' diff --git a/framework/swell/types/common.ts b/framework/swell/types/common.ts new file mode 100644 index 000000000..b52c33a4d --- /dev/null +++ b/framework/swell/types/common.ts @@ -0,0 +1 @@ +export * from '@commerce/types/common' diff --git a/framework/swell/types/customer.ts b/framework/swell/types/customer.ts new file mode 100644 index 000000000..87c9afcc4 --- /dev/null +++ b/framework/swell/types/customer.ts @@ -0,0 +1 @@ +export * from '@commerce/types/customer' diff --git a/framework/swell/types/index.ts b/framework/swell/types/index.ts new file mode 100644 index 000000000..7ab0b7f64 --- /dev/null +++ b/framework/swell/types/index.ts @@ -0,0 +1,25 @@ +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/swell/types/login.ts b/framework/swell/types/login.ts new file mode 100644 index 000000000..ab11a420a --- /dev/null +++ b/framework/swell/types/login.ts @@ -0,0 +1,11 @@ +import * as Core from '@commerce/types/login' +import { LoginBody, LoginTypes } from '@commerce/types/login' + +export * from '@commerce/types/login' + +export type LoginHook = { + data: null + actionInput: LoginBody + fetcherInput: LoginBody + body: T['body'] +} diff --git a/framework/swell/types/logout.ts b/framework/swell/types/logout.ts new file mode 100644 index 000000000..9f0a466af --- /dev/null +++ b/framework/swell/types/logout.ts @@ -0,0 +1 @@ +export * from '@commerce/types/logout' diff --git a/framework/swell/types/page.ts b/framework/swell/types/page.ts new file mode 100644 index 000000000..20ec8ea38 --- /dev/null +++ b/framework/swell/types/page.ts @@ -0,0 +1 @@ +export * from '@commerce/types/page' diff --git a/framework/swell/types/product.ts b/framework/swell/types/product.ts new file mode 100644 index 000000000..c776d58fa --- /dev/null +++ b/framework/swell/types/product.ts @@ -0,0 +1 @@ +export * from '@commerce/types/product' diff --git a/framework/swell/types/signup.ts b/framework/swell/types/signup.ts new file mode 100644 index 000000000..58543c6f6 --- /dev/null +++ b/framework/swell/types/signup.ts @@ -0,0 +1 @@ +export * from '@commerce/types/signup' diff --git a/framework/swell/types/site.ts b/framework/swell/types/site.ts new file mode 100644 index 000000000..bfef69cf9 --- /dev/null +++ b/framework/swell/types/site.ts @@ -0,0 +1 @@ +export * from '@commerce/types/site' diff --git a/framework/swell/types/wishlist.ts b/framework/swell/types/wishlist.ts new file mode 100644 index 000000000..8907fbf82 --- /dev/null +++ b/framework/swell/types/wishlist.ts @@ -0,0 +1 @@ +export * from '@commerce/types/wishlist' diff --git a/framework/swell/utils/get-categories.ts b/framework/swell/utils/get-categories.ts index acf33a5b9..ab38bae96 100644 --- a/framework/swell/utils/get-categories.ts +++ b/framework/swell/utils/get-categories.ts @@ -1,5 +1,5 @@ import { SwellConfig } from '../api' -import { Category } from '@commerce/types' +import { Category } from '../types/site' const getCategories = async (config: SwellConfig): Promise => { const data = await config.fetch('categories', 'get') diff --git a/framework/swell/utils/normalize.ts b/framework/swell/utils/normalize.ts index b0cfb6193..2306f0662 100644 --- a/framework/swell/utils/normalize.ts +++ b/framework/swell/utils/normalize.ts @@ -1,6 +1,6 @@ -import { Product, Customer } from '@commerce/types' - -import { MoneyV2, ProductOption } from '../schema' +import { Customer } from '../types/customer' +import { Product, ProductOption } from '../types/product' +import { MoneyV2 } from '../schema' import type { Cart, @@ -10,6 +10,7 @@ import type { SwellImage, SwellVariant, ProductOptionValue, + SwellProductOptionValue, SwellCart, LineItem, } from '../types' @@ -21,8 +22,13 @@ const money = ({ amount, currencyCode }: MoneyV2) => { } } +type swellProductOption = { + id: string + name: string + values: any[] +} + type normalizedProductOption = { - __typename?: string id: string displayName: string values: ProductOptionValue[] @@ -32,11 +38,11 @@ const normalizeProductOption = ({ id, name: displayName = '', values = [], -}: ProductOption) => { +}: swellProductOption): ProductOption => { let returnValues = values.map((value) => { let output: any = { label: value.name, - id: value?.id || id, + // id: value?.id || id, } if (displayName.match(/colou?r/gi)) { output = { @@ -68,7 +74,7 @@ const normalizeProductImages = (images: SwellImage[]) => { const normalizeProductVariants = ( variants: SwellVariant[], - productOptions: normalizedProductOption[] + productOptions: swellProductOption[] ) => { return variants?.map( ({ id, name, price, option_value_ids: optionValueIds = [] }) => { @@ -79,22 +85,22 @@ const normalizeProductVariants = ( const options = optionValueIds.map((id) => { const matchingOption = productOptions.find((option) => { return option.values.find( - (value: ProductOptionValue) => value.id == id + (value: SwellProductOptionValue) => value.id == id ) }) return normalizeProductOption({ id, - name: matchingOption?.displayName ?? '', + name: matchingOption?.name ?? '', values, }) }) return { id, - name, + // name, // sku: sku ?? id, - price: price ?? null, - listPrice: price ?? null, + // price: price ?? null, + // listPrice: price ?? null, // requiresShipping: true, options, } @@ -116,11 +122,12 @@ export function normalizeProduct(swellProduct: SwellProduct): Product { } = swellProduct // ProductView accesses variants for each product const emptyVariants = [{ options: [], id, name }] + const productOptions = options ? options.map((o) => normalizeProductOption(o)) : [] const productVariants = variants - ? normalizeProductVariants(variants, productOptions) + ? normalizeProductVariants(variants, options) : [] const productImages = normalizeProductImages(images) diff --git a/framework/swell/swell-js.d.ts b/swell-js.d.ts similarity index 100% rename from framework/swell/swell-js.d.ts rename to swell-js.d.ts From b9cb71be6a1c4ddfad0548d68c00b0696153fdd5 Mon Sep 17 00:00:00 2001 From: Mirek Mencel Date: Tue, 15 Jun 2021 00:09:33 +0200 Subject: [PATCH 02/11] Fix Saleor's Demo link (#362) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 225c4d535..84807bcf6 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Demo live at: [demo.vercel.store](https://demo.vercel.store/) - Swell Demo: https://swell.vercel.store/ - BigCommerce Demo: https://bigcommerce.vercel.store/ - Vendure Demo: https://vendure.vercel.store -- Saleor Demo: https://saleor.vercel.store/ +- Saleor Demo: https://saleorcommerce.vercel.store/ ## Features From 3c9b90f453d77efe369c62220eb1a4480a45aec3 Mon Sep 17 00:00:00 2001 From: Mirek Mencel Date: Tue, 15 Jun 2021 00:19:38 +0200 Subject: [PATCH 03/11] Fix Saleor's Demo link #2 (#363) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 84807bcf6..189192216 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Demo live at: [demo.vercel.store](https://demo.vercel.store/) - Swell Demo: https://swell.vercel.store/ - BigCommerce Demo: https://bigcommerce.vercel.store/ - Vendure Demo: https://vendure.vercel.store -- Saleor Demo: https://saleorcommerce.vercel.store/ +- Saleor Demo: https://saleor-commerce.vercel.app/ ## Features From 78cc378a72c5b27db34b3903281b045520513c19 Mon Sep 17 00:00:00 2001 From: B Date: Tue, 15 Jun 2021 20:23:17 -0300 Subject: [PATCH 04/11] New Release (#371) * Custom Checkout Progress * Updates to Checkout * Custom Checkout Progress * Adding tabs * Adding Collapse * Adding Collapse * Improving Sidebar Scroll * Modif footer * Changes * More design updates * sidebar cart * More design updates * More design updates * More design updates * More design updates * Types * Types * Design Updates * More changes * More changes * More changes * Changes * Changes * Changes * New tailwind required changes * Sidebar Styling issues with Mobile * Latest changes - Normalizing cart * Styling Fixes * New changes * Changes * latest * Refactor and Renaming some UI Props * Adding Quantity Component * Adding Rating Component * Rating Component * More updates * User Select disabled, plus hidding horizontal scroll bars * Changes * Adding ProductOptions Component and more helpers * Styling updates * Styling updates * Fix for slim tags * Missmatch with RightArrow * Footer updates and some styles * Latest Updates * Latest Updates * Latest Updates * Removing Portal, since it's not needed. We might add it later I'd rather not to. * Removing Portal, since it's not needed. We might add it later I'd rather not to. * Sam backdrop filter * General UI Improvements * General UI Improvements * Search now with Geist Colors * Now with Geist Colors * Changes * Scroll for Mobile on IOs devises * LoadingDots Working (: * Changes * More Changes * Perf changes * More perf changes * Fade to the Nametags in the ProductCard * changes * Search issue ui * Search issue ui * Make sure to only refresh navbar and modals when required * Index revalidate * Fixed image issue * hide album scroll on windows * Fix scrollbar * Changing * Adding 404 with Layout * Removing Toast * Adding Assets * Adding Assets * Progress with LocalProvider * New productTag * Only images for the drop * changes * Empty SWRhooks * Adding Local Provider * Working local * Working view of a LocalProvider * More updates * Changes * Removed react-ticker * default to local if no env available * default to local if no env available * add missing `@` to css import * rewrite search rewrites to multiple pages * allow requests in getStaticProps to execute in parallel * make type import explicit * add a tsconfig.js file * use local provider in tsconfig.js * avoid a circular dependency * Saleor was not in the providers list * avoid circular dependency in bigcommerce * Adding more to the Local Provider (#366) * Adding more data * Adding more data * optimize assets (#370) * Optimize assets (#372) * optimize assets * remove assets * remove assets * cart enabled * Adding saleor * Changes with Webpack * Changes Co-authored-by: Luis Alvarez Co-authored-by: Tobias Koppers Co-authored-by: Shu Ding --- README.md | 8 +- assets/base.css | 54 +- components/auth/ForgotPassword.tsx | 2 +- components/auth/LoginView.tsx | 2 +- components/auth/SignUpView.tsx | 4 +- components/cart/CartItem/CartItem.module.css | 16 +- components/cart/CartItem/CartItem.tsx | 178 +- .../CartSidebarView.module.css | 10 +- .../cart/CartSidebarView/CartSidebarView.tsx | 98 +- .../CheckoutSidebarView.module.css | 7 + .../CheckoutSidebarView.tsx | 89 + .../checkout/CheckoutSidebarView/index.ts | 1 + .../PaymentMethodView.module.css | 17 + .../PaymentMethodView/PaymentMethodView.tsx | 84 + .../checkout/PaymentMethodView/index.ts | 1 + .../PaymentWidget/PaymentWidget.module.css | 4 + .../checkout/PaymentWidget/PaymentWidget.tsx | 29 + components/checkout/PaymentWidget/index.ts | 1 + .../ShippingView/ShippingView.module.css | 21 + .../checkout/ShippingView/ShippingView.tsx | 78 + components/checkout/ShippingView/index.ts | 1 + .../ShippingWidget/ShippingWidget.module.css | 4 + .../ShippingWidget/ShippingWidget.tsx | 33 + components/checkout/ShippingWidget/index.ts | 1 + components/common/Avatar/Avatar.tsx | 2 +- .../common/FeatureBar/FeatureBar.module.css | 4 +- components/common/Footer/Footer.module.css | 4 + components/common/Footer/Footer.tsx | 76 +- .../HomeAllProductsGrid.tsx | 4 +- .../common/I18nWidget/I18nWidget.module.css | 20 +- components/common/I18nWidget/I18nWidget.tsx | 2 +- components/common/Layout/Layout.tsx | 75 +- components/common/Navbar/Navbar.module.css | 16 +- components/common/Navbar/Navbar.tsx | 13 +- .../common/Searchbar/Searchbar.module.css | 16 +- components/common/Searchbar/Searchbar.tsx | 43 +- .../SidebarLayout/SidebarLayout.module.css | 20 + .../common/SidebarLayout/SidebarLayout.tsx | 50 + components/common/SidebarLayout/index.ts | 1 + .../common/UserNav/DropdownMenu.module.css | 10 +- components/common/UserNav/DropdownMenu.tsx | 2 +- components/common/UserNav/UserNav.module.css | 4 +- components/common/UserNav/UserNav.tsx | 32 +- .../icons/{RightArrow.tsx => ArrowRight.tsx} | 7 +- components/icons/ChevronDown.tsx | 20 + components/icons/ChevronLeft.tsx | 20 + components/icons/ChevronRight.tsx | 20 + components/icons/CreditCard.tsx | 1 + components/icons/Star.tsx | 16 + components/icons/index.ts | 12 +- .../ProductCard/ProductCard.module.css | 190 +- .../product/ProductCard/ProductCard.tsx | 164 +- .../product/ProductOptions/ProductOptions.tsx | 50 + components/product/ProductOptions/index.ts | 1 + .../ProductSidebar/ProductSidebar.module.css | 84 + .../product/ProductSidebar/ProductSidebar.tsx | 87 + components/product/ProductSidebar/index.ts | 1 + .../ProductSlider/ProductSlider.module.css | 126 +- .../product/ProductSlider/ProductSlider.tsx | 87 +- .../ProductSliderControl.module.css | 29 + .../ProductSliderControl.tsx | 31 + .../product/ProductSliderControl/index.ts | 1 + .../product/ProductTag/ProductTag.module.css | 30 + components/product/ProductTag/ProductTag.tsx | 36 + components/product/ProductTag/index.ts | 1 + .../ProductView/ProductView.module.css | 106 +- .../product/ProductView/ProductView.tsx | 208 +- components/product/Swatch/Swatch.module.css | 12 +- components/product/Swatch/Swatch.tsx | 86 +- components/product/helpers.ts | 16 +- components/product/index.ts | 1 + components/search.tsx | 439 + components/ui/Button/Button.module.css | 26 +- components/ui/Button/Button.tsx | 3 +- components/ui/Collapse/Collapse.module.css | 25 + components/ui/Collapse/Collapse.tsx | 46 + components/ui/Collapse/index.ts | 2 + components/ui/Container/Container.tsx | 9 +- components/ui/Grid/Grid.module.css | 44 +- components/ui/Grid/Grid.tsx | 4 +- components/ui/Hero/Hero.module.css | 27 +- components/ui/Hero/Hero.tsx | 22 +- components/ui/Input/Input.module.css | 2 +- components/ui/Input/Input.tsx | 4 +- .../ui/LoadingDots/LoadingDots.module.css | 29 +- components/ui/LoadingDots/LoadingDots.tsx | 6 +- components/ui/Marquee/Marquee.module.css | 20 +- components/ui/Marquee/Marquee.tsx | 22 +- components/ui/Modal/Modal.module.css | 11 +- components/ui/Modal/Modal.tsx | 53 +- components/ui/Quantity/Quantity.module.css | 27 + components/ui/Quantity/Quantity.tsx | 62 + components/ui/Quantity/index.ts | 2 + components/ui/Rating/Rating.module.css | 0 components/ui/Rating/Rating.tsx | 27 + components/ui/Rating/index.ts | 2 + components/ui/Sidebar/Sidebar.module.css | 13 +- components/ui/Sidebar/Sidebar.tsx | 49 +- components/ui/Skeleton/Skeleton.module.css | 16 +- components/ui/Skeleton/Skeleton.tsx | 12 +- components/ui/Text/Text.module.css | 6 +- components/ui/Text/Text.tsx | 7 +- components/ui/context.tsx | 109 +- components/ui/index.ts | 3 + .../WishlistButton/WishlistButton.module.css | 33 + .../WishlistButton/WishlistButton.tsx | 10 +- .../WishlistCard/WishlistCard.module.css | 2 +- framework/bigcommerce/api/index.ts | 8 +- .../api/utils/fetch-graphql-api.ts | 58 +- .../bigcommerce/api/utils/fetch-store-api.ts | 94 +- framework/bigcommerce/index.tsx | 3 +- framework/commerce/api/index.ts | 25 +- framework/commerce/config.js | 35 +- framework/commerce/new-provider.md | 3 +- framework/commerce/types/cart.ts | 20 +- framework/commerce/types/product.ts | 2 +- framework/local/.env.template | 1 + framework/local/README.md | 1 + framework/local/api/endpoints/cart/index.ts | 1 + .../local/api/endpoints/catalog/index.ts | 1 + .../local/api/endpoints/catalog/products.ts | 1 + .../local/api/endpoints/checkout/index.ts | 1 + .../local/api/endpoints/customer/index.ts | 1 + framework/local/api/endpoints/login/index.ts | 1 + framework/local/api/endpoints/logout/index.ts | 1 + framework/local/api/endpoints/signup/index.ts | 1 + .../local/api/endpoints/wishlist/index.tsx | 1 + framework/local/api/index.ts | 42 + .../local/api/operations/get-all-pages.ts | 19 + .../api/operations/get-all-product-paths.ts | 15 + .../local/api/operations/get-all-products.ts | 25 + .../api/operations/get-customer-wishlist.ts | 6 + framework/local/api/operations/get-page.ts | 13 + framework/local/api/operations/get-product.ts | 26 + .../local/api/operations/get-site-info.ts | 43 + framework/local/api/operations/index.ts | 6 + framework/local/api/utils/fetch-local.ts | 34 + framework/local/api/utils/fetch.ts | 3 + framework/local/auth/index.ts | 3 + framework/local/auth/use-login.tsx | 16 + framework/local/auth/use-logout.tsx | 17 + framework/local/auth/use-signup.tsx | 19 + framework/local/cart/index.ts | 4 + framework/local/cart/use-add-item.tsx | 17 + framework/local/cart/use-cart.tsx | 42 + framework/local/cart/use-remove-item.tsx | 18 + framework/local/cart/use-update-item.tsx | 18 + framework/local/commerce.config.json | 6 + framework/local/customer/index.ts | 1 + framework/local/customer/use-customer.tsx | 15 + framework/local/data.json | 235 + framework/local/fetcher.ts | 11 + framework/local/index.tsx | 32 + framework/local/next.config.js | 8 + framework/local/product/index.ts | 2 + framework/local/product/use-price.tsx | 2 + framework/local/product/use-search.tsx | 17 + framework/local/provider.ts | 21 + framework/local/wishlist/use-add-item.tsx | 13 + framework/local/wishlist/use-remove-item.tsx | 17 + framework/local/wishlist/use-wishlist.tsx | 43 + .../saleor/api/utils/fetch-graphql-api.ts | 2 +- .../shopify/api/operations/get-site-info.ts | 10 +- .../shopify/api/utils/fetch-graphql-api.ts | 47 +- framework/shopify/index.tsx | 3 +- .../shopify/utils/handle-fetch-response.ts | 2 +- framework/shopify/utils/normalize.ts | 1 + .../swell/api/operations/get-site-info.ts | 4 +- framework/vendure/auth/use-logout.tsx | 24 +- lib/search-props.tsx | 27 + next.config.js | 14 - package-lock.json | 11033 ++++++++++++++++ package.json | 6 +- pages/404.tsx | 35 + pages/[...pages].tsx | 13 +- pages/cart.tsx | 22 +- pages/index.tsx | 35 +- pages/orders.tsx | 8 +- pages/product/[slug].tsx | 26 +- pages/profile.tsx | 6 +- pages/search.tsx | 469 +- pages/search/[category].tsx | 16 + pages/search/designers/[name].tsx | 16 + pages/search/designers/[name]/[category].tsx | 16 + pages/wishlist.tsx | 8 +- public/assets/drop-shirt-0.png | Bin 0 -> 157663 bytes public/assets/drop-shirt-1.png | Bin 0 -> 260517 bytes public/assets/drop-shirt-2.png | Bin 0 -> 244812 bytes public/assets/drop-shirt.png | Bin 0 -> 157663 bytes public/assets/lightweight-jacket-0.png | Bin 0 -> 507021 bytes public/assets/lightweight-jacket-1.png | Bin 0 -> 476841 bytes public/assets/lightweight-jacket-2.png | Bin 0 -> 353198 bytes public/assets/t-shirt-0.png | Bin 0 -> 415845 bytes public/assets/t-shirt-1.png | Bin 0 -> 337401 bytes public/assets/t-shirt-2.png | Bin 0 -> 429830 bytes public/assets/t-shirt-3.png | Bin 0 -> 666930 bytes public/assets/t-shirt-4.png | Bin 0 -> 364452 bytes public/jacket.png | Bin 772153 -> 0 bytes tailwind.config.js | 24 +- tsconfig.js | 57 + tsconfig.json | 13 +- yarn.lock | 848 +- 202 files changed, 15406 insertions(+), 2201 deletions(-) create mode 100644 components/checkout/CheckoutSidebarView/CheckoutSidebarView.module.css create mode 100644 components/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx create mode 100644 components/checkout/CheckoutSidebarView/index.ts create mode 100644 components/checkout/PaymentMethodView/PaymentMethodView.module.css create mode 100644 components/checkout/PaymentMethodView/PaymentMethodView.tsx create mode 100644 components/checkout/PaymentMethodView/index.ts create mode 100644 components/checkout/PaymentWidget/PaymentWidget.module.css create mode 100644 components/checkout/PaymentWidget/PaymentWidget.tsx create mode 100644 components/checkout/PaymentWidget/index.ts create mode 100644 components/checkout/ShippingView/ShippingView.module.css create mode 100644 components/checkout/ShippingView/ShippingView.tsx create mode 100644 components/checkout/ShippingView/index.ts create mode 100644 components/checkout/ShippingWidget/ShippingWidget.module.css create mode 100644 components/checkout/ShippingWidget/ShippingWidget.tsx create mode 100644 components/checkout/ShippingWidget/index.ts create mode 100644 components/common/SidebarLayout/SidebarLayout.module.css create mode 100644 components/common/SidebarLayout/SidebarLayout.tsx create mode 100644 components/common/SidebarLayout/index.ts rename components/icons/{RightArrow.tsx => ArrowRight.tsx} (79%) create mode 100644 components/icons/ChevronDown.tsx create mode 100644 components/icons/ChevronLeft.tsx create mode 100644 components/icons/ChevronRight.tsx create mode 100644 components/icons/Star.tsx create mode 100644 components/product/ProductOptions/ProductOptions.tsx create mode 100644 components/product/ProductOptions/index.ts create mode 100644 components/product/ProductSidebar/ProductSidebar.module.css create mode 100644 components/product/ProductSidebar/ProductSidebar.tsx create mode 100644 components/product/ProductSidebar/index.ts create mode 100644 components/product/ProductSliderControl/ProductSliderControl.module.css create mode 100644 components/product/ProductSliderControl/ProductSliderControl.tsx create mode 100644 components/product/ProductSliderControl/index.ts create mode 100644 components/product/ProductTag/ProductTag.module.css create mode 100644 components/product/ProductTag/ProductTag.tsx create mode 100644 components/product/ProductTag/index.ts create mode 100644 components/search.tsx create mode 100644 components/ui/Collapse/Collapse.module.css create mode 100644 components/ui/Collapse/Collapse.tsx create mode 100644 components/ui/Collapse/index.ts create mode 100644 components/ui/Quantity/Quantity.module.css create mode 100644 components/ui/Quantity/Quantity.tsx create mode 100644 components/ui/Quantity/index.ts create mode 100644 components/ui/Rating/Rating.module.css create mode 100644 components/ui/Rating/Rating.tsx create mode 100644 components/ui/Rating/index.ts create mode 100644 components/wishlist/WishlistButton/WishlistButton.module.css create mode 100644 framework/local/.env.template create mode 100644 framework/local/README.md create mode 100644 framework/local/api/endpoints/cart/index.ts create mode 100644 framework/local/api/endpoints/catalog/index.ts create mode 100644 framework/local/api/endpoints/catalog/products.ts create mode 100644 framework/local/api/endpoints/checkout/index.ts create mode 100644 framework/local/api/endpoints/customer/index.ts create mode 100644 framework/local/api/endpoints/login/index.ts create mode 100644 framework/local/api/endpoints/logout/index.ts create mode 100644 framework/local/api/endpoints/signup/index.ts create mode 100644 framework/local/api/endpoints/wishlist/index.tsx create mode 100644 framework/local/api/index.ts create mode 100644 framework/local/api/operations/get-all-pages.ts create mode 100644 framework/local/api/operations/get-all-product-paths.ts create mode 100644 framework/local/api/operations/get-all-products.ts create mode 100644 framework/local/api/operations/get-customer-wishlist.ts create mode 100644 framework/local/api/operations/get-page.ts create mode 100644 framework/local/api/operations/get-product.ts create mode 100644 framework/local/api/operations/get-site-info.ts create mode 100644 framework/local/api/operations/index.ts create mode 100644 framework/local/api/utils/fetch-local.ts create mode 100644 framework/local/api/utils/fetch.ts create mode 100644 framework/local/auth/index.ts create mode 100644 framework/local/auth/use-login.tsx create mode 100644 framework/local/auth/use-logout.tsx create mode 100644 framework/local/auth/use-signup.tsx create mode 100644 framework/local/cart/index.ts create mode 100644 framework/local/cart/use-add-item.tsx create mode 100644 framework/local/cart/use-cart.tsx create mode 100644 framework/local/cart/use-remove-item.tsx create mode 100644 framework/local/cart/use-update-item.tsx create mode 100644 framework/local/commerce.config.json create mode 100644 framework/local/customer/index.ts create mode 100644 framework/local/customer/use-customer.tsx create mode 100644 framework/local/data.json create mode 100644 framework/local/fetcher.ts create mode 100644 framework/local/index.tsx create mode 100644 framework/local/next.config.js create mode 100644 framework/local/product/index.ts create mode 100644 framework/local/product/use-price.tsx create mode 100644 framework/local/product/use-search.tsx create mode 100644 framework/local/provider.ts create mode 100644 framework/local/wishlist/use-add-item.tsx create mode 100644 framework/local/wishlist/use-remove-item.tsx create mode 100644 framework/local/wishlist/use-wishlist.tsx create mode 100644 lib/search-props.tsx create mode 100644 package-lock.json create mode 100644 pages/404.tsx create mode 100644 pages/search/[category].tsx create mode 100644 pages/search/designers/[name].tsx create mode 100644 pages/search/designers/[name]/[category].tsx create mode 100644 public/assets/drop-shirt-0.png create mode 100644 public/assets/drop-shirt-1.png create mode 100644 public/assets/drop-shirt-2.png create mode 100644 public/assets/drop-shirt.png create mode 100644 public/assets/lightweight-jacket-0.png create mode 100644 public/assets/lightweight-jacket-1.png create mode 100644 public/assets/lightweight-jacket-2.png create mode 100644 public/assets/t-shirt-0.png create mode 100644 public/assets/t-shirt-1.png create mode 100644 public/assets/t-shirt-2.png create mode 100644 public/assets/t-shirt-3.png create mode 100644 public/assets/t-shirt-4.png delete mode 100644 public/jacket.png create mode 100644 tsconfig.js diff --git a/README.md b/README.md index 189192216..7c69eb09d 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,11 @@ That's it! Every provider defines the features that it supports under `framework/{provider}/commerce.config.json` +#### Features Available + +- wishlist +- customCheckout + #### How to turn Features on and off > NOTE: The selected provider should support the feature that you are toggling. (This means that you can't turn wishlist on if the provider doesn't support this functionality out the box) @@ -73,7 +78,8 @@ Every provider defines the features that it supports under `framework/{provider} ```json { "features": { - "wishlist": false + "wishlist": false, + "customCheckout": true } } ``` diff --git a/assets/base.css b/assets/base.css index e63ea1aa4..00081f459 100644 --- a/assets/base.css +++ b/assets/base.css @@ -15,21 +15,28 @@ --cyan: #22b8cf; --green: #37b679; --red: #da3c3c; - --pink: #e64980; --purple: #f81ce5; --blue: #0070f3; - --violet: #5f3dc4; - --violet-light: #7048e8; - --accents-0: #f8f9fa; - --accents-1: #f1f3f5; - --accents-2: #e9ecef; - --accents-3: #dee2e6; - --accents-4: #ced4da; - --accents-5: #adb5bd; - --accents-6: #868e96; - --accents-7: #495057; - --accents-8: #343a40; - --accents-9: #212529; + + --pink: #ff0080; + --pink-light: #ff379c; + + --magenta: #eb367f; + + --violet: #7928ca; + --violet-dark: #4c2889; + + --accent-0: #fff; + --accent-1: #fafafa; + --accent-2: #eaeaea; + --accent-3: #999999; + --accent-4: #888888; + --accent-5: #666666; + --accent-6: #444444; + --accent-7: #333333; + --accent-8: #111111; + --accent-9: #000; + --font-sans: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', sans-serif; } @@ -48,16 +55,16 @@ --text-primary: white; --text-secondary: black; - --accents-0: #212529; - --accents-1: #343a40; - --accents-2: #495057; - --accents-3: #868e96; - --accents-4: #adb5bd; - --accents-5: #ced4da; - --accents-6: #dee2e6; - --accents-7: #e9ecef; - --accents-8: #f1f3f5; - --accents-9: #f8f9fa; + --accent-9: #fff; + --accent-8: #fafafa; + --accent-7: #eaeaea; + --accent-6: #999999; + --accent-5: #888888; + --accent-4: #666666; + --accent-3: #444444; + --accent-2: #333333; + --accent-1: #111111; + --accent-0: #000; } *, @@ -84,6 +91,7 @@ body { -moz-osx-font-smoothing: grayscale; background-color: var(--primary); color: var(--text-primary); + overscroll-behavior-x: none; } body { diff --git a/components/auth/ForgotPassword.tsx b/components/auth/ForgotPassword.tsx index 597ee328e..dbac371c7 100644 --- a/components/auth/ForgotPassword.tsx +++ b/components/auth/ForgotPassword.tsx @@ -61,7 +61,7 @@ const ForgotPassword: FC = () => { - Do you have an account? + Do you have an account? {` `} = () => { Log In

- Do you have an account? + Do you have an account? {` `} { const { closeSidebarIfPresent } = useUI() + const [removing, setRemoving] = useState(false) + const [quantity, setQuantity] = useState(item.quantity) + const removeItem = useRemoveItem() + const updateItem = useUpdateItem({ item }) const { price } = usePrice({ amount: item.variant.price * item.quantity, @@ -33,48 +40,28 @@ const CartItem = ({ currencyCode, }) - const updateItem = useUpdateItem({ item }) - const removeItem = useRemoveItem() - const [quantity, setQuantity] = useState(item.quantity) - const [removing, setRemoving] = useState(false) + const handleChange = async ({ + target: { value }, + }: ChangeEvent) => { + setQuantity(Number(value)) + await updateItem({ quantity: Number(value) }) + } - const updateQuantity = async (val: number) => { + const increaseQuantity = async (n = 1) => { + const val = Number(quantity) + n + setQuantity(val) await updateItem({ quantity: val }) } - const handleQuantity = (e: ChangeEvent) => { - const val = !e.target.value ? '' : Number(e.target.value) - - if (!val || (Number.isInteger(val) && val >= 0)) { - setQuantity(val) - } - } - const handleBlur = () => { - const val = Number(quantity) - - if (val !== item.quantity) { - updateQuantity(val) - } - } - const increaseQuantity = (n = 1) => { - const val = Number(quantity) + n - - if (Number.isInteger(val) && val >= 0) { - setQuantity(val) - updateQuantity(val) - } - } const handleRemove = async () => { setRemoving(true) - try { - // If this action succeeds then there's no need to do `setRemoving(true)` - // because the component will be removed from the view await removeItem(item) } catch (error) { setRemoving(false) } } + // TODO: Add a type for this const options = (item as any).options @@ -87,79 +74,76 @@ const CartItem = ({ return (
  • -
    - - closeSidebarIfPresent()} - className={s.productImage} - width={150} - height={150} - src={item.variant.image!.url} - alt={item.variant.image!.altText} - unoptimized - /> - -
    -
    - - closeSidebarIfPresent()} - > -
    +
    + + closeSidebarIfPresent()} + className={s.productImage} + width={150} + height={150} + src={item.variant.image!.url} + alt={item.variant.image!.altText} + unoptimized + /> + +
    +
    + + closeSidebarIfPresent()} > {item.name} + + + {options && options.length > 0 && ( +
    + {options.map((option: ItemOption, i: number) => ( +
    + {option.name} + {option.name === 'Color' ? ( + + ) : ( + + {option.value} + + )} + {i === options.length - 1 ? '' : } +
    + ))}
    - {item.variant ? {item.variant.name} : ""} - - - {options && options.length > 0 ? ( -
    - {options.map((option: ItemOption, i: number) => ( - - {option.value} - {i === options.length - 1 ? '' : ', '} - - ))} -
    - ) : null} -
    - - - + )} + {variant === 'display' && ( +
    {quantity}x
    + )} +
    +
    + {price}
    -
    - {price} - -
    + {variant === 'default' && ( + increaseQuantity(1)} + decrease={() => increaseQuantity(-1)} + /> + )}
  • ) } diff --git a/components/cart/CartSidebarView/CartSidebarView.module.css b/components/cart/CartSidebarView/CartSidebarView.module.css index 9b94021ad..c9ffbed50 100644 --- a/components/cart/CartSidebarView/CartSidebarView.module.css +++ b/components/cart/CartSidebarView/CartSidebarView.module.css @@ -1,15 +1,11 @@ .root { - @apply h-full flex flex-col; + min-height: 100vh; } .root.empty { @apply bg-secondary text-secondary; } -.root.success { - @apply bg-green text-white; -} - -.root.error { - @apply bg-red text-white; +.lineItemsList { + @apply py-4 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accent-2 border-accent-2; } diff --git a/components/cart/CartSidebarView/CartSidebarView.tsx b/components/cart/CartSidebarView/CartSidebarView.tsx index 326390327..128b928a8 100644 --- a/components/cart/CartSidebarView/CartSidebarView.tsx +++ b/components/cart/CartSidebarView/CartSidebarView.tsx @@ -1,17 +1,17 @@ -import { FC } from 'react' import cn from 'classnames' import Link from 'next/link' -import CartItem from '../CartItem' +import { FC } from 'react' import s from './CartSidebarView.module.css' -import { Button } from '@components/ui' -import { UserNav } from '@components/common' +import CartItem from '../CartItem' +import { Button, Text } from '@components/ui' import { useUI } from '@components/ui/context' import { Bag, Cross, Check } from '@components/icons' import useCart from '@framework/cart/use-cart' import usePrice from '@framework/product/use-price' +import SidebarLayout from '@components/common/SidebarLayout' const CartSidebarView: FC = () => { - const { closeSidebar } = useUI() + const { closeSidebar, setSidebarView } = useUI() const { data, isLoading, isEmpty } = useCart() const { price: subTotal } = usePrice( @@ -27,33 +27,18 @@ const CartSidebarView: FC = () => { } ) const handleClose = () => closeSidebar() + const goToCheckout = () => setSidebarView('CHECKOUT_VIEW') const error = null const success = null return ( -
    -
    -
    -
    - -
    -
    - -
    -
    -
    - {isLoading || isEmpty ? (
    @@ -62,7 +47,7 @@ const CartSidebarView: FC = () => {

    Your cart is empty

    -

    +

    Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.

    @@ -89,14 +74,11 @@ const CartSidebarView: FC = () => { <>
    -

    + My Cart -

    + -
      +
        {data!.lineItems.map((item: any) => ( {
    -
    -
    -
      -
    • - Subtotal - {subTotal} -
    • -
    • - Taxes - Calculated at checkout -
    • -
    • - Estimated Shipping - FREE -
    • -
    -
    - Total - {total} -
    +
    +
      +
    • + Subtotal + {subTotal} +
    • +
    • + Taxes + Calculated at checkout +
    • +
    • + Shipping + FREE +
    • +
    +
    + Total + {total} +
    +
    + {process.env.COMMERCE_CUSTOMCHECKOUT_ENABLED ? ( + + ) : ( + + )}
    -
    )} -
    + ) } diff --git a/components/checkout/CheckoutSidebarView/CheckoutSidebarView.module.css b/components/checkout/CheckoutSidebarView/CheckoutSidebarView.module.css new file mode 100644 index 000000000..34c1b487c --- /dev/null +++ b/components/checkout/CheckoutSidebarView/CheckoutSidebarView.module.css @@ -0,0 +1,7 @@ +.root { + min-height: calc(100vh - 322px); +} + +.lineItemsList { + @apply py-4 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accent-2 border-accent-2; +} diff --git a/components/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx b/components/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx new file mode 100644 index 000000000..fb562e7af --- /dev/null +++ b/components/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx @@ -0,0 +1,89 @@ +import cn from 'classnames' +import Link from 'next/link' +import { FC } from 'react' +import CartItem from '@components/cart/CartItem' +import { Button, Text } from '@components/ui' +import { useUI } from '@components/ui/context' +import useCart from '@framework/cart/use-cart' +import usePrice from '@framework/product/use-price' +import ShippingWidget from '../ShippingWidget' +import PaymentWidget from '../PaymentWidget' +import SidebarLayout from '@components/common/SidebarLayout' +import s from './CheckoutSidebarView.module.css' + +const CheckoutSidebarView: FC = () => { + const { setSidebarView } = useUI() + const { data } = useCart() + + const { price: subTotal } = usePrice( + data && { + amount: Number(data.subtotalPrice), + currencyCode: data.currency.code, + } + ) + const { price: total } = usePrice( + data && { + amount: Number(data.totalPrice), + currencyCode: data.currency.code, + } + ) + + return ( + setSidebarView('CART_VIEW')} + > +
    + + Checkout + + + setSidebarView('PAYMENT_VIEW')} /> + setSidebarView('SHIPPING_VIEW')} /> + +
      + {data!.lineItems.map((item: any) => ( + + ))} +
    +
    + +
    +
      +
    • + Subtotal + {subTotal} +
    • +
    • + Taxes + Calculated at checkout +
    • +
    • + Shipping + FREE +
    • +
    +
    + Total + {total} +
    +
    + {/* Once data is correcly filled */} + {/* */} + +
    +
    +
    + ) +} + +export default CheckoutSidebarView diff --git a/components/checkout/CheckoutSidebarView/index.ts b/components/checkout/CheckoutSidebarView/index.ts new file mode 100644 index 000000000..168bc58f4 --- /dev/null +++ b/components/checkout/CheckoutSidebarView/index.ts @@ -0,0 +1 @@ +export { default } from './CheckoutSidebarView' diff --git a/components/checkout/PaymentMethodView/PaymentMethodView.module.css b/components/checkout/PaymentMethodView/PaymentMethodView.module.css new file mode 100644 index 000000000..f3880c72c --- /dev/null +++ b/components/checkout/PaymentMethodView/PaymentMethodView.module.css @@ -0,0 +1,17 @@ +.fieldset { + @apply flex flex-col my-3; +} + +.fieldset .label { + @apply text-accent-7 uppercase text-xs font-medium mb-2; +} + +.fieldset .input, +.fieldset .select { + @apply p-2 border border-accent-2 w-full text-sm font-normal; +} + +.fieldset .input:focus, +.fieldset .select:focus { + @apply outline-none shadow-outline-normal; +} diff --git a/components/checkout/PaymentMethodView/PaymentMethodView.tsx b/components/checkout/PaymentMethodView/PaymentMethodView.tsx new file mode 100644 index 000000000..a5f6f4b51 --- /dev/null +++ b/components/checkout/PaymentMethodView/PaymentMethodView.tsx @@ -0,0 +1,84 @@ +import { FC } from 'react' +import cn from 'classnames' +import { Button, Text } from '@components/ui' +import { useUI } from '@components/ui/context' +import s from './PaymentMethodView.module.css' +import SidebarLayout from '@components/common/SidebarLayout' + +const PaymentMethodView: FC = () => { + const { setSidebarView } = useUI() + + return ( + setSidebarView('CHECKOUT_VIEW')}> +
    + Payment Method +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    +
    +
    + +
    +
    + ) +} + +export default PaymentMethodView diff --git a/components/checkout/PaymentMethodView/index.ts b/components/checkout/PaymentMethodView/index.ts new file mode 100644 index 000000000..951b3c318 --- /dev/null +++ b/components/checkout/PaymentMethodView/index.ts @@ -0,0 +1 @@ +export { default } from './PaymentMethodView' diff --git a/components/checkout/PaymentWidget/PaymentWidget.module.css b/components/checkout/PaymentWidget/PaymentWidget.module.css new file mode 100644 index 000000000..38dcab0c0 --- /dev/null +++ b/components/checkout/PaymentWidget/PaymentWidget.module.css @@ -0,0 +1,4 @@ +.root { + @apply border border-accent-2 px-6 py-5 mb-4 text-center + flex items-center cursor-pointer hover:border-accent-4; +} diff --git a/components/checkout/PaymentWidget/PaymentWidget.tsx b/components/checkout/PaymentWidget/PaymentWidget.tsx new file mode 100644 index 000000000..e1892934e --- /dev/null +++ b/components/checkout/PaymentWidget/PaymentWidget.tsx @@ -0,0 +1,29 @@ +import { FC } from 'react' +import s from './PaymentWidget.module.css' +import { ChevronRight, CreditCard } from '@components/icons' + +interface ComponentProps { + onClick?: () => any +} + +const PaymentWidget: FC = ({ onClick }) => { + /* Shipping Address + Only available with checkout set to true - + This means that the provider does offer checkout functionality. */ + return ( +
    +
    + + + Add Payment Method + + {/* VISA #### #### #### 2345 */} +
    +
    + +
    +
    + ) +} + +export default PaymentWidget diff --git a/components/checkout/PaymentWidget/index.ts b/components/checkout/PaymentWidget/index.ts new file mode 100644 index 000000000..18cadea57 --- /dev/null +++ b/components/checkout/PaymentWidget/index.ts @@ -0,0 +1 @@ +export { default } from './PaymentWidget' diff --git a/components/checkout/ShippingView/ShippingView.module.css b/components/checkout/ShippingView/ShippingView.module.css new file mode 100644 index 000000000..157d3174e --- /dev/null +++ b/components/checkout/ShippingView/ShippingView.module.css @@ -0,0 +1,21 @@ +.fieldset { + @apply flex flex-col my-3; +} + +.fieldset .label { + @apply text-accent-7 uppercase text-xs font-medium mb-2; +} + +.fieldset .input, +.fieldset .select { + @apply p-2 border border-accent-2 w-full text-sm font-normal; +} + +.fieldset .input:focus, +.fieldset .select:focus { + @apply outline-none shadow-outline-normal; +} + +.radio { + @apply bg-black; +} diff --git a/components/checkout/ShippingView/ShippingView.tsx b/components/checkout/ShippingView/ShippingView.tsx new file mode 100644 index 000000000..1d03a2aac --- /dev/null +++ b/components/checkout/ShippingView/ShippingView.tsx @@ -0,0 +1,78 @@ +import { FC } from 'react' +import cn from 'classnames' +import s from './ShippingView.module.css' +import Button from '@components/ui/Button' +import { useUI } from '@components/ui/context' +import SidebarLayout from '@components/common/SidebarLayout' + +const PaymentMethodView: FC = () => { + const { setSidebarView } = useUI() + + return ( + setSidebarView('CHECKOUT_VIEW')}> +
    +

    + Shipping +

    +
    +
    + + Same as billing address +
    +
    + + + Use a different shipping address + +
    +
    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    +
    +
    + +
    +
    + ) +} + +export default PaymentMethodView diff --git a/components/checkout/ShippingView/index.ts b/components/checkout/ShippingView/index.ts new file mode 100644 index 000000000..428e7e4fe --- /dev/null +++ b/components/checkout/ShippingView/index.ts @@ -0,0 +1 @@ +export { default } from './ShippingView' diff --git a/components/checkout/ShippingWidget/ShippingWidget.module.css b/components/checkout/ShippingWidget/ShippingWidget.module.css new file mode 100644 index 000000000..38dcab0c0 --- /dev/null +++ b/components/checkout/ShippingWidget/ShippingWidget.module.css @@ -0,0 +1,4 @@ +.root { + @apply border border-accent-2 px-6 py-5 mb-4 text-center + flex items-center cursor-pointer hover:border-accent-4; +} diff --git a/components/checkout/ShippingWidget/ShippingWidget.tsx b/components/checkout/ShippingWidget/ShippingWidget.tsx new file mode 100644 index 000000000..b072178b0 --- /dev/null +++ b/components/checkout/ShippingWidget/ShippingWidget.tsx @@ -0,0 +1,33 @@ +import { FC } from 'react' +import s from './ShippingWidget.module.css' +import { ChevronRight, MapPin } from '@components/icons' +import cn from 'classnames' + +interface ComponentProps { + onClick?: () => any +} + +const ShippingWidget: FC = ({ onClick }) => { + /* Shipping Address + Only available with checkout set to true - + This means that the provider does offer checkout functionality. */ + return ( +
    +
    + + + Add Shipping Address + + {/* + 1046 Kearny Street.
    + San Franssisco, California +
    */} +
    +
    + +
    +
    + ) +} + +export default ShippingWidget diff --git a/components/checkout/ShippingWidget/index.ts b/components/checkout/ShippingWidget/index.ts new file mode 100644 index 000000000..88e6dca4b --- /dev/null +++ b/components/checkout/ShippingWidget/index.ts @@ -0,0 +1 @@ +export { default } from './ShippingWidget' diff --git a/components/common/Avatar/Avatar.tsx b/components/common/Avatar/Avatar.tsx index f78aa1d01..663538450 100644 --- a/components/common/Avatar/Avatar.tsx +++ b/components/common/Avatar/Avatar.tsx @@ -14,7 +14,7 @@ const Avatar: FC = ({}) => {
    {/* Add an image - We're generating a gradient as placeholder */}
    diff --git a/components/common/FeatureBar/FeatureBar.module.css b/components/common/FeatureBar/FeatureBar.module.css index 419fd4b08..a3cb61cd2 100644 --- a/components/common/FeatureBar/FeatureBar.module.css +++ b/components/common/FeatureBar/FeatureBar.module.css @@ -1,9 +1,7 @@ .root { @apply text-center p-6 bg-primary text-sm flex-row justify-center items-center font-medium fixed bottom-0 w-full z-30 transition-all duration-300 ease-out; -} -@screen md { - .root { + @screen md { @apply flex text-left; } } diff --git a/components/common/Footer/Footer.module.css b/components/common/Footer/Footer.module.css index 259318ecf..2ba492086 100644 --- a/components/common/Footer/Footer.module.css +++ b/components/common/Footer/Footer.module.css @@ -1,3 +1,7 @@ +.root { + @apply border-t border-accent-2; +} + .link { & > svg { @apply transform duration-75 ease-linear; diff --git a/components/common/Footer/Footer.tsx b/components/common/Footer/Footer.tsx index 4190815ec..04b80404e 100644 --- a/components/common/Footer/Footer.tsx +++ b/components/common/Footer/Footer.tsx @@ -15,65 +15,50 @@ interface Props { pages?: Page[] } -const LEGAL_PAGES = ['terms-of-use', 'shipping-returns', 'privacy-policy'] +const links = [ + { + name: 'Home', + url: '/', + }, +] const Footer: FC = ({ className, pages }) => { - const { sitePages, legalPages } = usePages(pages) - const rootClassName = cn(className) + const { sitePages } = usePages(pages) + const rootClassName = cn(s.root, className) return (