saleor: update the provider structure

This commit is contained in:
Zaiste 2021-06-04 22:43:28 +02:00
parent 79e916f6ee
commit 33992283b3
No known key found for this signature in database
GPG Key ID: 15DF7EBC7F2FFE35
44 changed files with 580 additions and 513 deletions

View File

@ -34,8 +34,8 @@ const SignUpView: FC<Props> = () => {
setMessage('')
await signup({
email,
// firstName,
// lastName,
firstName,
lastName,
password,
})
setLoading(false)

View File

@ -120,8 +120,7 @@ const ProductView: FC<Props> = ({ product }) => {
<Swatch
key={`${opt.id}-${i}`}
active={v.label.toLowerCase() === active}
// variant={opt.displayName}
variant={opt.variant}
variant={opt.displayName}
color={v.hexColors ? v.hexColors[0] : ''}
label={v.label}
onClick={() => {

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1,57 @@
import { CommerceAPI, GetAPISchema, createEndpoint } from '@commerce/api'
import checkoutEndpoint from '@commerce/api/endpoints/checkout'
import { CheckoutSchema } from '@commerce/types/checkout'
export type CheckoutAPI = GetAPISchema<CommerceAPI, CheckoutSchema>
export type CheckoutEndpoint = CheckoutAPI['endpoint']
const checkout: CheckoutEndpoint['handlers']['checkout'] = async ({
req,
res,
config,
}) => {
try {
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Checkout</title>
</head>
<body>
<div style='margin: 10rem auto; text-align: center; font-family: SansSerif, "Segoe UI", Helvetica; color: #888;'>
<svg xmlns="http://www.w3.org/2000/svg" style='height: 60px; width: 60px;' fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
<h1>Checkout not yet implemented :(</h1>
<p>
See <a href='https://github.com/vercel/commerce/issues/64' target='_blank'>#64</a>
</p>
</div>
</body>
</html>
`
res.status(200)
res.setHeader('Content-Type', 'text/html')
res.write(html)
res.end()
} catch (error) {
console.error(error)
const message = 'An unexpected error ocurred'
res.status(500).json({ data: null, errors: [{ message }] })
}
}
export const handlers: CheckoutEndpoint['handlers'] = { checkout }
const checkoutApi = createEndpoint<CheckoutAPI>({
handler: checkoutEndpoint,
handlers,
})
export default checkoutApi

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -16,26 +16,7 @@ export interface SaleorConfig extends CommerceAPIConfig {
storeChannel: string
}
export class Config {
private config: SaleorConfig
constructor(config: SaleorConfig) {
this.config = config
}
getConfig(userConfig: Partial<SaleorConfig> = {}) {
return Object.entries(userConfig).reduce<SaleorConfig>(
(cfg, [key, value]) => Object.assign(cfg, { [key]: value }),
{ ...this.config }
)
}
setConfig(newConfig: Partial<SaleorConfig>) {
Object.assign(this.config, newConfig)
}
}
const config = new Config({
const config: SaleorConfig = {
locale: 'en-US',
commerceUrl: Const.API_URL,
apiToken: Const.SALEOR_TOKEN,
@ -44,12 +25,25 @@ const config = new Config({
fetch: fetchGraphqlApi,
customerCookie: '',
storeChannel: Const.API_CHANNEL,
})
export function getConfig(userConfig?: Partial<SaleorConfig>) {
return config.getConfig(userConfig)
}
export function setConfig(newConfig: Partial<SaleorConfig>) {
return config.setConfig(newConfig)
import {
CommerceAPI,
getCommerceApi as commerceApi,
} from '@commerce/api'
import * as operations from './operations'
export interface ShopifyConfig extends CommerceAPIConfig {}
export const provider = { config, operations }
export type Provider = typeof provider
export type SaleorAPI<P extends Provider = Provider> = CommerceAPI<P>
export function getCommerceApi<P extends Provider>(
customProvider: P = provider as any
): SaleorAPI<P> {
return commerceApi(customProvider)
}

View File

@ -0,0 +1,50 @@
import type { OperationContext } from '@commerce/api/operations'
import { QueryPagesArgs, PageCountableEdge } from '../../schema'
import type { SaleorConfig, Provider } from '..'
import * as Query from '../../utils/queries'
export type Page = any
export type GetAllPagesResult<
T extends { pages: any[] } = { pages: Page[] }
> = T
export default function getAllPagesOperation({
commerce,
}: OperationContext<Provider>) {
async function getAllPages({
query = Query.PageMany,
config,
variables,
}: {
url?: string
config?: Partial<SaleorConfig>
variables?: QueryPagesArgs
preview?: boolean
query?: string
} = {}): Promise<GetAllPagesResult> {
const { fetch, locale, locales = ['en-US'] } = commerce.getConfig(config)
const { data } = await fetch(query, { variables },
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
const pages = data.pages?.edges?.map(({ node: { title: name, slug, ...node } }: PageCountableEdge) => ({
...node,
url: `/${locale}/${slug}`,
name,
}))
return { pages }
}
return getAllPages
}

View File

@ -0,0 +1,46 @@
import type { OperationContext } from '@commerce/api/operations'
import {
GetAllProductPathsQuery,
GetAllProductPathsQueryVariables,
ProductCountableEdge,
} from '../../schema'
import type { ShopifyConfig, Provider, SaleorConfig } from '..'
import { getAllProductsPathsQuery } from '../../utils/queries'
import fetchAllProducts from '../utils/fetch-all-products'
export type GetAllProductPathsResult = {
products: Array<{ path: string }>
}
export default function getAllProductPathsOperation({
commerce,
}: OperationContext<Provider>) {
async function getAllProductPaths({
query,
config,
variables,
}: {
query?: string
config?: SaleorConfig
variables?: any
} = {}): Promise<GetAllProductPathsResult> {
config = commerce.getConfig(config)
const products = await fetchAllProducts({
config,
query: getAllProductsPathsQuery,
variables,
})
return {
products: products?.map(({ node: { slug } }: ProductCountableEdge) => ({
path: `/${slug}`,
})),
}
}
return getAllProductPaths
}

View File

@ -0,0 +1,50 @@
import type { OperationContext } from '@commerce/api/operations'
import { Product } from '@commerce/types/product'
import { ProductCountableEdge } from '../../schema'
import type { Provider, SaleorConfig } from '..'
import { normalizeProduct } from '../../utils'
import * as Query from '../../utils/queries'
type ReturnType = {
products: Product[]
}
export default function getAllProductsOperation({
commerce,
}: OperationContext<Provider>) {
async function getAllProducts({
query = Query.ProductMany,
variables,
config,
}: {
query?: string
variables?: any
config?: Partial<SaleorConfig>
preview?: boolean
featured?: boolean
} = {}): Promise<ReturnType> {
const { fetch, locale } = commerce.getConfig(config)
const { data } = await fetch(
query,
{ variables },
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
const products = data.products?.edges?.map(({ node: p }: ProductCountableEdge) => normalizeProduct(p)) ?? []
return {
products,
}
}
return getAllProducts
}

View File

@ -0,0 +1,51 @@
import type { OperationContext } from '@commerce/api/operations'
import type { Provider, SaleorConfig } from '..'
import { QueryPageArgs } from '../../schema'
import * as Query from '../../utils/queries'
export type Page = any
export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
export default function getPageOperation({
commerce,
}: OperationContext<Provider>) {
async function getPage({
query = Query.PageOne,
variables,
config,
}: {
query?: string
variables: QueryPageArgs,
config?: Partial<SaleorConfig>
preview?: boolean
}): Promise<GetPageResult> {
const { fetch, locale = 'en-US' } = commerce.getConfig(config)
const {
data: { page },
} = await fetch(query, { variables },
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
return {
page: page
? {
...page,
name: page.title,
url: `/${locale}/${page.slug}`,
}
: null,
}
}
return getPage
}

View File

@ -0,0 +1,46 @@
import type { OperationContext } from '@commerce/api/operations'
import { normalizeProduct, } from '../../utils'
import type { Provider, SaleorConfig } from '..'
import * as Query from '../../utils/queries'
type Variables = {
slug: string
}
type ReturnType = {
product: any
}
export default function getProductOperation({
commerce,
}: OperationContext<Provider>) {
async function getProduct({
query = Query.ProductOneBySlug,
variables,
config: cfg,
}: {
query?: string
variables: Variables
config?: Partial<SaleorConfig>
preview?: boolean
}): Promise<ReturnType> {
const { fetch, locale } = commerce.getConfig(cfg)
const { data } = await fetch(query, { variables },
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
return {
product: data?.product ? normalizeProduct(data.product) : null,
}
}
return getProduct
}

View File

@ -0,0 +1,35 @@
import type { OperationContext } from '@commerce/api/operations'
import { Category } from '@commerce/types/site'
import type { SaleorConfig, Provider } from '..'
import { getCategories, getVendors } from '../../utils'
interface GetSiteInfoResult {
categories: Category[]
brands: any[]
}
export default function getSiteInfoOperation({ commerce }: OperationContext<Provider>) {
async function getSiteInfo({
query,
config,
variables,
}: {
query?: string
config?: Partial<SaleorConfig>
preview?: boolean
variables?: any
} = {}): Promise<GetSiteInfoResult> {
const cfg = commerce.getConfig(config)
const categories = await getCategories(cfg)
const brands = await getVendors(cfg)
return {
categories,
brands,
}
}
return getSiteInfo
}

View File

@ -0,0 +1,7 @@
export { default as getAllPages } from './get-all-pages'
export { default as getPage } from './get-page'
export { default as getAllProducts } from './get-all-products'
export { default as getAllProductPaths } from './get-all-product-paths'
export { default as getProduct } from './get-product'
export { default as getSiteInfo } from './get-site-info'
export { default as login } from './login'

View File

@ -0,0 +1,42 @@
import type { ServerResponse } from 'http'
import type { OperationContext } from '@commerce/api/operations'
import type { Provider, SaleorConfig } from '..'
import {
throwUserErrors,
} from '../../utils'
import * as Mutation from '../../utils/mutations'
export default function loginOperation({
commerce,
}: OperationContext<Provider>) {
async function login({
query = Mutation.SessionCreate,
variables,
config,
}: {
query?: string
variables: any
res: ServerResponse
config?: SaleorConfig
}): Promise<any> {
config = commerce.getConfig(config)
const { data: { customerAccessTokenCreate } } = await config.fetch(query, { variables })
throwUserErrors(customerAccessTokenCreate?.customerUserErrors)
const customerAccessToken = customerAccessTokenCreate?.customerAccessToken
const accessToken = customerAccessToken?.accessToken
// if (accessToken) {
// setCustomerToken(accessToken)
// }
return {
result: customerAccessToken?.accessToken,
}
}
return login
}

View File

@ -1,50 +0,0 @@
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import { SaleorConfig, getConfig } from '..'
export type SaleorApiHandler<T = any, H extends SaleorHandlers = {}, Options extends {} = {}> = (
req: NextApiRequest,
res: NextApiResponse<SaleorApiResponse<T>>,
config: SaleorConfig,
handlers: H,
// Custom configs that may be used by a particular handler
options: Options
) => void | Promise<void>
export type SaleorHandler<T = any, Body = null> = (options: {
req: NextApiRequest
res: NextApiResponse<SaleorApiResponse<T>>
config: SaleorConfig
body: Body
}) => void | Promise<void>
export type SaleorHandlers<T = any> = {
[k: string]: SaleorHandler<T, any>
}
export type SaleorApiResponse<T> = {
data: T | null
errors?: { message: string; code?: string }[]
}
export default function createApiHandler<T = any, H extends SaleorHandlers = {}, Options extends {} = {}>(
handler: SaleorApiHandler<T, H, Options>,
handlers: H,
defaultOptions: Options
) {
return function getApiHandler({
config,
operations,
options,
}: {
config?: SaleorConfig
operations?: Partial<H>
options?: Options extends {} ? Partial<Options> : never
} = {}): NextApiHandler {
const ops = { ...operations, ...handlers }
const opts = { ...defaultOptions, ...options }
return function apiHandler(req, res) {
return handler(req, res, getConfig(config), ops, opts)
}
}
}

View File

@ -3,12 +3,11 @@ import fetch from './fetch'
import { API_URL } from '../../const'
import { getError } from '../../utils/handle-fetch-response'
import { getConfig } from '..'
import { getCommerceApi } from '..'
import { getToken } from '@framework/utils'
const fetchGraphqlApi: GraphQLFetcher = async (query: string, { variables } = {}, fetchOptions) => {
// FIXME @zaiste follow the bigcommerce example
const config = getConfig()
const config = getCommerceApi().getConfig()
const token = getToken()
const res = await fetch(API_URL!, {

View File

@ -7,10 +7,11 @@ import * as mutation from '../utils/mutations'
import { Mutation, MutationTokenCreateArgs } from '../schema'
import useLogin, { UseLogin } from '@commerce/auth/use-login'
import { setCSRFToken, setToken, throwUserErrors, checkoutAttach, getCheckoutId } from '../utils'
import { LoginHook } from '@commerce/types/login'
export default useLogin as UseLogin<typeof handler>
export const handler: MutationHook<null, {}, MutationTokenCreateArgs> = {
export const handler: MutationHook<LoginHook> = {
fetchOptions: {
query: mutation.SessionCreate,
},

View File

@ -4,10 +4,11 @@ import useLogout, { UseLogout } from '@commerce/auth/use-logout'
import useCustomer from '../customer/use-customer'
import * as mutation from '../utils/mutations'
import { setCSRFToken, setToken, setCheckoutToken } from '../utils/customer-token'
import { LogoutHook } from '@commerce/types/logout'
export default useLogout as UseLogout<typeof handler>
export const handler: MutationHook<null> = {
export const handler: MutationHook<LogoutHook> = {
fetchOptions: {
query: mutation.SessionDestroy,
},

View File

@ -7,10 +7,11 @@ import { AccountRegisterInput, Mutation, MutationAccountRegisterArgs } from '../
import * as mutation from '../utils/mutations'
import { handleAutomaticLogin, throwUserErrors } from '../utils'
import { SignupHook } from '@commerce/types/signup'
export default useSignup as UseSignup<typeof handler>
export const handler: MutationHook<null, {}, AccountRegisterInput, AccountRegisterInput> = {
export const handler: MutationHook<SignupHook> = {
fetchOptions: {
query: mutation.AccountCreate,
},
@ -27,6 +28,8 @@ export const handler: MutationHook<null, {}, AccountRegisterInput, AccountRegist
input: {
email,
password,
redirectUrl: 'https://localhost.com',
channel: 'default-channel'
},
},
})

View File

@ -8,12 +8,12 @@ import * as mutation from '../utils/mutations'
import { getCheckoutId, checkoutToCart } from '../utils'
import { Cart, CartItemBody } from '../types'
import { Mutation, MutationCheckoutLinesAddArgs } from '../schema'
import { AddItemHook } from '@commerce/types/cart'
export default useAddItem as UseAddItem<typeof handler>
export const handler: MutationHook<Cart, {}, CartItemBody> = {
export const handler: MutationHook<AddItemHook> = {
fetchOptions: { query: mutation.CheckoutLineAdd },
async fetcher({ input: item, options, fetch }) {
if (item.quantity && (!Number.isInteger(item.quantity) || item.quantity! < 1)) {

View File

@ -1,14 +1,14 @@
import { useMemo } from 'react'
import useCommerceCart, { FetchCartInput, UseCart } from '@commerce/cart/use-cart'
import useCommerceCart, { UseCart } from '@commerce/cart/use-cart'
import { Cart } from '../types'
import { SWRHook } from '@commerce/utils/types'
import { checkoutCreate, checkoutToCart, getCheckoutId } from '../utils'
import * as query from '../utils/queries'
import { GetCartHook } from '@commerce/types/cart'
export default useCommerceCart as UseCart<typeof handler>
export const handler: SWRHook<Cart | null, {}, FetchCartInput, { isEmpty?: boolean }> = {
export const handler: SWRHook<GetCartHook> = {
fetchOptions: {
query: query.CheckoutOne,
},

View File

@ -1,25 +1,17 @@
import { useCallback } from 'react'
import type { MutationHookContext, HookFetcherContext } from '@commerce/utils/types'
import { RemoveCartItemBody } from '@commerce/types'
import { ValidationError } from '@commerce/utils/errors'
import useRemoveItem, { RemoveItemInput as RemoveItemInputBase, UseRemoveItem } from '@commerce/cart/use-remove-item'
import type { MutationHookContext, HookFetcherContext, MutationHook } from '@commerce/utils/types'
import useRemoveItem, { UseRemoveItem } from '@commerce/cart/use-remove-item'
import useCart from './use-cart'
import * as mutation from '../utils/mutations'
import { getCheckoutId, checkoutToCart } from '../utils'
import { Cart, LineItem } from '../types'
import { Mutation, MutationCheckoutLineDeleteArgs } from '../schema'
export type RemoveItemFn<T = any> = T extends LineItem
? (input?: RemoveItemInput<T>) => Promise<Cart | null>
: (input: RemoveItemInput<T>) => Promise<Cart | null>
export type RemoveItemInput<T = any> = T extends LineItem ? Partial<RemoveItemInputBase> : RemoveItemInputBase
import { LineItem, RemoveItemHook } from '../types/cart'
export default useRemoveItem as UseRemoveItem<typeof handler>
export const handler = {
fetchOptions: { query: mutation.CheckoutLineDelete },
async fetcher({ input: { itemId }, options, fetch }: HookFetcherContext<RemoveCartItemBody>) {
async fetcher({ input: { itemId }, options, fetch }: HookFetcherContext<RemoveItemHook>) {
const data = await fetch<Mutation, MutationCheckoutLineDeleteArgs>({
...options,
variables: {
@ -29,25 +21,19 @@ export const handler = {
})
return checkoutToCart(data.checkoutLineDelete)
},
useHook:
({ fetch }: MutationHookContext<Cart | null, RemoveCartItemBody>) =>
<T extends LineItem | undefined = undefined>(ctx: { item?: T } = {}) => {
const { item } = ctx
useHook: ({ fetch }: MutationHookContext<RemoveItemHook>) => <
T extends LineItem | undefined = undefined
> () => {
const { mutate } = useCart()
const removeItem: RemoveItemFn<LineItem> = async (input) => {
const itemId = input?.id ?? item?.id
if (!itemId) {
throw new ValidationError({
message: 'Invalid input used for this operation',
})
}
return useCallback(
async function removeItem(input) {
const data = await fetch({ input: { itemId: input.id } })
await mutate(data, false)
const data = await fetch({ input: { itemId } })
await mutate(data, false)
return data
}
return useCallback(removeItem as RemoveItemFn<T>, [fetch, mutate])
return data
},
[fetch, mutate]
);
},
}

View File

@ -2,26 +2,32 @@ import { useCallback } from 'react'
import debounce from 'lodash.debounce'
import type { HookFetcherContext, MutationHookContext } from '@commerce/utils/types'
import { ValidationError } from '@commerce/utils/errors'
import useUpdateItem, { UpdateItemInput as UpdateItemInputBase, UseUpdateItem } from '@commerce/cart/use-update-item'
import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item'
import useCart from './use-cart'
import { handler as removeItemHandler } from './use-remove-item'
import type { Cart, LineItem, UpdateCartItemBody } from '../types'
import type { LineItem } from '../types'
import { checkoutToCart } from '../utils'
import { getCheckoutId } from '../utils'
import { Mutation, MutationCheckoutLinesUpdateArgs } from '../schema'
import * as mutation from '../utils/mutations'
export type UpdateItemInput<T = any> = T extends LineItem
? Partial<UpdateItemInputBase<LineItem>>
: UpdateItemInputBase<LineItem>
import type { UpdateItemHook } from '../types/cart'
export type UpdateItemActionInput<T = any> = T extends LineItem
? Partial<UpdateItemHook['actionInput']>
: UpdateItemHook['actionInput']
export default useUpdateItem as UseUpdateItem<typeof handler>
export const handler = {
fetchOptions: { query: mutation.CheckoutLineUpdate },
async fetcher({ input: { itemId, item }, options, fetch }: HookFetcherContext<UpdateCartItemBody>) {
async fetcher({
input: { itemId, item },
options,
fetch
}: HookFetcherContext<UpdateItemHook>) {
if (Number.isInteger(item.quantity)) {
// Also allow the update hook to remove an item if the quantity is lower than 1
if (item.quantity! < 1) {
@ -53,8 +59,7 @@ export const handler = {
return checkoutToCart(checkoutLinesUpdate)
},
useHook:
({ fetch }: MutationHookContext<Cart | null, UpdateCartItemBody>) =>
useHook: ({ fetch }: MutationHookContext<UpdateItemHook>) =>
<T extends LineItem | undefined = undefined>(
ctx: {
item?: T
@ -65,7 +70,7 @@ export const handler = {
const { mutate } = useCart() as any
return useCallback(
debounce(async (input: UpdateItemInput<T>) => {
debounce(async (input: UpdateItemActionInput<T>) => {
const itemId = input.id ?? item?.id
const productId = input.productId ?? item?.productId
const variantId = input.productId ?? item?.variantId

View File

@ -1,40 +0,0 @@
import { getConfig, SaleorConfig } from '../api'
import { PageCountableEdge } from '../schema'
import * as query from '../utils/queries'
type Variables = {
first?: number
}
type ReturnType = {
pages: Page[]
}
export type Page = {
id: string
name: string
url: string
sort_order?: number
body: string
}
const getAllPages = async (options?: {
variables?: Variables
config: SaleorConfig
preview?: boolean
}): Promise<ReturnType> => {
let { config, variables = { first: 100 } } = options ?? {}
config = getConfig(config)
const { locale } = config
const { data } = await config.fetch(query.PageMany, { variables })
const pages = data.pages?.edges?.map(({ node: { title: name, slug, ...node } }: PageCountableEdge) => ({
...node,
url: `/${locale}/${slug}`,
name,
}))
return { pages }
}
export default getAllPages

View File

@ -1,36 +0,0 @@
import { getConfig, SaleorConfig } from '../api'
import { Page } from './get-all-pages'
import * as query from '../utils/queries'
type Variables = {
id: string
}
export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
const getPage = async (options: {
variables: Variables
config: SaleorConfig
preview?: boolean
}): Promise<GetPageResult> => {
let { config, variables } = options ?? {}
config = getConfig(config)
const { locale } = config
const { data } = await config.fetch(query.PageOne, { variables })
const page = data.page
return {
page: page
? {
...page,
name: page.title,
url: `/${locale}/${page.slug}`,
}
: null,
}
}
export default getPage

View File

@ -1,31 +0,0 @@
import getCategories, { Category } from '../utils/get-categories'
import getVendors, { Brands } from '../utils/get-vendors'
import { getConfig, SaleorConfig } from '../api'
export type GetSiteInfoResult<
T extends { categories: any[]; brands: any[] } = {
categories: Category[]
brands: Brands
}
> = T
const getSiteInfo = async (options?: {
variables?: any
config: SaleorConfig
preview?: boolean
}): Promise<GetSiteInfoResult> => {
let { config } = options ?? {}
config = getConfig(config)
const categories = await getCategories(config)
const brands = await getVendors(config)
return {
categories,
brands,
}
}
export default getSiteInfo

View File

@ -1,23 +0,0 @@
import { getConfig, SaleorConfig } from '../api'
import * as query from '../utils/queries'
import Cookies from 'js-cookie'
async function getCustomerId({
customerToken: customerAccesToken,
config,
}: {
customerToken: string
config?: SaleorConfig
}): Promise<number | undefined> {
config = getConfig(config)
const { data } = await config.fetch(query.CustomerOne, {
variables: {
customerAccesToken: customerAccesToken || Cookies.get(config.customerCookie),
},
})
return data.customer?.id
}
export default getCustomerId

View File

@ -1,12 +1,12 @@
import useCustomer, { UseCustomer } from '@commerce/customer/use-customer'
import { Customer } from '@commerce/types'
import { CustomerHook } from '@commerce/types/customer'
import { SWRHook } from '@commerce/utils/types'
import * as query from '../utils/queries'
export default useCustomer as UseCustomer<typeof handler>
export const handler: SWRHook<Customer | null> = {
export const handler: SWRHook<CustomerHook> = {
fetchOptions: {
query: query.CustomerCurrent,
},

View File

@ -1,23 +0,0 @@
import { CollectionCountableEdge } from '../schema'
import { getConfig, SaleorConfig } from '../api'
import * as query from '../utils/queries'
const getAllCollections = async (options?: { variables?: any; config: SaleorConfig; preview?: boolean }) => {
let { config, variables = { first: 100 } } = options ?? {}
config = getConfig(config)
const { data } = await config.fetch(query.CollectionMany, { variables })
const edges = data.collections?.edges ?? []
const categories = edges.map(({ node: { id: entityId, name, slug } }: CollectionCountableEdge) => ({
entityId,
name,
path: `/${slug}`,
}))
return {
categories,
}
}
export default getAllCollections

View File

@ -1,41 +0,0 @@
import { getConfig, SaleorConfig } from '../api'
import fetchAllProducts from '../api/utils/fetch-all-products'
import { ProductCountableEdge } from '../schema'
import { getAllProductsPathsQuery } from '../utils/queries'
type ProductPath = {
path: string
}
export type ProductPathNode = {
node: ProductPath
}
type ReturnType = {
products: ProductPathNode[]
}
const getAllProductPaths = async (options?: {
variables?: any
config?: SaleorConfig
preview?: boolean
}): Promise<ReturnType> => {
let { config, variables = { first: 100 } } = options ?? {}
config = getConfig(config)
const products = await fetchAllProducts({
config,
query: getAllProductsPathsQuery,
variables,
})
return {
products: products?.map(({ node: { slug } }: ProductCountableEdge) => ({
node: {
path: `/${slug}`,
},
})),
}
}
export default getAllProductPaths

View File

@ -1,54 +0,0 @@
import { GraphQLFetcherResult } from '@commerce/api'
import { Product } from '@commerce/types'
import { getConfig, SaleorConfig } from '../api'
import { ProductCountableEdge } from '../schema'
import { normalizeProduct } from '../utils/normalize'
import * as query from '../utils/queries'
type Variables = {
first?: number
field?: string
}
type ReturnType = {
products: Product[]
}
const getAllProducts = async (options: {
variables?: Variables
config?: SaleorConfig
preview?: boolean
featured?: boolean
}): Promise<ReturnType> => {
let { config, variables = { first: 100 }, featured } = options ?? {}
config = getConfig(config)
if (featured) {
const { data }: GraphQLFetcherResult = await config.fetch(query.CollectionOne, {
variables: { ...variables, categoryId: 'Q29sbGVjdGlvbjoxOQ==' },
})
debugger
const products = data.collection.products?.edges?.map(({ node: p }: ProductCountableEdge) => normalizeProduct(p)) ?? []
return {
products,
}
} else {
const { data }: GraphQLFetcherResult = await config.fetch(query.ProductMany, {
variables,
})
const products = data.products?.edges?.map(({ node: p }: ProductCountableEdge) => normalizeProduct(p)) ?? []
return {
products,
}
}
}
export default getAllProducts

View File

@ -1,29 +0,0 @@
import { GraphQLFetcherResult } from '@commerce/api'
import { getConfig, SaleorConfig } from '../api'
import { normalizeProduct } from '../utils'
import * as query from '../utils/queries'
type Variables = {
slug: string
}
type ReturnType = {
product: any
}
const getProduct = async (options: {
variables: Variables
config: SaleorConfig
preview?: boolean
}): Promise<ReturnType> => {
let { config, variables } = options ?? {}
config = getConfig(config)
const { data }: GraphQLFetcherResult = await config.fetch(query.ProductOneBySlug, { variables })
return {
product: data?.product ? normalizeProduct(data.product) : null,
}
}
export default getProduct

View File

@ -1,18 +1,19 @@
import { SWRHook } from '@commerce/utils/types'
import { Product } from '@commerce/types'
import { Product } from '@commerce/types/product'
import useSearch, { UseSearch } from '@commerce/product/use-search'
import { ProductCountableEdge } from '../schema'
import { getSearchVariables, normalizeProduct } from '../utils'
import * as query from '../utils/queries'
import { SearchProductsHook } from '@commerce/types/product'
export default useSearch as UseSearch<typeof handler>
export type SearchProductsInput = {
search?: string
categoryId?: string
brandId?: string
categoryId?: string | number
brandId?: string | number
sort?: string
}
@ -21,7 +22,7 @@ export type SearchProductsData = {
found: boolean
}
export const handler: SWRHook<SearchProductsData, SearchProductsInput, SearchProductsInput> = {
export const handler: SWRHook<SearchProductsHook> = {
fetchOptions: {
query: query.ProductMany,
},

View File

@ -1,4 +1,4 @@
import * as Core from '@commerce/types'
import type { Cart as CoreCart } from '@commerce/types'
import { CheckoutLine } from './schema'
export type SaleorCheckout = {
@ -7,10 +7,10 @@ export type SaleorCheckout = {
lineItems: CheckoutLine[]
}
export type Cart = Core.Cart & {
export type Cart = CoreCart.Cart & {
lineItems: LineItem[]
}
export interface LineItem extends Core.LineItem {
export interface LineItem extends CoreCart.LineItem {
options?: any[]
}
@ -23,21 +23,21 @@ export type OptionSelections = {
option_value: number | string
}
export type CartItemBody = Core.CartItemBody & {
export type CartItemBody = CoreCart.CartItemBody & {
productId: string // The product id is always required for BC
optionSelections?: OptionSelections
}
export type GetCartHandlerBody = Core.GetCartHandlerBody
// export type GetCartHandlerBody = CoreCart.GetCartHandlerBody
export type AddCartItemBody = Core.AddCartItemBody<CartItemBody>
// export type AddCartItemBody = Core.AddCartItemBody<CartItemBody>
export type AddCartItemHandlerBody = Core.AddCartItemHandlerBody<CartItemBody>
// export type AddCartItemHandlerBody = Core.AddCartItemHandlerBody<CartItemBody>
export type UpdateCartItemBody = Core.UpdateCartItemBody<CartItemBody>
// export type UpdateCartItemBody = Core.UpdateCartItemBody<CartItemBody>
export type UpdateCartItemHandlerBody = Core.UpdateCartItemHandlerBody<CartItemBody>
// export type UpdateCartItemHandlerBody = Core.UpdateCartItemHandlerBody<CartItemBody>
export type RemoveCartItemBody = Core.RemoveCartItemBody
// export type RemoveCartItemBody = Core.RemoveCartItemBody
export type RemoveCartItemHandlerBody = Core.RemoveCartItemHandlerBody
// export type RemoveCartItemHandlerBody = Core.RemoveCartItemHandlerBody

View File

@ -0,0 +1,32 @@
import * as Core from '@commerce/types/cart'
export * from '@commerce/types/cart'
export type SaleorCart = {}
/**
* Extend core cart types
*/
export type Cart = Core.Cart & {
lineItems: Core.LineItem[]
url?: string
}
export type CartTypes = Core.CartTypes
export type CartHooks = Core.CartHooks<CartTypes>
export type GetCartHook = CartHooks['getCart']
export type AddItemHook = CartHooks['addItem']
export type UpdateItemHook = CartHooks['updateItem']
export type RemoveItemHook = CartHooks['removeItem']
export type CartSchema = Core.CartSchema<CartTypes>
export type CartHandlers = Core.CartHandlers<CartTypes>
export type GetCartHandler = CartHandlers['getCart']
export type AddItemHandler = CartHandlers['addItem']
export type UpdateItemHandler = CartHandlers['updateItem']
export type RemoveItemHandler = CartHandlers['removeItem']

View File

@ -1,13 +1,8 @@
import { Category } from '@commerce/types/site'
import { SaleorConfig } from '../api'
import { CollectionCountableEdge } from '../schema'
import * as query from './queries'
export type Category = {
entityId: string
name: string
path: string
}
const getCategories = async (config: SaleorConfig): Promise<Category[]> => {
const { data } = await config.fetch(query.CollectionMany, {
variables: {
@ -16,9 +11,10 @@ const getCategories = async (config: SaleorConfig): Promise<Category[]> => {
})
return (
data.collections?.edges?.map(({ node: { id: entityId, name, slug } }: CollectionCountableEdge) => ({
entityId,
data.collections?.edges?.map(({ node: { id, name, slug } }: CollectionCountableEdge) => ({
id,
name,
slug,
path: `/${slug}`,
})) ?? []
)

View File

@ -1,4 +1,4 @@
import { Product } from '@commerce/types'
import { Product } from '@commerce/types/product'
import { Product as SaleorProduct, Checkout, CheckoutLine, Money, ProductVariant } from '../schema'
@ -120,7 +120,7 @@ function normalizeLineItem({ id, variant, quantity }: CheckoutLine): LineItem {
sku: variant?.sku ?? '',
name: variant?.name!,
image: {
url: variant?.media![0].url ?? placeholderImg,
url: variant?.media![0] ? variant?.media![0].url : placeholderImg,
},
requiresShipping: false,
price: variant?.pricing?.price?.gross.amount!,

View File

@ -72,7 +72,7 @@
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^6.7.0",
"prettier": "^2.3.0",
"typescript": "^4.2.4"
"typescript": "4.2.4"
},
"husky": {
"hooks": {

144
yarn.lock
View File

@ -921,25 +921,25 @@
resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-10.0.9-canary.5.tgz#5ece6594ec08b48bc319d8f171d9c46a7beb04ba"
integrity sha512-47Y2GO+PezgJF4t41/VOEmIpUe66bbzbh/jO+doldwoPiLPxrSfOMpAnlJLpm5keHquBJMCIQbwDtmSpNvPkTg==
"@nodelib/fs.scandir@2.1.4":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69"
integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
"@nodelib/fs.stat" "2.0.4"
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655"
integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3":
version "1.2.6"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063"
integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==
version "1.2.7"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz#94c23db18ee4653e129abd26fb06f870ac9e1ee2"
integrity sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==
dependencies:
"@nodelib/fs.scandir" "2.1.4"
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@opentelemetry/api@0.14.0":
@ -1081,21 +1081,16 @@
dependencies:
"@types/node" "*"
"@types/node@*":
version "15.3.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.1.tgz#23a06b87eedb524016616e886b116b8fdcb180af"
integrity sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw==
"@types/node@*", "@types/node@^15.6.1":
version "15.12.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.1.tgz#9b60797dee1895383a725f828a869c86c6caa5c2"
integrity sha512-zyxJM8I1c9q5sRMtVF+zdd13Jt6RU4r4qfhTd7lQubyThvLfx6yYekWSQjGCGV2Tkecgxnlpl/DNlb6Hg+dmEw==
"@types/node@10.12.18":
version "10.12.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
"@types/node@^15.6.1":
version "15.6.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.6.1.tgz#32d43390d5c62c5b6ec486a9bc9c59544de39a08"
integrity sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA==
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@ -1107,9 +1102,9 @@
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react@^17.0.8":
version "17.0.8"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.8.tgz#fe76e3ba0fbb5602704110fd1e3035cf394778e3"
integrity sha512-3sx4c0PbXujrYAKwXxNONXUtRp9C+hE2di0IuxFyf5BELD+B+AXL8G7QrmSKhVwKZDbv0igiAjQAMhXj8Yg3aw==
version "17.0.9"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.9.tgz#1147fb520024a62c9b3841f5cb4db89b73ddb87f"
integrity sha512-2Cw7FvevpJxQrCb+k5t6GH1KIvmadj5uBbjPaLlJB/nZWUj56e1ZqcD6zsoMFB47MsJUTFl9RJ132A7hb3QFJA==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@ -1766,15 +1761,10 @@ camelcase@^5.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001173, caniuse-lite@^1.0.30001179, caniuse-lite@^1.0.30001219:
version "1.0.30001228"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa"
integrity sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==
caniuse-lite@^1.0.30001230:
version "1.0.30001231"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001231.tgz#6c1f9b49fc27cc368b894e64b9b28b39ef80603b"
integrity sha512-WAFFv31GgU4DiwNAy77qMo3nNyycEhH3ikcCVHvkQpPe/fO8Tb2aRYzss8kgyLQBm8mJ7OryW4X6Y4vsBCIqag==
caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001173, caniuse-lite@^1.0.30001179, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001230:
version "1.0.30001234"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001234.tgz#8fc2e709e3b0679d7af7f073a1c661155c39b975"
integrity sha512-a3gjUVKkmwLdNysa1xkUAwN2VfJUJyVW47rsi3aCbkRCtbHAfo+rOsCqVw29G6coQ8gzAPb5XBXwiGHwme3isA==
capital-case@^1.0.4:
version "1.0.4"
@ -2584,9 +2574,9 @@ ecdsa-sig-formatter@1.0.11:
safe-buffer "^5.0.1"
electron-to-chromium@^1.3.634, electron-to-chromium@^1.3.723:
version "1.3.734"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.734.tgz#c8d318a4eb27509190cf3a08870dbcbf06c74dcb"
integrity sha512-iQF2mjPZ6zNNq45kbJ6MYZYCBNdv2JpGiJC/lVx4tGJWi9MNg73KkL9sWGN4X4I/CP2SBLWsT8nPADZZpAHIyw==
version "1.3.749"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz#0ecebc529ceb49dd2a7c838ae425236644c3439a"
integrity sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A==
elegant-spinner@^1.0.1:
version "1.0.1"
@ -2672,9 +2662,9 @@ error-ex@^1.3.1:
is-arrayish "^0.2.1"
es-abstract@^1.18.0-next.1:
version "1.18.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4"
integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==
version "1.18.3"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0"
integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==
dependencies:
call-bind "^1.0.2"
es-to-primitive "^1.2.1"
@ -2684,14 +2674,14 @@ es-abstract@^1.18.0-next.1:
has-symbols "^1.0.2"
is-callable "^1.2.3"
is-negative-zero "^2.0.1"
is-regex "^1.1.2"
is-string "^1.0.5"
object-inspect "^1.9.0"
is-regex "^1.1.3"
is-string "^1.0.6"
object-inspect "^1.10.3"
object-keys "^1.1.1"
object.assign "^4.1.2"
string.prototype.trimend "^1.0.4"
string.prototype.trimstart "^1.0.4"
unbox-primitive "^1.0.0"
unbox-primitive "^1.0.1"
es-to-primitive@^1.2.1:
version "1.2.1"
@ -2778,9 +2768,9 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
safe-buffer "^5.1.1"
execa@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.1.tgz#aee63b871c9b2cb56bc9addcd3c70a785c6bf0d1"
integrity sha512-4hFTjFbFzQa3aCLobpbPJR/U+VoL1wdV5ozOWjeet0AWDeYr9UFGM1eUFWHX+VtOWFq4p0xXUXfW1YxUaP4fpw==
version "5.1.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
dependencies:
cross-spawn "^7.0.3"
get-stream "^6.0.0"
@ -3150,9 +3140,9 @@ graphql-tag@^2.11.0:
tslib "^2.1.0"
graphql-ws@^4.4.1:
version "4.7.0"
resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-4.7.0.tgz#b323fbf35a3736eed85dac24c0054d6d10c93e62"
integrity sha512-Md8SsmC9ZlsogFPd3Ot8HbIAAqsHh8Xoq7j4AmcIat1Bh6k91tjVyQvA0Au1/BolXSYq+RDvib6rATU2Hcf1Xw==
version "4.8.0"
resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-4.8.0.tgz#4b0a82fa1ad00a3baa1cae980032dcaaad08b339"
integrity sha512-0jk0c7GPfAlQfA7xZ4CKlLvFF4JBPYbczIHIXl/tk/fXoCLzmrmwQ/HNwOoOHfFMS3usbD1nt77k67pgXx2BYQ==
graphql@^15.5.0:
version "15.5.0"
@ -3559,7 +3549,7 @@ is-promise@^2.1.0:
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
is-regex@^1.1.2:
is-regex@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f"
integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==
@ -3594,7 +3584,7 @@ is-stream@^2.0.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
is-string@^1.0.5:
is-string@^1.0.5, is-string@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f"
integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==
@ -4208,17 +4198,17 @@ miller-rabin@^4.0.0:
bn.js "^4.0.0"
brorand "^1.0.1"
mime-db@1.47.0:
version "1.47.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c"
integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==
mime-db@1.48.0:
version "1.48.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d"
integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==
mime-types@^2.1.12:
version "2.1.30"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d"
integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==
version "2.1.31"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b"
integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==
dependencies:
mime-db "1.47.0"
mime-db "1.48.0"
mime@^2.3.1:
version "2.5.2"
@ -4512,7 +4502,7 @@ object-hash@^2.1.1:
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5"
integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
object-inspect@^1.9.0:
object-inspect@^1.10.3:
version "1.10.3"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369"
integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==
@ -5210,16 +5200,7 @@ postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.32, postcss@^7.0.
source-map "^0.6.1"
supports-color "^6.1.0"
postcss@^8.1.6, postcss@^8.1.7, postcss@^8.2.1:
version "8.2.15"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.15.tgz#9e66ccf07292817d226fc315cbbf9bc148fbca65"
integrity sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q==
dependencies:
colorette "^1.2.2"
nanoid "^3.1.23"
source-map "^0.6.1"
postcss@^8.3.0:
postcss@^8.1.6, postcss@^8.1.7, postcss@^8.2.1, postcss@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.0.tgz#b1a713f6172ca427e3f05ef1303de8b65683325f"
integrity sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==
@ -5258,9 +5239,9 @@ prepend-http@^2.0.0:
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
prettier@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18"
integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==
version "2.3.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6"
integrity sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==
pretty-hrtime@^1.0.3:
version "1.0.3"
@ -6151,9 +6132,9 @@ tabbable@^5.2.0:
integrity sha512-0uyt8wbP0P3T4rrsfYg/5Rg3cIJ8Shl1RJ54QMqYxm1TLdWqJD1u6+RQjr2Lor3wmfT7JRHkirIwy99ydBsyPg==
tailwindcss@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.1.2.tgz#29402bf73a445faedd03df6d3b177e7b52b7c4a1"
integrity sha512-T5t+wwd+/hsOyRw2HJuFuv0LTUm3MUdHm2DJ94GPVgzqwPPFa9XxX0KlwLWupUuiOUj6uiKURCzYPHFcuPch/w==
version "2.1.4"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.1.4.tgz#ee8a1b8ccc140db61960b6738f968a8a1c4cd1f8"
integrity sha512-fh1KImDLg6se/Suaelju/5oFbqq1b0ntagmGLu0aG9LlnNPGHgO1n/4E57CbKcCtyz/VYnvVXUiWmfyfBBZQ6g==
dependencies:
"@fullhuman/postcss-purgecss" "^3.1.3"
bytes "^3.0.0"
@ -6350,12 +6331,17 @@ type-fest@^0.7.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==
typescript@4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
typescript@^3.9.5, typescript@^3.9.7:
version "3.9.9"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674"
integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==
typescript@^4.2.3, typescript@^4.2.4:
typescript@^4.2.3:
version "4.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
@ -6365,7 +6351,7 @@ ua-parser-js@^0.7.18:
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"
integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==
unbox-primitive@^1.0.0:
unbox-primitive@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"
integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==