From b8a0bb5a21029cc037a8af228d1406226ee311b6 Mon Sep 17 00:00:00 2001 From: okbel Date: Fri, 29 Jan 2021 11:22:41 -0300 Subject: [PATCH 1/4] Progress --- CHANGELOG.md | 5 +++-- components/product/ProductView/ProductView.tsx | 5 ++--- .../wishlist/WishlistButton/WishlistButton.tsx | 6 +++--- tsconfig.json | 12 ++++++------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d1d95638..b21b673f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ## Changelog -- Select Variants Working -- Click on cart item title, closes the sidebar +- Select Variants Fully Working +- Click on the Cart Item Title, closes the sidebar. + diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index d3d11ea16..448dfb10a 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -4,9 +4,8 @@ import { NextSeo } from 'next-seo' import { FC, useState } from 'react' import s from './ProductView.module.css' -import { useUI } from '@components/ui' import { Swatch, ProductSlider } from '@components/product' -import { Button, Container, Text } from '@components/ui' +import { Button, Container, Text, useUI} from '@components/ui' import usePrice from '@framework/product/use-price' import { useAddItem } from '@framework/cart' @@ -100,8 +99,8 @@ const ProductView: FC = ({ product }) => { ))} - +
{product.options?.map((opt) => ( diff --git a/components/wishlist/WishlistButton/WishlistButton.tsx b/components/wishlist/WishlistButton/WishlistButton.tsx index dced18a89..19ae3ec1a 100644 --- a/components/wishlist/WishlistButton/WishlistButton.tsx +++ b/components/wishlist/WishlistButton/WishlistButton.tsx @@ -1,12 +1,12 @@ import React, { FC, useState } from 'react' import cn from 'classnames' -import { Heart } from '@components/icons' import { useUI } from '@components/ui' -import useCustomer from '@framework/customer/use-customer' +import { Heart } from '@components/icons' import useAddItem from '@framework/wishlist/use-add-item' +import useWishlist from '@framework/wishlist/use-wishlist' +import useCustomer from '@framework/customer/use-customer' import useRemoveItem from '@framework/wishlist/use-remove-item' -import useWishlist from '@framework/wishlist/use-add-item' type Props = { productId: Product['id'] diff --git a/tsconfig.json b/tsconfig.json index 67de1ee36..480622bb4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,16 +16,16 @@ "jsx": "preserve", "paths": { "@lib/*": ["lib/*"], - "@assets/*": ["assets/*"], - "@config/*": ["config/*"], - "@components/*": ["components/*"], "@utils/*": ["utils/*"], - "@commerce/*": ["framework/commerce/*"], + "@config/*": ["config/*"], + "@assets/*": ["assets/*"], + "@components/*": ["components/*"], "@commerce": ["framework/commerce"], - "@framework/*": ["framework/bigcommerce/*"], + "@commerce/*": ["framework/commerce/*"], "@framework": ["framework/bigcommerce"] + "@framework/*": ["framework/bigcommerce/*"], } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], - "exclude": ["node_modules", "components/wishlist"] + "exclude": ["node_modules"] } From 3f30344619730ce20eac92c0c8b0d66b3d18955a Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 4 Feb 2021 12:29:20 -0300 Subject: [PATCH 2/4] userAvatar --- components/common/Avatar/Avatar.tsx | 14 +++++--------- components/common/UserNav/UserNav.tsx | 2 +- components/ui/context.tsx | 16 ++++++++++++++++ lib/hooks/useUserAvatar.ts | 26 ++++++++++++++++++++++++++ tsconfig.json | 4 ++-- 5 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 lib/hooks/useUserAvatar.ts diff --git a/components/common/Avatar/Avatar.tsx b/components/common/Avatar/Avatar.tsx index 351a117ec..ab91d7089 100644 --- a/components/common/Avatar/Avatar.tsx +++ b/components/common/Avatar/Avatar.tsx @@ -1,5 +1,5 @@ -import { FC, useState, useMemo, useRef, useEffect } from 'react' -import { getRandomPairOfColors } from '@lib/colors' +import { FC, useRef, useEffect } from 'react' +import { useUserAvatar } from '@lib/hooks/useUserAvatar' interface Props { className?: string @@ -7,18 +7,14 @@ interface Props { } const Avatar: FC = ({}) => { - const [bg] = useState(useMemo(() => getRandomPairOfColors, [])) let ref = useRef() as React.MutableRefObject - - useEffect(() => { - if (ref && ref.current) { - ref.current.style.backgroundImage = `linear-gradient(140deg, ${bg[0]}, ${bg[1]} 100%)` - } - }, [bg]) + let { userAvatar } = useUserAvatar() + console.log(userAvatar) return (
{/* Add an image - We're generating a gradient as placeholder */} diff --git a/components/common/UserNav/UserNav.tsx b/components/common/UserNav/UserNav.tsx index f8e6373d9..e33796927 100644 --- a/components/common/UserNav/UserNav.tsx +++ b/components/common/UserNav/UserNav.tsx @@ -3,11 +3,11 @@ import Link from 'next/link' import cn from 'classnames' import useCart from '@framework/cart/use-cart' import useCustomer from '@framework/customer/use-customer' +import { Avatar } from '@components/common' import { Heart, Bag } from '@components/icons' import { useUI } from '@components/ui/context' import DropdownMenu from './DropdownMenu' import s from './UserNav.module.css' -import { Avatar } from '@components/common' interface Props { className?: string diff --git a/components/ui/context.tsx b/components/ui/context.tsx index 206573858..13992a736 100644 --- a/components/ui/context.tsx +++ b/components/ui/context.tsx @@ -8,6 +8,7 @@ export interface State { displayToast: boolean modalView: string toastText: string + userAvatar: string } const initialState = { @@ -17,6 +18,7 @@ const initialState = { modalView: 'LOGIN_VIEW', displayToast: false, toastText: '', + userAvatar: '', } type Action = @@ -52,6 +54,10 @@ type Action = type: 'SET_MODAL_VIEW' view: MODAL_VIEWS } + | { + type: 'SET_USER_AVATAR' + value: string + } type MODAL_VIEWS = 'SIGNUP_VIEW' | 'LOGIN_VIEW' | 'FORGOT_VIEW' type ToastText = string @@ -123,6 +129,12 @@ function uiReducer(state: State, action: Action) { toastText: action.text, } } + case 'SET_USER_AVATAR': { + return { + ...state, + userAvatar: action.value, + } + } } } @@ -147,6 +159,9 @@ export const UIProvider: FC = (props) => { const openToast = () => dispatch({ type: 'OPEN_TOAST' }) const closeToast = () => dispatch({ type: 'CLOSE_TOAST' }) + const setUserAvatar = (value: string) => + dispatch({ type: 'SET_USER_AVATAR', value }) + const setModalView = (view: MODAL_VIEWS) => dispatch({ type: 'SET_MODAL_VIEW', view }) @@ -164,6 +179,7 @@ export const UIProvider: FC = (props) => { setModalView, openToast, closeToast, + setUserAvatar, }), [state] ) diff --git a/lib/hooks/useUserAvatar.ts b/lib/hooks/useUserAvatar.ts new file mode 100644 index 000000000..bc9020931 --- /dev/null +++ b/lib/hooks/useUserAvatar.ts @@ -0,0 +1,26 @@ +import { useEffect } from 'react' +import { getRandomPairOfColors } from '@lib/colors' +import { useUI } from '@components/ui/context' + +export const useUserAvatar = (name = 'userAvatar') => { + const { userAvatar, setUserAvatar } = useUI() + + useEffect(() => { + if (!userAvatar && localStorage.getItem(name)) { + // get bg value locally. + setUserAvatar(localStorage.getItem(name)) + } + if (!localStorage.getItem(name)) { + // local not set, set. + const bg = getRandomPairOfColors() + const value = `linear-gradient(140deg, ${bg[0]}, ${bg[1]} 100%)` + localStorage.setItem(name, value) + setUserAvatar(value) + } + }, []) + + return { + userAvatar, + setUserAvatar, + } +} diff --git a/tsconfig.json b/tsconfig.json index 480622bb4..f8161ccf2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,8 +22,8 @@ "@components/*": ["components/*"], "@commerce": ["framework/commerce"], "@commerce/*": ["framework/commerce/*"], - "@framework": ["framework/bigcommerce"] - "@framework/*": ["framework/bigcommerce/*"], + "@framework": ["framework/bigcommerce"], + "@framework/*": ["framework/bigcommerce/*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], From 300d04c1acadcc4e162c7d9810b6e2730f64c2c4 Mon Sep 17 00:00:00 2001 From: Peter Mekhaeil <4616064+petermekhaeil@users.noreply.github.com> Date: Fri, 12 Feb 2021 22:14:16 +0800 Subject: [PATCH 3/4] Shopify Provider (#186) * Start of Shopify provider * add missing comment to documentation * add missing env vars to documentation * update reference to types file --- .env.template | 4 +- framework/shopify/README.md | 260 ++++++++++++++++++ framework/shopify/api/cart/index.ts | 1 + framework/shopify/api/catalog/index.ts | 1 + framework/shopify/api/catalog/products.ts | 1 + framework/shopify/api/checkout/index.ts | 1 + framework/shopify/api/customers/index.ts | 1 + framework/shopify/api/customers/login.ts | 1 + framework/shopify/api/customers/logout.ts | 1 + framework/shopify/api/customers/signup.ts | 1 + framework/shopify/api/index.ts | 60 ++++ .../api/operations/get-all-collections.ts | 21 ++ framework/shopify/api/operations/get-page.ts | 27 ++ .../shopify/api/utils/fetch-graphql-api.ts | 51 ++++ framework/shopify/api/wishlist/index.tsx | 2 + framework/shopify/auth/use-login.tsx | 13 + framework/shopify/auth/use-logout.tsx | 13 + framework/shopify/auth/use-signup.tsx | 13 + framework/shopify/cart/index.ts | 5 + framework/shopify/cart/use-add-item.tsx | 30 ++ framework/shopify/cart/use-cart.tsx | 42 +++ framework/shopify/cart/use-remove-item.tsx | 17 ++ framework/shopify/cart/use-update-item.tsx | 24 ++ framework/shopify/common/get-all-pages.ts | 55 ++++ framework/shopify/common/get-site-info.ts | 30 ++ framework/shopify/customer/use-customer.tsx | 32 +++ framework/shopify/index.tsx | 109 ++++++++ .../shopify/product/get-all-product-paths.ts | 31 +++ framework/shopify/product/get-all-products.ts | 40 +++ framework/shopify/product/get-product.ts | 37 +++ framework/shopify/product/use-price.tsx | 2 + framework/shopify/product/use-search.tsx | 41 +++ framework/shopify/types.ts | 130 +++++++++ framework/shopify/utils/storage.ts | 13 + .../shopify/utils/to-commerce-products.ts | 60 ++++ framework/shopify/wishlist/use-add-item.tsx | 13 + .../shopify/wishlist/use-remove-item.tsx | 17 ++ framework/shopify/wishlist/use-wishlist.tsx | 45 +++ next.config.js | 2 +- 39 files changed, 1245 insertions(+), 2 deletions(-) create mode 100644 framework/shopify/README.md create mode 100644 framework/shopify/api/cart/index.ts create mode 100644 framework/shopify/api/catalog/index.ts create mode 100644 framework/shopify/api/catalog/products.ts create mode 100644 framework/shopify/api/checkout/index.ts create mode 100644 framework/shopify/api/customers/index.ts create mode 100644 framework/shopify/api/customers/login.ts create mode 100644 framework/shopify/api/customers/logout.ts create mode 100644 framework/shopify/api/customers/signup.ts create mode 100644 framework/shopify/api/index.ts create mode 100644 framework/shopify/api/operations/get-all-collections.ts create mode 100644 framework/shopify/api/operations/get-page.ts create mode 100644 framework/shopify/api/utils/fetch-graphql-api.ts create mode 100644 framework/shopify/api/wishlist/index.tsx create mode 100644 framework/shopify/auth/use-login.tsx create mode 100644 framework/shopify/auth/use-logout.tsx create mode 100644 framework/shopify/auth/use-signup.tsx create mode 100644 framework/shopify/cart/index.ts create mode 100644 framework/shopify/cart/use-add-item.tsx create mode 100644 framework/shopify/cart/use-cart.tsx create mode 100644 framework/shopify/cart/use-remove-item.tsx create mode 100644 framework/shopify/cart/use-update-item.tsx create mode 100644 framework/shopify/common/get-all-pages.ts create mode 100644 framework/shopify/common/get-site-info.ts create mode 100644 framework/shopify/customer/use-customer.tsx create mode 100644 framework/shopify/index.tsx create mode 100644 framework/shopify/product/get-all-product-paths.ts create mode 100644 framework/shopify/product/get-all-products.ts create mode 100644 framework/shopify/product/get-product.ts create mode 100644 framework/shopify/product/use-price.tsx create mode 100644 framework/shopify/product/use-search.tsx create mode 100644 framework/shopify/types.ts create mode 100644 framework/shopify/utils/storage.ts create mode 100644 framework/shopify/utils/to-commerce-products.ts create mode 100644 framework/shopify/wishlist/use-add-item.tsx create mode 100644 framework/shopify/wishlist/use-remove-item.tsx create mode 100644 framework/shopify/wishlist/use-wishlist.tsx diff --git a/.env.template b/.env.template index 73a8a6e3b..7d8400baf 100644 --- a/.env.template +++ b/.env.template @@ -2,4 +2,6 @@ BIGCOMMERCE_STOREFRONT_API_URL= BIGCOMMERCE_STOREFRONT_API_TOKEN= BIGCOMMERCE_STORE_API_URL= BIGCOMMERCE_STORE_API_TOKEN= -BIGCOMMERCE_STORE_API_CLIENT_ID= \ No newline at end of file +BIGCOMMERCE_STORE_API_CLIENT_ID= +SHOPIFY_STORE_DOMAIN= +SHOPIFY_STOREFRONT_ACCESS_TOKEN= \ No newline at end of file diff --git a/framework/shopify/README.md b/framework/shopify/README.md new file mode 100644 index 000000000..fc6a70ce3 --- /dev/null +++ b/framework/shopify/README.md @@ -0,0 +1,260 @@ +## Table of Contents + +- [Getting Started](#getting-started) + - [Modifications](#modifications) + - [Adding item to Cart](#adding-item-to-cart) + - [Proceed to Checkout](#proceed-to-checkout) +- [General Usage](#general-usage) + - [CommerceProvider](#commerceprovider) + - [useCommerce](#usecommerce) +- [Hooks](#hooks) + - [usePrice](#useprice) + - [useAddItem](#useadditem) + - [useRemoveItem](#useremoveitem) + - [useUpdateItem](#useupdateitem) +- [APIs](#apis) + - [getProduct](#getproduct) + - [getAllProducts](#getallproducts) + - [getAllCollections](#getallcollections) + - [getAllPages](#getallpages) + +# Shopify Storefront Data Hooks + +Collection of hooks and data fetching functions to integrate Shopify in a React application. Designed to work with [Next.js Commerce](https://demo.vercel.store/). + +## Getting Started + +1. Install dependencies: + +``` +yarn install shopify-buy +yarn install -D @types/shopify-buy +``` + +3. Environment variables need to be set: + +``` +SHOPIFY_STORE_DOMAIN= +SHOPIFY_STOREFRONT_ACCESS_TOKEN= +NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN= +NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN= +``` + +4. Point the framework to `shopify` by updating `tsconfig.json`: + +``` +"@framework/*": ["framework/shopify/*"], +"@framework": ["framework/shopify"] +``` + +### Modifications + +These modifications are temporarily until contributions are made to remove them. + +#### Adding item to Cart + +```js +// components/product/ProductView/ProductView.tsx +const ProductView: FC = ({ product }) => { + const addToCart = async () => { + setLoading(true) + try { + await addItem({ + productId: product.id, + variantId: variant ? variant.id : product.variants[0].id, + }) + openSidebar() + setLoading(false) + } catch (err) { + setLoading(false) + } + } +} +``` + +#### Proceed to Checkout + +```js +// components/cart/CartSidebarView/CartSidebarView.tsx +import { useCommerce } from '@framework' + +const CartSidebarView: FC = () => { + const { checkout } = useCommerce() + return ( + + ) +} +``` + +## General Usage + +### CommerceProvider + +Provider component that creates the commerce context for children. + +```js +import { CommerceProvider } from '@framework' + +const App = ({ children }) => { + return {children} +} + +export default App +``` + +### useCommerce + +Returns the configs that are defined in the nearest `CommerceProvider`. Also provides access to Shopify's `checkout` and `shop`. + +```js +import { useCommerce } from 'nextjs-commerce-shopify' + +const { checkout, shop } = useCommerce() +``` + +- `checkout`: The information required to checkout items and pay ([Documentation](https://shopify.dev/docs/storefront-api/reference/checkouts/checkout)). +- `shop`: Represents a collection of the general settings and information about the shop ([Documentation](https://shopify.dev/docs/storefront-api/reference/online-store/shop/index)). + +## Hooks + +### usePrice + +Display the product variant price according to currency and locale. + +```js +import usePrice from '@framework/product/use-price' + +const { price } = usePrice({ + amount, +}) +``` + +Takes in either `amount` or `variant`: + +- `amount`: A price value for a particular item if the amount is known. +- `variant`: A shopify product variant. Price will be extracted from the variant. + +### useAddItem + +```js +import { useAddItem } from '@framework/cart' + +const AddToCartButton = ({ variantId, quantity }) => { + const addItem = useAddItem() + + const addToCart = async () => { + await addItem({ + variantId, + }) + } + + return +} +``` + +### useRemoveItem + +```js +import { useRemoveItem } from '@framework/cart' + +const RemoveButton = ({ item }) => { + const removeItem = useRemoveItem() + + const handleRemove = async () => { + await removeItem({ id: item.id }) + } + + return +} +``` + +### useUpdateItem + +```js +import { useUpdateItem } from '@framework/cart' + +const CartItem = ({ item }) => { + const [quantity, setQuantity] = useState(item.quantity) + const updateItem = useUpdateItem(item) + + const updateQuantity = async (e) => { + const val = e.target.value + await updateItem({ quantity: val }) + } + + return ( + + ) +} +``` + +## APIs + +Collections of APIs to fetch data from a Shopify store. + +The data is fetched using the [Shopify JavaScript Buy SDK](https://github.com/Shopify/js-buy-sdk#readme). Read the [Shopify Storefront API reference](https://shopify.dev/docs/storefront-api/reference) for more information. + +### getProduct + +Get a single product by its `handle`. + +```js +import getProduct from '@framework/product/get-product' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const product = await getProduct({ + variables: { slug }, + config, +}) +``` + +### getAllProducts + +```js +import getAllProducts from '@framework/product/get-all-products' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const { products } = await getAllProducts({ + variables: { first: 12 }, + config, +}) +``` + +### getAllCollections + +```js +import getAllCollections from '@framework/product/get-all-collections' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const collections = await getAllCollections({ + config, +}) +``` + +### getAllPages + +```js +import getAllPages from '@framework/common/get-all-pages' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const pages = await getAllPages({ + variables: { first: 12 }, + config, +}) +``` diff --git a/framework/shopify/api/cart/index.ts b/framework/shopify/api/cart/index.ts new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/framework/shopify/api/cart/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/catalog/index.ts b/framework/shopify/api/catalog/index.ts new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/framework/shopify/api/catalog/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/catalog/products.ts b/framework/shopify/api/catalog/products.ts new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/framework/shopify/api/catalog/products.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/checkout/index.ts b/framework/shopify/api/checkout/index.ts new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/framework/shopify/api/checkout/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/customers/index.ts b/framework/shopify/api/customers/index.ts new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/framework/shopify/api/customers/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/customers/login.ts b/framework/shopify/api/customers/login.ts new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/framework/shopify/api/customers/login.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/customers/logout.ts b/framework/shopify/api/customers/logout.ts new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/framework/shopify/api/customers/logout.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/customers/signup.ts b/framework/shopify/api/customers/signup.ts new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/framework/shopify/api/customers/signup.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/index.ts b/framework/shopify/api/index.ts new file mode 100644 index 000000000..dcb0fc2ba --- /dev/null +++ b/framework/shopify/api/index.ts @@ -0,0 +1,60 @@ +import type { CommerceAPIConfig } from '@commerce/api' +import fetchGraphqlApi from './utils/fetch-graphql-api' + +export interface ShopifyConfig extends CommerceAPIConfig {} + +// No I don't like this - will fix it later +const API_URL = + process.env.SHOPIFY_STORE_DOMAIN || + process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN +const API_TOKEN = + process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN || + process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN + +if (!API_URL) { + throw new Error( + `The environment variable SHOPIFY_STORE_DOMAIN is missing and it's required to access your store` + ) +} + +if (!API_TOKEN) { + throw new Error( + `The environment variable SHOPIFY_STOREFRONT_ACCESS_TOKEN is missing and it's required to access your store` + ) +} + +export class Config { + private config: ShopifyConfig + + constructor(config: ShopifyConfig) { + 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({ + commerceUrl: API_URL, + apiToken: API_TOKEN, + // TODO + // @ts-ignore + fetch: fetchGraphqlApi, + customerCookie: 'SHOP_TOKEN', +}) + +export function getConfig(userConfig?: Partial) { + return config.getConfig(userConfig) +} + +export function setConfig(newConfig: Partial) { + return config.setConfig(newConfig) +} diff --git a/framework/shopify/api/operations/get-all-collections.ts b/framework/shopify/api/operations/get-all-collections.ts new file mode 100644 index 000000000..9cf216a91 --- /dev/null +++ b/framework/shopify/api/operations/get-all-collections.ts @@ -0,0 +1,21 @@ +import Client from 'shopify-buy' +import { ShopifyConfig } from '../index' + +type Options = { + config: ShopifyConfig +} + +const getAllCollections = async (options: Options) => { + const { config } = options + + const client = Client.buildClient({ + storefrontAccessToken: config.apiToken, + domain: config.commerceUrl, + }) + + const res = await client.collection.fetchAllWithProducts() + + return JSON.parse(JSON.stringify(res)) +} + +export default getAllCollections diff --git a/framework/shopify/api/operations/get-page.ts b/framework/shopify/api/operations/get-page.ts new file mode 100644 index 000000000..11651e335 --- /dev/null +++ b/framework/shopify/api/operations/get-page.ts @@ -0,0 +1,27 @@ +import { ShopifyConfig, getConfig } from '..' +import type { Page } from '../../types' + +export type { Page } + +export type GetPageResult = T + +export type PageVariables = { + id: string +} + +async function getPage({ + url, + variables, + config, + preview, +}: { + url?: string + variables: PageVariables + config?: ShopifyConfig + preview?: boolean +}): Promise { + config = getConfig(config) + return {} +} + +export default getPage diff --git a/framework/shopify/api/utils/fetch-graphql-api.ts b/framework/shopify/api/utils/fetch-graphql-api.ts new file mode 100644 index 000000000..946242c93 --- /dev/null +++ b/framework/shopify/api/utils/fetch-graphql-api.ts @@ -0,0 +1,51 @@ +import { CommerceAPIFetchOptions } from '@commerce/api' +import { FetcherError } from '@commerce/utils/errors' +import { getConfig } from '../index' + +export interface GraphQLFetcherResult { + data: Data + res: Response +} +export type GraphQLFetcher< + Data extends GraphQLFetcherResult = GraphQLFetcherResult, + Variables = any +> = ( + query: string, + queryData?: CommerceAPIFetchOptions, + fetchOptions?: RequestInit +) => Promise + +const fetchGraphqlApi: GraphQLFetcher = async ( + query: string, + { variables } = {}, + fetchOptions +) => { + const config = getConfig() + const url = `https://${config.commerceUrl}/api/2020-10/graphql.json` + + const res = await fetch(url, { + ...fetchOptions, + method: 'POST', + headers: { + 'X-Shopify-Storefront-Access-Token': config.apiToken, + ...fetchOptions?.headers, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query, + variables, + }), + }) + + const json = await res.json() + if (json.errors) { + throw new FetcherError({ + errors: json.errors ?? [{ message: 'Failed to fetch Shopify API' }], + status: res.status, + }) + } + + return { data: json.data, res } +} + +export default fetchGraphqlApi diff --git a/framework/shopify/api/wishlist/index.tsx b/framework/shopify/api/wishlist/index.tsx new file mode 100644 index 000000000..a72856673 --- /dev/null +++ b/framework/shopify/api/wishlist/index.tsx @@ -0,0 +1,2 @@ +export type WishlistItem = { product: any; id: number } +export default function () {} diff --git a/framework/shopify/auth/use-login.tsx b/framework/shopify/auth/use-login.tsx new file mode 100644 index 000000000..75f067c3a --- /dev/null +++ b/framework/shopify/auth/use-login.tsx @@ -0,0 +1,13 @@ +import { useCallback } from 'react' + +export function emptyHook() { + const useEmptyHook = async (options = {}) => { + return useCallback(async function () { + return Promise.resolve() + }, []) + } + + return useEmptyHook +} + +export default emptyHook diff --git a/framework/shopify/auth/use-logout.tsx b/framework/shopify/auth/use-logout.tsx new file mode 100644 index 000000000..75f067c3a --- /dev/null +++ b/framework/shopify/auth/use-logout.tsx @@ -0,0 +1,13 @@ +import { useCallback } from 'react' + +export function emptyHook() { + const useEmptyHook = async (options = {}) => { + return useCallback(async function () { + return Promise.resolve() + }, []) + } + + return useEmptyHook +} + +export default emptyHook diff --git a/framework/shopify/auth/use-signup.tsx b/framework/shopify/auth/use-signup.tsx new file mode 100644 index 000000000..75f067c3a --- /dev/null +++ b/framework/shopify/auth/use-signup.tsx @@ -0,0 +1,13 @@ +import { useCallback } from 'react' + +export function emptyHook() { + const useEmptyHook = async (options = {}) => { + return useCallback(async function () { + return Promise.resolve() + }, []) + } + + return useEmptyHook +} + +export default emptyHook diff --git a/framework/shopify/cart/index.ts b/framework/shopify/cart/index.ts new file mode 100644 index 000000000..e1c6ef823 --- /dev/null +++ b/framework/shopify/cart/index.ts @@ -0,0 +1,5 @@ +export { default as useCart } from './use-cart' +export { default as useAddItem } from './use-add-item' +export { default as useRemoveItem } from './use-remove-item' +// export { default as useWishlistActions } from './use-cart-actions' +// export { default as useUpdateItem } from './use-cart-actions' diff --git a/framework/shopify/cart/use-add-item.tsx b/framework/shopify/cart/use-add-item.tsx new file mode 100644 index 000000000..276d66e30 --- /dev/null +++ b/framework/shopify/cart/use-add-item.tsx @@ -0,0 +1,30 @@ +import { useCallback } from 'react' +import { LineItemToAdd } from 'shopify-buy' +import { useCommerce } from '../index' + +type Options = { + productId: number + variantId: string | number +} + +const useAddItem = () => { + const { checkout, client, updateCheckout } = useCommerce() + + return useCallback( + async function addItem(options: Options) { + const lineItems: LineItemToAdd[] = [ + { + variantId: `${options.variantId}`, + quantity: 1, + }, + ] + + const cart = await client?.checkout.addLineItems(checkout.id, lineItems) + updateCheckout(cart) + return cart + }, + [checkout, client] + ) +} + +export default useAddItem diff --git a/framework/shopify/cart/use-cart.tsx b/framework/shopify/cart/use-cart.tsx new file mode 100644 index 000000000..f067b520d --- /dev/null +++ b/framework/shopify/cart/use-cart.tsx @@ -0,0 +1,42 @@ +import { useCommerce } from '../index' + +export function emptyHook() { + const { checkout } = useCommerce() + const { lineItems, totalPriceV2 } = checkout || {} + + return { + data: { + subTotal: totalPriceV2?.amount || 0, + total: totalPriceV2?.amount || 0, + currency: { + code: '', + }, + line_items: + lineItems?.map((item) => { + return [ + { + id: item.id, + name: item.title, + quantity: item.quantity, + }, + ] + }) || [], + items: + lineItems?.map((item) => { + return { + id: item.id, + name: item.title, + images: [{ url: '/jacket.png' }], + url: '/', + quantity: item.quantity, + productId: item.id, + variantId: item.id, + } + }) || [], + }, + isEmpty: false, + isLoading: false, + } +} + +export default emptyHook diff --git a/framework/shopify/cart/use-remove-item.tsx b/framework/shopify/cart/use-remove-item.tsx new file mode 100644 index 000000000..c0ce93bd5 --- /dev/null +++ b/framework/shopify/cart/use-remove-item.tsx @@ -0,0 +1,17 @@ +import { useCallback } from 'react' +import { useCommerce } from '../index' + +const useRemoveItem = () => { + const { checkout, client, updateCheckout } = useCommerce() + + return useCallback( + async function removeItem({ id }: { id: string }) { + const cart = await client?.checkout.removeLineItems(checkout.id, [id]) + updateCheckout(cart) + return cart + }, + [checkout, client] + ) +} + +export default useRemoveItem diff --git a/framework/shopify/cart/use-update-item.tsx b/framework/shopify/cart/use-update-item.tsx new file mode 100644 index 000000000..05118a65b --- /dev/null +++ b/framework/shopify/cart/use-update-item.tsx @@ -0,0 +1,24 @@ +import { useCallback } from 'react' +import { useCommerce } from '../index' + +const useUpdateItem = (item: CartItem) => { + const { checkout, client, updateCheckout } = useCommerce() + + return useCallback( + async function updateItem({ quantity }: { quantity: number }) { + const lineItemsToUpdate = [{ id: item.id, quantity }] + + const cart = await client?.checkout.updateLineItems( + checkout.id, + lineItemsToUpdate + ) + + updateCheckout(cart) + + return cart + }, + [checkout, client] + ) +} + +export default useUpdateItem diff --git a/framework/shopify/common/get-all-pages.ts b/framework/shopify/common/get-all-pages.ts new file mode 100644 index 000000000..02db3fdc3 --- /dev/null +++ b/framework/shopify/common/get-all-pages.ts @@ -0,0 +1,55 @@ +import { getConfig, ShopifyConfig } from '../api' +import { Page as PageType, PageEdge } from '../types' + +export type Page = PageType + +export const getAllPagesQuery = /* GraphQL */ ` + query($first: Int!) { + pages(first: $first) { + edges { + node { + id + title + handle + body + bodySummary + url + } + } + } + } +` + +type Variables = { + first?: number +} + +type Options = { + variables?: Variables + config: ShopifyConfig + preview?: boolean +} + +type ReturnType = { + pages: Page[] +} + +const getAllPages = async (options?: Options): Promise => { + let { config, variables = { first: 250 } } = options || {} + + config = getConfig(config) + + const { data } = await config.fetch(getAllPagesQuery, { variables }) + + const pages = data.pages.edges.map(({ node }: PageEdge) => { + return { + ...node, + name: node.handle, + url: `${config!.locale}/${node.handle}`, + } + }) + + return { pages } +} + +export default getAllPages diff --git a/framework/shopify/common/get-site-info.ts b/framework/shopify/common/get-site-info.ts new file mode 100644 index 000000000..c08ae2b92 --- /dev/null +++ b/framework/shopify/common/get-site-info.ts @@ -0,0 +1,30 @@ +import { ShopifyConfig } from '../index' + +type Options = { + config: ShopifyConfig + preview?: boolean +} + +const getSiteInfo = async (options: Options) => { + // TODO + return { + categories: [ + { + path: '', + name: '', + entityId: 0, + }, + ], + brands: [ + { + node: { + path: '', + name: '', + entityId: 0, + }, + }, + ], + } +} + +export default getSiteInfo diff --git a/framework/shopify/customer/use-customer.tsx b/framework/shopify/customer/use-customer.tsx new file mode 100644 index 000000000..a909443ff --- /dev/null +++ b/framework/shopify/customer/use-customer.tsx @@ -0,0 +1,32 @@ +import type { HookFetcher } from '@commerce/utils/types' +import type { SwrOptions } from '@commerce/utils/use-data' +import useCommerceCustomer from '@commerce/use-customer' + +const defaultOpts = {} + +export type Customer = { + entityId: number + firstName: string + lastName: string + email: string +} +export type CustomerData = {} + +export const fetcher: HookFetcher = async () => { + return null +} + +export function extendHook( + customFetcher: typeof fetcher, + swrOptions?: SwrOptions +) { + const useCustomer = () => { + return { data: { firstName: null, lastName: null, email: null } } + } + + useCustomer.extend = extendHook + + return useCustomer +} + +export default extendHook(fetcher) diff --git a/framework/shopify/index.tsx b/framework/shopify/index.tsx new file mode 100644 index 000000000..5fd08e0d9 --- /dev/null +++ b/framework/shopify/index.tsx @@ -0,0 +1,109 @@ +import React, { + ReactNode, + createContext, + useContext, + useMemo, + useState, + useEffect, +} from 'react' +import Client from 'shopify-buy' +import { Shop, Cart, Client as ClientType } from './types' +import { + getCheckoutIdFromStorage, + setCheckoutIdInStorage, +} from './utils/storage' +import { getConfig } from '@framework/api' + +const Commerce = createContext({}) + +type CommerceProps = { + children?: ReactNode + locale: string +} + +type CommerceContextValue = { + client: ClientType + shop: Shop + checkout: Cart + updateCheckout: (cart: Cart | undefined) => void + currencyCode: string + locale: string + sessionToken: string +} + +export function CommerceProvider({ + children, + locale = 'en-US', +}: CommerceProps) { + const sessionToken = 'nextjs-commerce-shopify-token' + + const config = getConfig() + + const client = Client.buildClient({ + storefrontAccessToken: config.apiToken, + domain: config.commerceUrl, + language: locale, + }) as ClientType + + const [shop, setShop] = useState() + const [checkout, setCheckout] = useState() + + const fetchShopify = async () => { + const shopInfo: Shop = await client.shop.fetchInfo() + let checkoutResource: Cart + + const checkoutOptions = { + presentmentCurrencyCode: + /*config.currencyCode ||*/ shopInfo?.currencyCode, + } + + let checkoutId = getCheckoutIdFromStorage(sessionToken) + + // we could have a cart id stored in session storage + // user could be refreshing or navigating back and forth + if (checkoutId) { + checkoutResource = await client.checkout.fetch(checkoutId) + + // could be expired order - we will create a new order + if (checkoutResource.completedAt) { + checkoutResource = await client.checkout.create(checkoutOptions) + } + } else { + checkoutResource = await client.checkout.create(checkoutOptions) + } + + setCheckoutIdInStorage(sessionToken, checkoutResource.id) + + setShop(shopInfo) + setCheckout(checkoutResource) + } + + useEffect(() => { + fetchShopify() + }, []) + + const updateCheckout = (newCheckout: Cart) => { + setCheckout(newCheckout) + } + + // Because the config is an object, if the parent re-renders this provider + // will re-render every consumer unless we memoize the config + const cfg = useMemo( + () => ({ + client, + checkout, + shop, + updateCheckout: updateCheckout, + currencyCode: /*config.currencyCode ||*/ checkout?.currencyCode, + locale, + sessionToken, + }), + [client] + ) + + return {children} +} + +export function useCommerce() { + return useContext(Commerce) as T +} diff --git a/framework/shopify/product/get-all-product-paths.ts b/framework/shopify/product/get-all-product-paths.ts new file mode 100644 index 000000000..3d4f0ef7a --- /dev/null +++ b/framework/shopify/product/get-all-product-paths.ts @@ -0,0 +1,31 @@ +import Client from 'shopify-buy' +import { getConfig } from '../api' +import { Product } from '../types' +import toCommerceProducts from '../utils/to-commerce-products' + +type ReturnType = { + products: any[] +} + +const getAllProductPaths = async (): Promise => { + const config = getConfig() + + const client = Client.buildClient({ + storefrontAccessToken: config.apiToken, + domain: config.commerceUrl, + }) + + const res = (await client.product.fetchAll()) as Product[] + + const products = toCommerceProducts(res) + + return { + products: products.map((product) => { + return { + node: { ...product }, + } + }), + } +} + +export default getAllProductPaths diff --git a/framework/shopify/product/get-all-products.ts b/framework/shopify/product/get-all-products.ts new file mode 100644 index 000000000..6e4881e99 --- /dev/null +++ b/framework/shopify/product/get-all-products.ts @@ -0,0 +1,40 @@ +import Client from 'shopify-buy' +import { ShopifyConfig } from '../api' +import { Product } from '../types' +import toCommerceProducts from '../utils/to-commerce-products' + +export type ProductNode = Product + +type Variables = { + first?: number + field?: string +} + +type Options = { + variables: Variables + config: ShopifyConfig + preview?: boolean +} + +type ReturnType = { + products: any[] +} + +const getAllProducts = async (options: Options): Promise => { + const { config } = options + + const client = Client.buildClient({ + storefrontAccessToken: config.apiToken, + domain: config.commerceUrl, + }) + + const res = (await client.product.fetchAll()) as Product[] + + const products = toCommerceProducts(res) + + return { + products, + } +} + +export default getAllProducts diff --git a/framework/shopify/product/get-product.ts b/framework/shopify/product/get-product.ts new file mode 100644 index 000000000..f71aa0213 --- /dev/null +++ b/framework/shopify/product/get-product.ts @@ -0,0 +1,37 @@ +import Client from 'shopify-buy' +import { ShopifyConfig } from '../api' +import { Product } from '../types' +import toCommerceProducts from '../utils/to-commerce-products' + +export type ProductNode = Product + +type Variables = { + slug: string +} + +type Options = { + variables: Variables + config: ShopifyConfig + preview?: boolean +} + +type ReturnType = { + product: any +} + +const getProduct = async (options: Options): Promise => { + const { variables, config } = options + + const client = Client.buildClient({ + storefrontAccessToken: config.apiToken, + domain: config.commerceUrl, + }) + + const res = (await client.product.fetchByHandle(variables.slug)) as Product + + return { + product: toCommerceProducts([res])[0], + } +} + +export default getProduct diff --git a/framework/shopify/product/use-price.tsx b/framework/shopify/product/use-price.tsx new file mode 100644 index 000000000..a79940a76 --- /dev/null +++ b/framework/shopify/product/use-price.tsx @@ -0,0 +1,2 @@ +export * from '@commerce/use-price' +export { default } from '@commerce/use-price' diff --git a/framework/shopify/product/use-search.tsx b/framework/shopify/product/use-search.tsx new file mode 100644 index 000000000..a2c32c896 --- /dev/null +++ b/framework/shopify/product/use-search.tsx @@ -0,0 +1,41 @@ +import type { HookFetcher } from '@commerce/utils/types' +import type { SwrOptions } from '@commerce/utils/use-data' +import useCommerceSearch from '@commerce/products/use-search' +import { ProductEdge } from '../types' + +const defaultOpts = {} + +export type SearchProductsInput = { + search?: string + categoryId?: number + brandId?: number + sort?: string +} + +export type SearchProductsData = { + products: ProductEdge[] + found: boolean +} + +export const fetcher: HookFetcher = ( + options, + { search, categoryId, brandId, sort }, + fetch +) => { + return { found: false, products: [] } +} + +export function extendHook( + customFetcher: typeof fetcher, + swrOptions?: SwrOptions +) { + const useSearch = (input: SearchProductsInput = {}) => { + return {} + } + + useSearch.extend = extendHook + + return useSearch +} + +export default extendHook(fetcher) diff --git a/framework/shopify/types.ts b/framework/shopify/types.ts new file mode 100644 index 000000000..47bb94e62 --- /dev/null +++ b/framework/shopify/types.ts @@ -0,0 +1,130 @@ +import { + Product as BaseProduct, + ProductVariant as BaseProductVariant, + Cart as BaseCart, + CheckoutResource as BaseCheckoutResource, + AttributeInput, + Client as BaseClient, + Shop as BaseShop, + Image as BaseImage, +} from 'shopify-buy' + +export type SelectedOptions = { + id: string + name: string + value: string +} + +export type PresentmentPrice = { + price: PriceV2 +} + +export type ProductVariant = BaseProductVariant & { + selectedOptions: Array + presentmentPrices: Array +} + +// TODO +export type ProductOptions = { + node: { + __typename: string + displayName: string + values: { + edges: [ + { + node: { + label: string + id: string + } + } + ] + } + } +} + +// TODO +export type ProductEdge = { + node: Product +} + +export type Product = BaseProduct & { + handle: string + name: string + path: string + entityId: number + descriptionHtml: string + prices: { + price: { + value: number + currencyCode: string + } + retailPrice: { + value: number + currencyCode: string + } + } + images: { + edges: [{ node: { urlOriginal: string; altText: string } }] + } + productOptions: ProductOptions + variants: Array & { + edges: [ + { + node: { + productOptions: ProductOptions[] + entityId: number + } + } + ] + } +} + +export type PriceV2 = { + amount: number + currencyCode: string +} + +export type Cart = BaseCart & { + webUrl?: string + currencyCode?: string + lineItemsSubtotalPrice?: PriceV2 + totalPriceV2?: PriceV2 +} + +export type Shop = BaseShop & { + currencyCode?: string +} + +export type Create = { + presentmentCurrencyCode?: string +} + +export type CheckoutResource = BaseCheckoutResource & { + updateLineItems( + checkoutId: string | number, + lineItems: AttributeInput[] + ): Promise + + create: (input: Create) => Promise +} + +export type Client = BaseClient & { + checkout: CheckoutResource +} + +export type Page = { + id: string + title: string + name: string + handle: string + body: string + bodySummary: string + url: string + sort_order: number +} + +export type PageEdge = { + node: Page +} + +export type Image = BaseImage diff --git a/framework/shopify/utils/storage.ts b/framework/shopify/utils/storage.ts new file mode 100644 index 000000000..d46dadb21 --- /dev/null +++ b/framework/shopify/utils/storage.ts @@ -0,0 +1,13 @@ +export const getCheckoutIdFromStorage = (token: string) => { + if (window && window.sessionStorage) { + return window.sessionStorage.getItem(token) + } + + return null +} + +export const setCheckoutIdInStorage = (token: string, id: string | number) => { + if (window && window.sessionStorage) { + return window.sessionStorage.setItem(token, id + '') + } +} diff --git a/framework/shopify/utils/to-commerce-products.ts b/framework/shopify/utils/to-commerce-products.ts new file mode 100644 index 000000000..c0b411eb6 --- /dev/null +++ b/framework/shopify/utils/to-commerce-products.ts @@ -0,0 +1,60 @@ +import { Product, Image } from '../types' + +export default function toCommerceProducts(products: Product[]) { + return products.map((product: Product) => { + return { + id: product.id, + entityId: product.id, + name: product.title, + slug: product.handle, + title: product.title, + vendor: product.vendor, + description: product.descriptionHtml, + path: `/${product.handle}`, + price: { + value: +product.variants[0].price, + currencyCode: 'USD', // TODO + }, + images: product.images.map((image: Image) => { + return { + url: image.src, + } + }), + variants: product.variants.map((variant) => { + return { + id: variant.id, + options: variant.selectedOptions.map((selectedOption) => { + return { + __typename: 'MultipleChoiceOption', + displayName: selectedOption.name, + values: [ + { + node: { + id: variant.id, + label: selectedOption.value, + }, + }, + ], + } + }), + } + }), + productOptions: product.options.map((option) => { + return { + __typename: 'MultipleChoiceOption', + displayName: option.name, + values: option.values.map((value) => { + return { + node: { + entityId: 1, + label: value.value, + hexColors: [value.value], + }, + } + }), + } + }), + options: [], + } + }) +} diff --git a/framework/shopify/wishlist/use-add-item.tsx b/framework/shopify/wishlist/use-add-item.tsx new file mode 100644 index 000000000..75f067c3a --- /dev/null +++ b/framework/shopify/wishlist/use-add-item.tsx @@ -0,0 +1,13 @@ +import { useCallback } from 'react' + +export function emptyHook() { + const useEmptyHook = async (options = {}) => { + return useCallback(async function () { + return Promise.resolve() + }, []) + } + + return useEmptyHook +} + +export default emptyHook diff --git a/framework/shopify/wishlist/use-remove-item.tsx b/framework/shopify/wishlist/use-remove-item.tsx new file mode 100644 index 000000000..a2d3a8a05 --- /dev/null +++ b/framework/shopify/wishlist/use-remove-item.tsx @@ -0,0 +1,17 @@ +import { useCallback } from 'react' + +type Options = { + includeProducts?: boolean +} + +export function emptyHook(options?: Options) { + const useEmptyHook = async ({ id }: { id: string | number }) => { + return useCallback(async function () { + return Promise.resolve() + }, []) + } + + return useEmptyHook +} + +export default emptyHook diff --git a/framework/shopify/wishlist/use-wishlist.tsx b/framework/shopify/wishlist/use-wishlist.tsx new file mode 100644 index 000000000..2aac16810 --- /dev/null +++ b/framework/shopify/wishlist/use-wishlist.tsx @@ -0,0 +1,45 @@ +import { HookFetcher } from '@commerce/utils/types' +import { SwrOptions } from '@commerce/utils/use-data' +import useCommerceWishlist from '@commerce/wishlist/use-wishlist' +import { Product } from '../types' +import useCustomer from '../customer/use-customer' + +const defaultOpts = {} + +export type Wishlist = { + items: [ + { + product_id: number + variant_id: number + id: number + product: Product + } + ] +} + +export interface UseWishlistOptions { + includeProducts?: boolean +} + +export interface UseWishlistInput extends UseWishlistOptions { + customerId?: number +} + +export const fetcher: HookFetcher = () => { + return null +} + +export function extendHook( + customFetcher: typeof fetcher, + swrOptions?: SwrOptions +) { + const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => { + return { data: null } + } + + useWishlist.extend = extendHook + + return useWishlist +} + +export default extendHook(fetcher) diff --git a/next.config.js b/next.config.js index e732ef78a..3c9e37210 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,6 @@ module.exports = { images: { - domains: ['cdn11.bigcommerce.com'], + domains: ['cdn11.bigcommerce.com', 'cdn.shopify.com'], }, i18n: { locales: ['en-US', 'es'], From 4de9b906f4f15db74a792cd1fa743f56ea92767b Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 24 Feb 2021 19:32:03 -0300 Subject: [PATCH 4/4] typos --- framework/bigcommerce/config.json | 2 +- framework/shopify/api/index.ts | 2 +- framework/shopify/customer/use-customer.tsx | 2 +- framework/shopify/product/use-search.tsx | 2 +- package.json | 1 + yarn.lock | 5 +++++ 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/framework/bigcommerce/config.json b/framework/bigcommerce/config.json index 17ef37e25..a0e7afc5d 100644 --- a/framework/bigcommerce/config.json +++ b/framework/bigcommerce/config.json @@ -1,5 +1,5 @@ { "features": { - "wishlist": false + "wishlist": true } } diff --git a/framework/shopify/api/index.ts b/framework/shopify/api/index.ts index dcb0fc2ba..0402cfccc 100644 --- a/framework/shopify/api/index.ts +++ b/framework/shopify/api/index.ts @@ -3,7 +3,7 @@ import fetchGraphqlApi from './utils/fetch-graphql-api' export interface ShopifyConfig extends CommerceAPIConfig {} -// No I don't like this - will fix it later +// TODO(bc) const API_URL = process.env.SHOPIFY_STORE_DOMAIN || process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN diff --git a/framework/shopify/customer/use-customer.tsx b/framework/shopify/customer/use-customer.tsx index a909443ff..7ea2ae679 100644 --- a/framework/shopify/customer/use-customer.tsx +++ b/framework/shopify/customer/use-customer.tsx @@ -1,6 +1,6 @@ import type { HookFetcher } from '@commerce/utils/types' import type { SwrOptions } from '@commerce/utils/use-data' -import useCommerceCustomer from '@commerce/use-customer' +import useCommerceCustomer from '@commerce/customer/use-customer' const defaultOpts = {} diff --git a/framework/shopify/product/use-search.tsx b/framework/shopify/product/use-search.tsx index a2c32c896..04f6a3536 100644 --- a/framework/shopify/product/use-search.tsx +++ b/framework/shopify/product/use-search.tsx @@ -1,6 +1,6 @@ import type { HookFetcher } from '@commerce/utils/types' import type { SwrOptions } from '@commerce/utils/use-data' -import useCommerceSearch from '@commerce/products/use-search' +import useCommerceSearch from '@commerce/product/use-search' import { ProductEdge } from '../types' const defaultOpts = {} diff --git a/package.json b/package.json index 8a7d64e6a..85bd9c063 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "react-dom": "^17.0.1", "react-merge-refs": "^1.1.0", "react-ticker": "^1.2.2", + "shopify-buy": "^2.11.0", "swr": "^0.4.0", "tabbable": "^5.1.5", "tailwindcss": "^2.0.2" diff --git a/yarn.lock b/yarn.lock index 3497602b9..1255b9d62 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6226,6 +6226,11 @@ shell-quote@1.7.2: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== +shopify-buy@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/shopify-buy/-/shopify-buy-2.11.0.tgz#0f7cb52741395e4ae778c336f32ddf3fe67c2f35" + integrity sha512-bGjS1b/VCPvCjazSstlKwgLtK1WBotWom06/12loja8yfo/cWkLuJsakBbQe1uEIDiOLhKaR0M0CAXZFheYDug== + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"