mirror of
https://github.com/vercel/commerce.git
synced 2025-06-18 21:21:21 +00:00
Merge branch 'agnostic' of https://github.com/vercel/commerce into agnostic
This commit is contained in:
commit
33ec99c701
6
.prettierrc
Normal file
6
.prettierrc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false
|
||||||
|
}
|
@ -1,3 +1,7 @@
|
|||||||
{
|
{
|
||||||
"provider": "shopify"
|
"provider": "bigcommerce",
|
||||||
|
"features": {
|
||||||
|
"wishlist": true,
|
||||||
|
"customCheckout": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import cn from 'classnames'
|
import cn from 'classnames'
|
||||||
import { UserNav } from '@components/common'
|
import Link from 'next/link'
|
||||||
import { Button } from '@components/ui'
|
|
||||||
import { Bag, Cross, Check } from '@components/icons'
|
|
||||||
import { useUI } from '@components/ui/context'
|
|
||||||
import useCart from '@framework/cart/use-cart'
|
|
||||||
import usePrice from '@framework/product/use-price'
|
|
||||||
import CartItem from '../CartItem'
|
import CartItem from '../CartItem'
|
||||||
import s from './CartSidebarView.module.css'
|
import s from './CartSidebarView.module.css'
|
||||||
import { LineItem } from '@commerce/types'
|
import { Button } from '@components/ui'
|
||||||
|
import { UserNav } from '@components/common'
|
||||||
|
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'
|
||||||
|
|
||||||
const CartSidebarView: FC = () => {
|
const CartSidebarView: FC = () => {
|
||||||
const { closeSidebar } = useUI()
|
const { closeSidebar } = useUI()
|
||||||
@ -88,9 +88,14 @@ const CartSidebarView: FC = () => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="px-4 sm:px-6 flex-1">
|
<div className="px-4 sm:px-6 flex-1">
|
||||||
<h2 className="pt-1 pb-4 text-2xl leading-7 font-bold text-base tracking-wide">
|
<Link href="/cart">
|
||||||
My Cart
|
<h2
|
||||||
</h2>
|
className="pt-1 pb-4 text-2xl leading-7 font-bold text-base tracking-wide cursor-pointer inline-block"
|
||||||
|
onClick={handleClose}
|
||||||
|
>
|
||||||
|
My Cart
|
||||||
|
</h2>
|
||||||
|
</Link>
|
||||||
<ul className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accents-3 border-t border-accents-3">
|
<ul className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accents-3 border-t border-accents-3">
|
||||||
{data!.lineItems.map((item: any) => (
|
{data!.lineItems.map((item: any) => (
|
||||||
<CartItem
|
<CartItem
|
||||||
|
20
components/icons/CreditCard.tsx
Normal file
20
components/icons/CreditCard.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const CreditCard = ({ ...props }) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
fill="none"
|
||||||
|
shapeRendering="geometricPrecision"
|
||||||
|
>
|
||||||
|
<rect x="1" y="4" width="22" height="16" rx="2" ry="2" />
|
||||||
|
<path d="M1 10h22" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreditCard
|
20
components/icons/MapPin.tsx
Normal file
20
components/icons/MapPin.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const MapPin = ({ ...props }) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
fill="none"
|
||||||
|
shapeRendering="geometricPrecision"
|
||||||
|
>
|
||||||
|
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" />
|
||||||
|
<circle cx="12" cy="10" r="3" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapPin
|
@ -14,3 +14,5 @@ export { default as RightArrow } from './RightArrow'
|
|||||||
export { default as Info } from './Info'
|
export { default as Info } from './Info'
|
||||||
export { default as ChevronUp } from './ChevronUp'
|
export { default as ChevronUp } from './ChevronUp'
|
||||||
export { default as Vercel } from './Vercel'
|
export { default as Vercel } from './Vercel'
|
||||||
|
export { default as MapPin } from './MapPin'
|
||||||
|
export { default as CreditCard } from './CreditCard'
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.productDisplay {
|
.productDisplay {
|
||||||
@apply relative flex px-0 pb-0 relative box-border col-span-1 bg-violet;
|
@apply relative flex px-0 pb-0 box-border col-span-1 bg-violet;
|
||||||
min-height: 600px;
|
min-height: 600px;
|
||||||
|
|
||||||
@screen md {
|
@screen md {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
.root {
|
.root {
|
||||||
|
composes: root from 'components/ui/Button/Button.module.css';
|
||||||
@apply h-12 w-12 bg-primary text-primary rounded-full mr-3 inline-flex
|
@apply h-12 w-12 bg-primary text-primary rounded-full mr-3 inline-flex
|
||||||
items-center justify-center cursor-pointer transition duration-150 ease-in-out
|
items-center justify-center cursor-pointer transition duration-150 ease-in-out
|
||||||
p-0 shadow-none border-gray-200 border box-border;
|
p-0 shadow-none border-gray-200 border box-border;
|
||||||
|
@ -59,7 +59,12 @@ type Action =
|
|||||||
value: string
|
value: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MODAL_VIEWS = 'SIGNUP_VIEW' | 'LOGIN_VIEW' | 'FORGOT_VIEW'
|
type MODAL_VIEWS =
|
||||||
|
| 'SIGNUP_VIEW'
|
||||||
|
| 'LOGIN_VIEW'
|
||||||
|
| 'FORGOT_VIEW'
|
||||||
|
| 'NEW_SHIPPING_ADDRESS'
|
||||||
|
| 'NEW_PAYMENT_METHOD'
|
||||||
type ToastText = string
|
type ToastText = string
|
||||||
|
|
||||||
export const UIContext = React.createContext<State | any>(initialState)
|
export const UIContext = React.createContext<State | any>(initialState)
|
||||||
|
@ -30,7 +30,8 @@ const WishlistButton: FC<Props> = ({
|
|||||||
const itemInWishlist = data?.items?.find(
|
const itemInWishlist = data?.items?.find(
|
||||||
// @ts-ignore Wishlist is not always enabled
|
// @ts-ignore Wishlist is not always enabled
|
||||||
(item) =>
|
(item) =>
|
||||||
item.product_id === productId && (item.variant_id as any) === variant.id
|
item.product_id === Number(productId) &&
|
||||||
|
(item.variant_id as any) === Number(variant.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleWishlistChange = async (e: any) => {
|
const handleWishlistChange = async (e: any) => {
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import type { ItemBody as WishlistItemBody } from '../wishlist'
|
import type { ItemBody as WishlistItemBody } from '../wishlist'
|
||||||
import type { CartItemBody, OptionSelections } from '../../types'
|
import type { CartItemBody, OptionSelections } from '../../types'
|
||||||
|
|
||||||
|
type BCWishlistItemBody = {
|
||||||
|
product_id: number
|
||||||
|
variant_id: number
|
||||||
|
}
|
||||||
|
|
||||||
type BCCartItemBody = {
|
type BCCartItemBody = {
|
||||||
product_id: number
|
product_id: number
|
||||||
variant_id: number
|
variant_id: number
|
||||||
@ -8,9 +13,11 @@ type BCCartItemBody = {
|
|||||||
option_selections?: OptionSelections
|
option_selections?: OptionSelections
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseWishlistItem = (item: WishlistItemBody) => ({
|
export const parseWishlistItem = (
|
||||||
product_id: item.productId,
|
item: WishlistItemBody
|
||||||
variant_id: item.variantId,
|
): BCWishlistItemBody => ({
|
||||||
|
product_id: Number(item.productId),
|
||||||
|
variant_id: Number(item.variantId),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const parseCartItem = (item: CartItemBody): BCCartItemBody => ({
|
export const parseCartItem = (item: CartItemBody): BCCartItemBody => ({
|
||||||
|
@ -68,14 +68,15 @@ async function getCustomerWishlist({
|
|||||||
const productsById = graphqlData.products.reduce<{
|
const productsById = graphqlData.products.reduce<{
|
||||||
[k: number]: ProductEdge
|
[k: number]: ProductEdge
|
||||||
}>((prods, p) => {
|
}>((prods, p) => {
|
||||||
prods[Number(p.node.entityId)] = p as any
|
prods[Number(p.id)] = p as any
|
||||||
return prods
|
return prods
|
||||||
}, {})
|
}, {})
|
||||||
// Populate the wishlist items with the graphql products
|
// Populate the wishlist items with the graphql products
|
||||||
wishlist.items.forEach((item) => {
|
wishlist.items.forEach((item) => {
|
||||||
const product = item && productsById[item.product_id!]
|
const product = item && productsById[item.product_id!]
|
||||||
if (item && product) {
|
if (item && product) {
|
||||||
item.product = product.node
|
// @ts-ignore Fix this type when the wishlist type is properly defined
|
||||||
|
item.product = product
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ export const handler: SWRHook<
|
|||||||
url: '/api/bigcommerce/wishlist',
|
url: '/api/bigcommerce/wishlist',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
fetcher({ input: { customerId, includeProducts }, options, fetch }) {
|
async fetcher({ input: { customerId, includeProducts }, options, fetch }) {
|
||||||
if (!customerId) return null
|
if (!customerId) return null
|
||||||
|
|
||||||
// Use a dummy base as we only care about the relative path
|
// Use a dummy base as we only care about the relative path
|
||||||
@ -35,7 +35,7 @@ export const handler: SWRHook<
|
|||||||
const { data: customer } = useCustomer()
|
const { data: customer } = useCustomer()
|
||||||
const response = useData({
|
const response = useData({
|
||||||
input: [
|
input: [
|
||||||
['customerId', (customer as any)?.id],
|
['customerId', customer?.entityId],
|
||||||
['includeProducts', input?.includeProducts],
|
['includeProducts', input?.includeProducts],
|
||||||
],
|
],
|
||||||
swrOptions: {
|
swrOptions: {
|
||||||
|
@ -5,10 +5,10 @@ import {
|
|||||||
API_TOKEN,
|
API_TOKEN,
|
||||||
SHOPIFY_CHECKOUT_ID_COOKIE,
|
SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||||
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
|
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
|
||||||
|
SHOPIFY_COOKIE_EXPIRE,
|
||||||
} from '../const'
|
} from '../const'
|
||||||
|
|
||||||
if (!API_URL) {
|
if (!API_URL) {
|
||||||
console.log(process.env)
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The environment variable NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN is missing and it's required to access your store`
|
`The environment variable NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN is missing and it's required to access your store`
|
||||||
)
|
)
|
||||||
@ -44,10 +44,11 @@ export class Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const config = new Config({
|
const config = new Config({
|
||||||
|
locale: 'en-US',
|
||||||
commerceUrl: API_URL,
|
commerceUrl: API_URL,
|
||||||
apiToken: API_TOKEN!,
|
apiToken: API_TOKEN!,
|
||||||
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
|
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||||
cartCookieMaxAge: 60 * 60 * 24 * 30,
|
cartCookieMaxAge: SHOPIFY_COOKIE_EXPIRE,
|
||||||
fetch: fetchGraphqlApi,
|
fetch: fetchGraphqlApi,
|
||||||
customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE,
|
customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE,
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
SHOPIFY_CHECKOUT_ID_COOKIE,
|
SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||||
SHOPIFY_CHECKOUT_URL_COOKIE,
|
SHOPIFY_CHECKOUT_URL_COOKIE,
|
||||||
|
SHOPIFY_COOKIE_EXPIRE,
|
||||||
} from '../../const'
|
} from '../../const'
|
||||||
|
|
||||||
import checkoutCreateMutation from '../../utils/mutations/checkout-create'
|
import checkoutCreateMutation from '../../utils/mutations/checkout-create'
|
||||||
@ -15,8 +16,11 @@ export const checkoutCreate = async (fetch: any) => {
|
|||||||
const checkoutId = checkout?.id
|
const checkoutId = checkout?.id
|
||||||
|
|
||||||
if (checkoutId) {
|
if (checkoutId) {
|
||||||
Cookies.set(SHOPIFY_CHECKOUT_ID_COOKIE, checkoutId)
|
const options = {
|
||||||
Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout?.webUrl)
|
expires: SHOPIFY_COOKIE_EXPIRE,
|
||||||
|
}
|
||||||
|
Cookies.set(SHOPIFY_CHECKOUT_ID_COOKIE, checkoutId, options)
|
||||||
|
Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout?.webUrl, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkout
|
return checkout
|
||||||
|
@ -25,12 +25,13 @@ const getAllPages = async (options?: {
|
|||||||
}): Promise<ReturnType> => {
|
}): Promise<ReturnType> => {
|
||||||
let { config, variables = { first: 250 } } = options ?? {}
|
let { config, variables = { first: 250 } } = options ?? {}
|
||||||
config = getConfig(config)
|
config = getConfig(config)
|
||||||
|
const { locale } = config
|
||||||
const { data } = await config.fetch(getAllPagesQuery, { variables })
|
const { data } = await config.fetch(getAllPagesQuery, { variables })
|
||||||
|
|
||||||
const pages = data.pages?.edges?.map(
|
const pages = data.pages?.edges?.map(
|
||||||
({ node: { title: name, handle, ...node } }: PageEdge) => ({
|
({ node: { title: name, handle, ...node } }: PageEdge) => ({
|
||||||
...node,
|
...node,
|
||||||
url: `/${handle}`,
|
url: `/${locale}/${handle}`,
|
||||||
name,
|
name,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -3,33 +3,32 @@ import getPageQuery from '../utils/queries/get-page-query'
|
|||||||
import { Page } from './get-all-pages'
|
import { Page } from './get-all-pages'
|
||||||
|
|
||||||
type Variables = {
|
type Variables = {
|
||||||
slug: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReturnType = {
|
export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
|
||||||
page: Page
|
|
||||||
}
|
|
||||||
|
|
||||||
const getPage = async (options: {
|
const getPage = async (options: {
|
||||||
variables: Variables
|
variables: Variables
|
||||||
config: ShopifyConfig
|
config: ShopifyConfig
|
||||||
preview?: boolean
|
preview?: boolean
|
||||||
}): Promise<ReturnType> => {
|
}): Promise<GetPageResult> => {
|
||||||
let { config, variables } = options ?? {}
|
let { config, variables } = options ?? {}
|
||||||
|
|
||||||
config = getConfig(config)
|
config = getConfig(config)
|
||||||
|
const { locale } = config
|
||||||
|
|
||||||
const { data } = await config.fetch(getPageQuery, {
|
const { data } = await config.fetch(getPageQuery, {
|
||||||
variables,
|
variables,
|
||||||
})
|
})
|
||||||
|
const page = data.node
|
||||||
const { pageByHandle: page } = data
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
page: page
|
page: page
|
||||||
? {
|
? {
|
||||||
...page,
|
...page,
|
||||||
name: page.title,
|
name: page.title,
|
||||||
url: page?.handle,
|
url: `/${locale}/${page.handle}`,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ export const SHOPIFY_CUSTOMER_TOKEN_COOKIE = 'shopify_customerToken'
|
|||||||
|
|
||||||
export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN
|
export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN
|
||||||
|
|
||||||
|
export const SHOPIFY_COOKIE_EXPIRE = 30
|
||||||
|
|
||||||
export const API_URL = `https://${STORE_DOMAIN}/api/2021-01/graphql.json`
|
export const API_URL = `https://${STORE_DOMAIN}/api/2021-01/graphql.json`
|
||||||
|
|
||||||
export const API_TOKEN = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN
|
export const API_TOKEN = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN
|
||||||
|
@ -4,6 +4,7 @@ import useSearch, { UseSearch } from '@commerce/product/use-search'
|
|||||||
import { ProductEdge } from '../schema'
|
import { ProductEdge } from '../schema'
|
||||||
import {
|
import {
|
||||||
getAllProductsQuery,
|
getAllProductsQuery,
|
||||||
|
getCollectionProductsQuery,
|
||||||
getSearchVariables,
|
getSearchVariables,
|
||||||
normalizeProduct,
|
normalizeProduct,
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
@ -14,8 +15,8 @@ export default useSearch as UseSearch<typeof handler>
|
|||||||
|
|
||||||
export type SearchProductsInput = {
|
export type SearchProductsInput = {
|
||||||
search?: string
|
search?: string
|
||||||
categoryId?: number
|
categoryId?: string
|
||||||
brandId?: number
|
brandId?: string
|
||||||
sort?: string
|
sort?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ export type SearchProductsData = {
|
|||||||
products: Product[]
|
products: Product[]
|
||||||
found: boolean
|
found: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handler: SWRHook<
|
export const handler: SWRHook<
|
||||||
SearchProductsData,
|
SearchProductsData,
|
||||||
SearchProductsInput,
|
SearchProductsInput,
|
||||||
@ -32,18 +34,30 @@ export const handler: SWRHook<
|
|||||||
query: getAllProductsQuery,
|
query: getAllProductsQuery,
|
||||||
},
|
},
|
||||||
async fetcher({ input, options, fetch }) {
|
async fetcher({ input, options, fetch }) {
|
||||||
const resp = await fetch({
|
const { categoryId, brandId } = input
|
||||||
query: options?.query,
|
|
||||||
|
const data = await fetch({
|
||||||
|
query: categoryId ? getCollectionProductsQuery : options.query,
|
||||||
method: options?.method,
|
method: options?.method,
|
||||||
variables: getSearchVariables(input),
|
variables: getSearchVariables(input),
|
||||||
})
|
})
|
||||||
const edges = resp.products?.edges
|
|
||||||
|
let edges
|
||||||
|
|
||||||
|
if (categoryId) {
|
||||||
|
edges = data.node?.products?.edges ?? []
|
||||||
|
if (brandId) {
|
||||||
|
edges = edges.filter(
|
||||||
|
({ node: { vendor } }: ProductEdge) => vendor === brandId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
edges = data.products?.edges ?? []
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
products: edges?.map(({ node: p }: ProductEdge) =>
|
products: edges.map(({ node }: ProductEdge) => normalizeProduct(node)),
|
||||||
// TODO: Fix this product type
|
found: !!edges.length,
|
||||||
normalizeProduct(p as any)
|
|
||||||
),
|
|
||||||
found: !!edges?.length,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) => (input = {}) => {
|
useHook: ({ useData }) => (input = {}) => {
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
import Cookies from 'js-cookie'
|
import Cookies, { CookieAttributes } from 'js-cookie'
|
||||||
import { SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '../const'
|
import { SHOPIFY_COOKIE_EXPIRE, SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '../const'
|
||||||
|
|
||||||
export const getCustomerToken = () => Cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE)
|
export const getCustomerToken = () => Cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE)
|
||||||
|
|
||||||
export const setCustomerToken = (token: string | null, options?: any) => {
|
export const setCustomerToken = (
|
||||||
|
token: string | null,
|
||||||
|
options?: CookieAttributes
|
||||||
|
) => {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
Cookies.remove(SHOPIFY_CUSTOMER_TOKEN_COOKIE)
|
Cookies.remove(SHOPIFY_CUSTOMER_TOKEN_COOKIE)
|
||||||
} else {
|
} else {
|
||||||
Cookies.set(SHOPIFY_CUSTOMER_TOKEN_COOKIE, token, options)
|
Cookies.set(
|
||||||
|
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
|
||||||
|
token,
|
||||||
|
options ?? {
|
||||||
|
expires: SHOPIFY_COOKIE_EXPIRE,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@ const getCategories = async (config: ShopifyConfig): Promise<Category[]> => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
data.collections?.edges?.map(
|
data.collections?.edges?.map(
|
||||||
({ node: { title: name, handle } }: CollectionEdge) => ({
|
({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({
|
||||||
entityId: handle,
|
entityId,
|
||||||
name,
|
name,
|
||||||
path: `/${handle}`,
|
path: `/${handle}`,
|
||||||
})
|
})
|
||||||
|
@ -2,9 +2,9 @@ import getSortVariables from './get-sort-variables'
|
|||||||
import type { SearchProductsInput } from '../product/use-search'
|
import type { SearchProductsInput } from '../product/use-search'
|
||||||
|
|
||||||
export const getSearchVariables = ({
|
export const getSearchVariables = ({
|
||||||
categoryId,
|
|
||||||
brandId,
|
brandId,
|
||||||
search,
|
search,
|
||||||
|
categoryId,
|
||||||
sort,
|
sort,
|
||||||
}: SearchProductsInput) => {
|
}: SearchProductsInput) => {
|
||||||
let query = ''
|
let query = ''
|
||||||
@ -13,17 +13,14 @@ export const getSearchVariables = ({
|
|||||||
query += `product_type:${search} OR title:${search} OR tag:${search}`
|
query += `product_type:${search} OR title:${search} OR tag:${search}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (categoryId) {
|
|
||||||
query += `tag:${categoryId}`
|
|
||||||
}
|
|
||||||
|
|
||||||
if (brandId) {
|
if (brandId) {
|
||||||
query += `${categoryId ? ' AND ' : ''}vendor:${brandId}`
|
query += `${search ? ' AND ' : ''}vendor:${brandId}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
categoryId,
|
||||||
query,
|
query,
|
||||||
...getSortVariables(sort),
|
...getSortVariables(sort, !!categoryId),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const getSortVariables = (sort?: string) => {
|
const getSortVariables = (sort?: string, isCategory = false) => {
|
||||||
let output = {}
|
let output = {}
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case 'price-asc':
|
case 'price-asc':
|
||||||
@ -21,7 +21,7 @@ const getSortVariables = (sort?: string) => {
|
|||||||
break
|
break
|
||||||
case 'latest-desc':
|
case 'latest-desc':
|
||||||
output = {
|
output = {
|
||||||
sortKey: 'CREATED_AT',
|
sortKey: isCategory ? 'CREATED' : 'CREATED_AT',
|
||||||
reverse: true,
|
reverse: true,
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { Product } from '@commerce/types'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Product as ShopifyProduct,
|
Product as ShopifyProduct,
|
||||||
Checkout,
|
Checkout,
|
||||||
@ -5,8 +7,8 @@ import {
|
|||||||
SelectedOption,
|
SelectedOption,
|
||||||
ImageConnection,
|
ImageConnection,
|
||||||
ProductVariantConnection,
|
ProductVariantConnection,
|
||||||
ProductOption,
|
|
||||||
MoneyV2,
|
MoneyV2,
|
||||||
|
ProductOption,
|
||||||
} from '../schema'
|
} from '../schema'
|
||||||
|
|
||||||
import type { Cart, LineItem } from '../types'
|
import type { Cart, LineItem } from '../types'
|
||||||
@ -19,18 +21,26 @@ const money = ({ amount, currencyCode }: MoneyV2) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const normalizeProductOption = ({
|
const normalizeProductOption = ({
|
||||||
|
id,
|
||||||
name: displayName,
|
name: displayName,
|
||||||
values,
|
values,
|
||||||
...rest
|
|
||||||
}: ProductOption) => {
|
}: ProductOption) => {
|
||||||
return {
|
return {
|
||||||
__typename: 'MultipleChoiceOption',
|
__typename: 'MultipleChoiceOption',
|
||||||
|
id,
|
||||||
displayName,
|
displayName,
|
||||||
values: values.map((value) => ({
|
values: values.map((value) => {
|
||||||
label: value,
|
let output: any = {
|
||||||
hexColors: displayName === 'Color' ? [value] : null,
|
label: value,
|
||||||
})),
|
}
|
||||||
...rest,
|
if (displayName === 'Color') {
|
||||||
|
output = {
|
||||||
|
...output,
|
||||||
|
hexColors: [value],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,19 +51,28 @@ const normalizeProductImages = ({ edges }: ImageConnection) =>
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const normalizeProductVariants = ({ edges }: ProductVariantConnection) => {
|
const normalizeProductVariants = ({ edges }: ProductVariantConnection) => {
|
||||||
return edges?.map(({ node: { id, selectedOptions } }) => ({
|
return edges?.map(
|
||||||
id,
|
({
|
||||||
options: selectedOptions.map(({ name, value }: SelectedOption) =>
|
node: { id, selectedOptions, sku, title, priceV2, compareAtPriceV2 },
|
||||||
normalizeProductOption({
|
}) => ({
|
||||||
id,
|
id,
|
||||||
name,
|
name: title,
|
||||||
values: [value],
|
sku: sku ?? id,
|
||||||
})
|
price: +priceV2.amount,
|
||||||
),
|
listPrice: +compareAtPriceV2?.amount,
|
||||||
}))
|
requiresShipping: true,
|
||||||
|
options: selectedOptions.map(({ name, value }: SelectedOption) =>
|
||||||
|
normalizeProductOption({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
values: [value],
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeProduct(productNode: ShopifyProduct): any {
|
export function normalizeProduct(productNode: ShopifyProduct): Product {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
title: name,
|
title: name,
|
||||||
@ -95,8 +114,8 @@ export function normalizeCart(checkout: Checkout): Cart {
|
|||||||
},
|
},
|
||||||
taxesIncluded: checkout.taxesIncluded,
|
taxesIncluded: checkout.taxesIncluded,
|
||||||
lineItems: checkout.lineItems?.edges.map(normalizeLineItem),
|
lineItems: checkout.lineItems?.edges.map(normalizeLineItem),
|
||||||
lineItemsSubtotalPrice: checkout.subtotalPriceV2?.amount,
|
lineItemsSubtotalPrice: +checkout.subtotalPriceV2?.amount,
|
||||||
subtotalPrice: checkout.subtotalPriceV2?.amount,
|
subtotalPrice: +checkout.subtotalPriceV2?.amount,
|
||||||
totalPrice: checkout.totalPriceV2?.amount,
|
totalPrice: checkout.totalPriceV2?.amount,
|
||||||
discounts: [],
|
discounts: [],
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,38 @@
|
|||||||
|
export const productConnection = `
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
hasPreviousPage
|
||||||
|
}
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
vendor
|
||||||
|
handle
|
||||||
|
description
|
||||||
|
priceRange {
|
||||||
|
minVariantPrice {
|
||||||
|
amount
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
images(first: 1) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
hasPreviousPage
|
||||||
|
}
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
originalSrc
|
||||||
|
altText
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
export const productsFragment = `
|
export const productsFragment = `
|
||||||
products(
|
products(
|
||||||
first: $first
|
first: $first
|
||||||
@ -5,39 +40,7 @@ products(
|
|||||||
reverse: $reverse
|
reverse: $reverse
|
||||||
query: $query
|
query: $query
|
||||||
) {
|
) {
|
||||||
pageInfo {
|
${productConnection}
|
||||||
hasNextPage
|
|
||||||
hasPreviousPage
|
|
||||||
}
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
vendor
|
|
||||||
handle
|
|
||||||
description
|
|
||||||
priceRange {
|
|
||||||
minVariantPrice {
|
|
||||||
amount
|
|
||||||
currencyCode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
images(first: 1) {
|
|
||||||
pageInfo {
|
|
||||||
hasNextPage
|
|
||||||
hasPreviousPage
|
|
||||||
}
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
originalSrc
|
|
||||||
altText
|
|
||||||
width
|
|
||||||
height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
import { productsFragment } from './get-all-products-query'
|
import { productConnection } from './get-all-products-query'
|
||||||
|
|
||||||
const getCollectionProductsQuery = /* GraphQL */ `
|
const getCollectionProductsQuery = /* GraphQL */ `
|
||||||
query getProductsFromCollection(
|
query getProductsFromCollection(
|
||||||
$categoryHandle: String!
|
$categoryId: ID!
|
||||||
$first: Int = 250
|
$first: Int = 250
|
||||||
$query: String = ""
|
$sortKey: ProductCollectionSortKeys = RELEVANCE
|
||||||
$sortKey: ProductSortKeys = RELEVANCE
|
|
||||||
$reverse: Boolean = false
|
$reverse: Boolean = false
|
||||||
) {
|
) {
|
||||||
collectionByHandle(handle: $categoryHandle)
|
node(id: $categoryId) {
|
||||||
{
|
id
|
||||||
${productsFragment}
|
... on Collection {
|
||||||
|
products(
|
||||||
|
first: $first
|
||||||
|
sortKey: $sortKey
|
||||||
|
reverse: $reverse
|
||||||
|
) {
|
||||||
|
${productConnection}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
export const getPageQuery = /* GraphQL */ `
|
export const getPageQuery = /* GraphQL */ `
|
||||||
query getPageBySlug($slug: String!) {
|
query($id: ID!) {
|
||||||
pageByHandle(handle: $slug) {
|
node(id: $id) {
|
||||||
id
|
id
|
||||||
title
|
... on Page {
|
||||||
handle
|
title
|
||||||
body
|
handle
|
||||||
bodySummary
|
body
|
||||||
url
|
bodySummary
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -32,6 +32,7 @@ const getProductQuery = /* GraphQL */ `
|
|||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
|
sku
|
||||||
selectedOptions {
|
selectedOptions {
|
||||||
name
|
name
|
||||||
value
|
value
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
// TODO: Fix the types in this file
|
|
||||||
// import { Product, Image } from '../types'
|
|
||||||
|
|
||||||
type Product = any
|
|
||||||
type Image = any
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
// TODO: Fix the variant type
|
|
||||||
variants: product.variants.map((variant: any) => {
|
|
||||||
return {
|
|
||||||
id: variant.id,
|
|
||||||
// TODO: Fix the selectedOption type
|
|
||||||
options: variant.selectedOptions.map((selectedOption: any) => {
|
|
||||||
return {
|
|
||||||
__typename: 'MultipleChoiceOption',
|
|
||||||
displayName: selectedOption.name,
|
|
||||||
values: [
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
id: variant.id,
|
|
||||||
label: selectedOption.value,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
// TODO: Fix the option type
|
|
||||||
productOptions: product.options.map((option: any) => {
|
|
||||||
return {
|
|
||||||
__typename: 'MultipleChoiceOption',
|
|
||||||
displayName: option.name,
|
|
||||||
// TODO: Fix the value type
|
|
||||||
values: option.values.map((value: any) => {
|
|
||||||
return {
|
|
||||||
node: {
|
|
||||||
entityId: 1,
|
|
||||||
label: value.value,
|
|
||||||
hexColors: [value.value],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
options: [],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -2,9 +2,7 @@
|
|||||||
// Shopify doesn't have a wishlist
|
// Shopify doesn't have a wishlist
|
||||||
|
|
||||||
import { HookFetcher } from '@commerce/utils/types'
|
import { HookFetcher } from '@commerce/utils/types'
|
||||||
import useCommerceWishlist from '@commerce/wishlist/use-wishlist'
|
|
||||||
import { Product } from '../schema'
|
import { Product } from '../schema'
|
||||||
import useCustomer from '../customer/use-customer'
|
|
||||||
|
|
||||||
const defaultOpts = {}
|
const defaultOpts = {}
|
||||||
|
|
||||||
|
155
lib/colors.ts
155
lib/colors.ts
@ -42,9 +42,160 @@ function hexToRgb(hex: string = '') {
|
|||||||
return [r, g, b]
|
return [r, g, b]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isDark(color = '') {
|
const colorMap: Record<string, string> = {
|
||||||
|
aliceblue: '#F0F8FF',
|
||||||
|
antiquewhite: '#FAEBD7',
|
||||||
|
aqua: '#00FFFF',
|
||||||
|
aquamarine: '#7FFFD4',
|
||||||
|
azure: '#F0FFFF',
|
||||||
|
beige: '#F5F5DC',
|
||||||
|
bisque: '#FFE4C4',
|
||||||
|
black: '#000000',
|
||||||
|
blanchedalmond: '#FFEBCD',
|
||||||
|
blue: '#0000FF',
|
||||||
|
blueviolet: '#8A2BE2',
|
||||||
|
brown: '#A52A2A',
|
||||||
|
burlywood: '#DEB887',
|
||||||
|
cadetblue: '#5F9EA0',
|
||||||
|
chartreuse: '#7FFF00',
|
||||||
|
chocolate: '#D2691E',
|
||||||
|
coral: '#FF7F50',
|
||||||
|
cornflowerblue: '#6495ED',
|
||||||
|
cornsilk: '#FFF8DC',
|
||||||
|
crimson: '#DC143C',
|
||||||
|
cyan: '#00FFFF',
|
||||||
|
darkblue: '#00008B',
|
||||||
|
darkcyan: '#008B8B',
|
||||||
|
darkgoldenrod: '#B8860B',
|
||||||
|
darkgray: '#A9A9A9',
|
||||||
|
darkgreen: '#006400',
|
||||||
|
darkgrey: '#A9A9A9',
|
||||||
|
darkkhaki: '#BDB76B',
|
||||||
|
darkmagenta: '#8B008B',
|
||||||
|
darkolivegreen: '#556B2F',
|
||||||
|
darkorange: '#FF8C00',
|
||||||
|
darkorchid: '#9932CC',
|
||||||
|
darkred: '#8B0000',
|
||||||
|
darksalmon: '#E9967A',
|
||||||
|
darkseagreen: '#8FBC8F',
|
||||||
|
darkslateblue: '#483D8B',
|
||||||
|
darkslategray: '#2F4F4F',
|
||||||
|
darkslategrey: '#2F4F4F',
|
||||||
|
darkturquoise: '#00CED1',
|
||||||
|
darkviolet: '#9400D3',
|
||||||
|
deeppink: '#FF1493',
|
||||||
|
deepskyblue: '#00BFFF',
|
||||||
|
dimgray: '#696969',
|
||||||
|
dimgrey: '#696969',
|
||||||
|
dodgerblue: '#1E90FF',
|
||||||
|
firebrick: '#B22222',
|
||||||
|
floralwhite: '#FFFAF0',
|
||||||
|
forestgreen: '#228B22',
|
||||||
|
fuchsia: '#FF00FF',
|
||||||
|
gainsboro: '#DCDCDC',
|
||||||
|
ghostwhite: '#F8F8FF',
|
||||||
|
gold: '#FFD700',
|
||||||
|
goldenrod: '#DAA520',
|
||||||
|
gray: '#808080',
|
||||||
|
green: '#008000',
|
||||||
|
greenyellow: '#ADFF2F',
|
||||||
|
grey: '#808080',
|
||||||
|
honeydew: '#F0FFF0',
|
||||||
|
hotpink: '#FF69B4',
|
||||||
|
indianred: '#CD5C5C',
|
||||||
|
indigo: '#4B0082',
|
||||||
|
ivory: '#FFFFF0',
|
||||||
|
khaki: '#F0E68C',
|
||||||
|
lavender: '#E6E6FA',
|
||||||
|
lavenderblush: '#FFF0F5',
|
||||||
|
lawngreen: '#7CFC00',
|
||||||
|
lemonchiffon: '#FFFACD',
|
||||||
|
lightblue: '#ADD8E6',
|
||||||
|
lightcoral: '#F08080',
|
||||||
|
lightcyan: '#E0FFFF',
|
||||||
|
lightgoldenrodyellow: '#FAFAD2',
|
||||||
|
lightgray: '#D3D3D3',
|
||||||
|
lightgreen: '#90EE90',
|
||||||
|
lightgrey: '#D3D3D3',
|
||||||
|
lightpink: '#FFB6C1',
|
||||||
|
lightsalmon: '#FFA07A',
|
||||||
|
lightseagreen: '#20B2AA',
|
||||||
|
lightskyblue: '#87CEFA',
|
||||||
|
lightslategray: '#778899',
|
||||||
|
lightslategrey: '#778899',
|
||||||
|
lightsteelblue: '#B0C4DE',
|
||||||
|
lightyellow: '#FFFFE0',
|
||||||
|
lime: '#00FF00',
|
||||||
|
limegreen: '#32CD32',
|
||||||
|
linen: '#FAF0E6',
|
||||||
|
magenta: '#FF00FF',
|
||||||
|
maroon: '#800000',
|
||||||
|
mediumaquamarine: '#66CDAA',
|
||||||
|
mediumblue: '#0000CD',
|
||||||
|
mediumorchid: '#BA55D3',
|
||||||
|
mediumpurple: '#9370DB',
|
||||||
|
mediumseagreen: '#3CB371',
|
||||||
|
mediumslateblue: '#7B68EE',
|
||||||
|
mediumspringgreen: '#00FA9A',
|
||||||
|
mediumturquoise: '#48D1CC',
|
||||||
|
mediumvioletred: '#C71585',
|
||||||
|
midnightblue: '#191970',
|
||||||
|
mintcream: '#F5FFFA',
|
||||||
|
mistyrose: '#FFE4E1',
|
||||||
|
moccasin: '#FFE4B5',
|
||||||
|
navajowhite: '#FFDEAD',
|
||||||
|
navy: '#000080',
|
||||||
|
oldlace: '#FDF5E6',
|
||||||
|
olive: '#808000',
|
||||||
|
olivedrab: '#6B8E23',
|
||||||
|
orange: '#FFA500',
|
||||||
|
orangered: '#FF4500',
|
||||||
|
orchid: '#DA70D6',
|
||||||
|
palegoldenrod: '#EEE8AA',
|
||||||
|
palegreen: '#98FB98',
|
||||||
|
paleturquoise: '#AFEEEE',
|
||||||
|
palevioletred: '#DB7093',
|
||||||
|
papayawhip: '#FFEFD5',
|
||||||
|
peachpuff: '#FFDAB9',
|
||||||
|
peru: '#CD853F',
|
||||||
|
pink: '#FFC0CB',
|
||||||
|
plum: '#DDA0DD',
|
||||||
|
powderblue: '#B0E0E6',
|
||||||
|
purple: '#800080',
|
||||||
|
rebeccapurple: '#663399',
|
||||||
|
red: '#FF0000',
|
||||||
|
rosybrown: '#BC8F8F',
|
||||||
|
royalblue: '#4169E1',
|
||||||
|
saddlebrown: '#8B4513',
|
||||||
|
salmon: '#FA8072',
|
||||||
|
sandybrown: '#F4A460',
|
||||||
|
seagreen: '#2E8B57',
|
||||||
|
seashell: '#FFF5EE',
|
||||||
|
sienna: '#A0522D',
|
||||||
|
silver: '#C0C0C0',
|
||||||
|
skyblue: '#87CEEB',
|
||||||
|
slateblue: '#6A5ACD',
|
||||||
|
slategray: '#708090',
|
||||||
|
slategrey: '#708090',
|
||||||
|
snow: '#FFFAFA',
|
||||||
|
springgreen: '#00FF7F',
|
||||||
|
steelblue: '#4682B4',
|
||||||
|
tan: '#D2B48C',
|
||||||
|
teal: '#008080',
|
||||||
|
thistle: '#D8BFD8',
|
||||||
|
tomato: '#FF6347',
|
||||||
|
turquoise: '#40E0D0',
|
||||||
|
violet: '#EE82EE',
|
||||||
|
wheat: '#F5DEB3',
|
||||||
|
white: '#FFFFFF',
|
||||||
|
whitesmoke: '#F5F5F5',
|
||||||
|
yellow: '#FFFF00',
|
||||||
|
yellowgreen: '#9ACD32',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDark(color: string = ''): boolean {
|
||||||
// Equation from http://24ways.org/2010/calculating-color-contrast
|
// Equation from http://24ways.org/2010/calculating-color-contrast
|
||||||
const rgb = hexToRgb(color)
|
let rgb = colorMap[color] ? hexToRgb(colorMap[color]) : hexToRgb(color)
|
||||||
const res = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000
|
const res = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000
|
||||||
return res < 128
|
return res < 128
|
||||||
}
|
}
|
||||||
|
14
package.json
14
package.json
@ -8,22 +8,18 @@
|
|||||||
"analyze": "BUNDLE_ANALYZE=both yarn build",
|
"analyze": "BUNDLE_ANALYZE=both yarn build",
|
||||||
"prettier-fix": "prettier --write .",
|
"prettier-fix": "prettier --write .",
|
||||||
"find:unused": "next-unused",
|
"find:unused": "next-unused",
|
||||||
"commerce": "node scripts/commerce.js",
|
|
||||||
"generate": "graphql-codegen",
|
"generate": "graphql-codegen",
|
||||||
"generate:definitions": "node framework/bigcommerce/scripts/generate-definitions.js"
|
"generate:definitions": "node framework/bigcommerce/scripts/generate-definitions.js"
|
||||||
},
|
},
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "12.x"
|
"node": "14.x"
|
||||||
},
|
|
||||||
"prettier": {
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": true
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reach/portal": "^0.11.2",
|
"@reach/portal": "^0.11.2",
|
||||||
"@vercel/fetch": "^6.1.0",
|
"@vercel/fetch": "^6.1.0",
|
||||||
|
"autoprefixer": "^10.2.4",
|
||||||
"body-scroll-lock": "^3.1.5",
|
"body-scroll-lock": "^3.1.5",
|
||||||
"bowser": "^2.11.0",
|
"bowser": "^2.11.0",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
@ -39,7 +35,7 @@
|
|||||||
"next": "^10.0.7",
|
"next": "^10.0.7",
|
||||||
"next-seo": "^4.11.0",
|
"next-seo": "^4.11.0",
|
||||||
"next-themes": "^0.0.4",
|
"next-themes": "^0.0.4",
|
||||||
"postcss": "^8.2.4",
|
"postcss": "^8.2.6",
|
||||||
"postcss-nesting": "^7.0.1",
|
"postcss-nesting": "^7.0.1",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
@ -48,7 +44,7 @@
|
|||||||
"shopify-buy": "^2.11.0",
|
"shopify-buy": "^2.11.0",
|
||||||
"swr": "^0.4.0",
|
"swr": "^0.4.0",
|
||||||
"tabbable": "^5.1.5",
|
"tabbable": "^5.1.5",
|
||||||
"tailwindcss": "^2.0.2"
|
"tailwindcss": "^2.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@graphql-codegen/cli": "^1.20.0",
|
"@graphql-codegen/cli": "^1.20.0",
|
||||||
@ -74,7 +70,7 @@
|
|||||||
"next-unused": "^0.0.3",
|
"next-unused": "^0.0.3",
|
||||||
"postcss-flexbugs-fixes": "^4.2.1",
|
"postcss-flexbugs-fixes": "^4.2.1",
|
||||||
"postcss-preset-env": "^6.7.0",
|
"postcss-preset-env": "^6.7.0",
|
||||||
"prettier": "^2.1.2",
|
"prettier": "^2.2.1",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
@ -5,7 +5,7 @@ import useCart from '@framework/cart/use-cart'
|
|||||||
import usePrice from '@framework/product/use-price'
|
import usePrice from '@framework/product/use-price'
|
||||||
import { Layout } from '@components/common'
|
import { Layout } from '@components/common'
|
||||||
import { Button, Text } from '@components/ui'
|
import { Button, Text } from '@components/ui'
|
||||||
import { Bag, Cross, Check } from '@components/icons'
|
import { Bag, Cross, Check, MapPin, CreditCard } from '@components/icons'
|
||||||
import { CartItem } from '@components/cart'
|
import { CartItem } from '@components/cart'
|
||||||
|
|
||||||
export async function getStaticProps({
|
export async function getStaticProps({
|
||||||
@ -38,7 +38,7 @@ export default function Cart() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid lg:grid-cols-12">
|
<div className="grid lg:grid-cols-12 w-full max-w-7xl mx-auto">
|
||||||
<div className="lg:col-span-8">
|
<div className="lg:col-span-8">
|
||||||
{isLoading || isEmpty ? (
|
{isLoading || isEmpty ? (
|
||||||
<div className="flex-1 px-12 py-24 flex flex-col justify-center items-center ">
|
<div className="flex-1 px-12 py-24 flex flex-col justify-center items-center ">
|
||||||
@ -103,6 +103,35 @@ export default function Cart() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="lg:col-span-4">
|
<div className="lg:col-span-4">
|
||||||
<div className="flex-shrink-0 px-4 py-24 sm:px-6">
|
<div className="flex-shrink-0 px-4 py-24 sm:px-6">
|
||||||
|
{process.env.COMMERCE_CUSTOMCHECKOUT_ENABLED && (
|
||||||
|
<>
|
||||||
|
{/* Shipping Address */}
|
||||||
|
{/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */}
|
||||||
|
<div className="rounded-md border border-accents-2 px-6 py-6 mb-4 text-center flex items-center justify-center cursor-pointer hover:border-accents-4">
|
||||||
|
<div className="mr-5">
|
||||||
|
<MapPin />
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-center font-medium">
|
||||||
|
<span className="uppercase">+ Add Shipping Address</span>
|
||||||
|
{/* <span>
|
||||||
|
1046 Kearny Street.<br/>
|
||||||
|
San Franssisco, California
|
||||||
|
</span> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Payment Method */}
|
||||||
|
{/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */}
|
||||||
|
<div className="rounded-md border border-accents-2 px-6 py-6 mb-4 text-center flex items-center justify-center cursor-pointer hover:border-accents-4">
|
||||||
|
<div className="mr-5">
|
||||||
|
<CreditCard />
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-center font-medium">
|
||||||
|
<span className="uppercase">+ Add Payment Method</span>
|
||||||
|
{/* <span>VISA #### #### #### 2345</span> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="border-t border-accents-2">
|
<div className="border-t border-accents-2">
|
||||||
<ul className="py-3">
|
<ul className="py-3">
|
||||||
<li className="flex justify-between py-1">
|
<li className="flex justify-between py-1">
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
import { useEffect } from 'react'
|
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import type { GetStaticPropsContext } from 'next'
|
import type { GetStaticPropsContext } from 'next'
|
||||||
|
|
||||||
import { Heart } from '@components/icons'
|
import { Heart } from '@components/icons'
|
||||||
import { Layout } from '@components/common'
|
import { Layout } from '@components/common'
|
||||||
import { Text, Container } from '@components/ui'
|
import { Text, Container } from '@components/ui'
|
||||||
@ -36,8 +33,7 @@ export async function getStaticProps({
|
|||||||
export default function Wishlist() {
|
export default function Wishlist() {
|
||||||
const { data: customer } = useCustomer()
|
const { data: customer } = useCustomer()
|
||||||
// @ts-ignore Shopify - Fix this types
|
// @ts-ignore Shopify - Fix this types
|
||||||
const { data, isLoading, isEmpty } = useWishlist()
|
const { data, isLoading, isEmpty } = useWishlist({ includeProducts: true })
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
@ -60,7 +56,7 @@ export default function Wishlist() {
|
|||||||
data &&
|
data &&
|
||||||
// @ts-ignore Shopify - Fix this types
|
// @ts-ignore Shopify - Fix this types
|
||||||
data.items?.map((item) => (
|
data.items?.map((item) => (
|
||||||
<WishlistCard key={item.id} product={item as any} />
|
<WishlistCard key={item.id} product={item.product! as any} />
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1 +0,0 @@
|
|||||||
console.log('Hello')
|
|
25
yarn.lock
25
yarn.lock
@ -1609,6 +1609,18 @@ auto-bind@~4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb"
|
resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb"
|
||||||
integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==
|
integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==
|
||||||
|
|
||||||
|
autoprefixer@^10.2.4:
|
||||||
|
version "10.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.4.tgz#c0e7cf24fcc6a1ae5d6250c623f0cb8beef2f7e1"
|
||||||
|
integrity sha512-DCCdUQiMD+P/as8m3XkeTUkUKuuRqLGcwD0nll7wevhqoJfMRpJlkFd1+MQh1pvupjiQuip42lc/VFvfUTMSKw==
|
||||||
|
dependencies:
|
||||||
|
browserslist "^4.16.1"
|
||||||
|
caniuse-lite "^1.0.30001181"
|
||||||
|
colorette "^1.2.1"
|
||||||
|
fraction.js "^4.0.13"
|
||||||
|
normalize-range "^0.1.2"
|
||||||
|
postcss-value-parser "^4.1.0"
|
||||||
|
|
||||||
autoprefixer@^9.6.1:
|
autoprefixer@^9.6.1:
|
||||||
version "9.8.6"
|
version "9.8.6"
|
||||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f"
|
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f"
|
||||||
@ -1818,7 +1830,7 @@ browserslist@4.16.1:
|
|||||||
escalade "^3.1.1"
|
escalade "^3.1.1"
|
||||||
node-releases "^1.1.69"
|
node-releases "^1.1.69"
|
||||||
|
|
||||||
browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.6.4:
|
browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.1, browserslist@^4.6.4:
|
||||||
version "4.16.3"
|
version "4.16.3"
|
||||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717"
|
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717"
|
||||||
integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==
|
integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==
|
||||||
@ -3187,6 +3199,11 @@ form-data@^3.0.0:
|
|||||||
combined-stream "^1.0.8"
|
combined-stream "^1.0.8"
|
||||||
mime-types "^2.1.12"
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
|
fraction.js@^4.0.13:
|
||||||
|
version "4.0.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.13.tgz#3c1c315fa16b35c85fffa95725a36fa729c69dfe"
|
||||||
|
integrity sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA==
|
||||||
|
|
||||||
fs-capacitor@^6.1.0:
|
fs-capacitor@^6.1.0:
|
||||||
version "6.2.0"
|
version "6.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-6.2.0.tgz#fa79ac6576629163cb84561995602d8999afb7f5"
|
resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-6.2.0.tgz#fa79ac6576629163cb84561995602d8999afb7f5"
|
||||||
@ -5586,7 +5603,7 @@ postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.
|
|||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
supports-color "^6.1.0"
|
supports-color "^6.1.0"
|
||||||
|
|
||||||
postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.4:
|
postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.6:
|
||||||
version "8.2.6"
|
version "8.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.6.tgz#5d69a974543b45f87e464bc4c3e392a97d6be9fe"
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.6.tgz#5d69a974543b45f87e464bc4c3e392a97d6be9fe"
|
||||||
integrity sha512-xpB8qYxgPuly166AGlpRjUdEYtmOWx2iCwGmrv4vqZL9YPVviDVPZPRXxnXr6xPZOdxQ9lp3ZBFCRgWJ7LE3Sg==
|
integrity sha512-xpB8qYxgPuly166AGlpRjUdEYtmOWx2iCwGmrv4vqZL9YPVviDVPZPRXxnXr6xPZOdxQ9lp3ZBFCRgWJ7LE3Sg==
|
||||||
@ -5645,7 +5662,7 @@ prepend-http@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
|
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
|
||||||
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
|
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
|
||||||
|
|
||||||
prettier@^2.0.5, prettier@^2.1.2:
|
prettier@^2.0.5, prettier@^2.2.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
|
||||||
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
|
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
|
||||||
@ -6617,7 +6634,7 @@ tabbable@^5.1.5:
|
|||||||
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.1.5.tgz#efec48ede268d511c261e3b81facbb4782a35147"
|
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.1.5.tgz#efec48ede268d511c261e3b81facbb4782a35147"
|
||||||
integrity sha512-oVAPrWgLLqrbvQE8XqcU7CVBq6SQbaIbHkhOca3u7/jzuQvyZycrUKPCGr04qpEIUslmUlULbSeN+m3QrKEykA==
|
integrity sha512-oVAPrWgLLqrbvQE8XqcU7CVBq6SQbaIbHkhOca3u7/jzuQvyZycrUKPCGr04qpEIUslmUlULbSeN+m3QrKEykA==
|
||||||
|
|
||||||
tailwindcss@^2.0.2:
|
tailwindcss@^2.0.3:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.0.3.tgz#f8d07797d1f89dc4b171673c26237b58783c2c86"
|
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.0.3.tgz#f8d07797d1f89dc4b171673c26237b58783c2c86"
|
||||||
integrity sha512-s8NEqdLBiVbbdL0a5XwTb8jKmIonOuI4RMENEcKLR61jw6SdKvBss7NWZzwCaD+ZIjlgmesv8tmrjXEp7C0eAQ==
|
integrity sha512-s8NEqdLBiVbbdL0a5XwTb8jKmIonOuI4RMENEcKLR61jw6SdKvBss7NWZzwCaD+ZIjlgmesv8tmrjXEp7C0eAQ==
|
||||||
|
Loading…
x
Reference in New Issue
Block a user