Apply prettier over all files

This commit is contained in:
Luis Alvarez
2020-10-01 20:40:40 -05:00
parent 2314ad760a
commit 0ef6449aff
72 changed files with 648 additions and 652 deletions

View File

@@ -5,7 +5,7 @@ export const responsiveImageFragment = /* GraphQL */ `
urlLarge: url(width: $imgLargeWidth, height: $imgLargeHeight)
urlXL: url(width: $imgXLWidth, height: $imgXLHeight)
}
`;
`
export const productInfoFragment = /* GraphQL */ `
fragment productInfo on Product {
@@ -63,4 +63,4 @@ export const productInfoFragment = /* GraphQL */ `
}
${responsiveImageFragment}
`;
`

View File

@@ -1,17 +1,17 @@
import { CommerceAPIConfig } from 'lib/commerce/api';
import { GetAllProductsQueryVariables } from '../schema';
import fetchAPI from './utils/fetch-api';
import { CommerceAPIConfig } from 'lib/commerce/api'
import { GetAllProductsQueryVariables } from '../schema'
import fetchAPI from './utils/fetch-api'
export interface Images {
small?: ImageOptions;
medium?: ImageOptions;
large?: ImageOptions;
xl?: ImageOptions;
small?: ImageOptions
medium?: ImageOptions
large?: ImageOptions
xl?: ImageOptions
}
export interface ImageOptions {
width: number;
height?: number;
width: number
height?: number
}
export type ProductImageVariables = Pick<
@@ -24,39 +24,39 @@ export type ProductImageVariables = Pick<
| 'imgLargeHeight'
| 'imgXLWidth'
| 'imgXLHeight'
>;
>
export interface BigcommerceConfigOptions extends CommerceAPIConfig {
images?: Images;
images?: Images
}
export interface BigcommerceConfig extends BigcommerceConfigOptions {
readonly imageVariables?: ProductImageVariables;
readonly imageVariables?: ProductImageVariables
}
const API_URL = process.env.BIGCOMMERCE_STOREFRONT_API_URL;
const API_TOKEN = process.env.BIGCOMMERCE_STOREFRONT_API_TOKEN;
const API_URL = process.env.BIGCOMMERCE_STOREFRONT_API_URL
const API_TOKEN = process.env.BIGCOMMERCE_STOREFRONT_API_TOKEN
if (!API_URL) {
throw new Error(
`The environment variable BIGCOMMERCE_STOREFRONT_API_URL is missing and it's required to access your store`
);
)
}
if (!API_TOKEN) {
throw new Error(
`The environment variable BIGCOMMERCE_STOREFRONT_API_TOKEN is missing and it's required to access your store`
);
)
}
export class Config {
private config: BigcommerceConfig;
private config: BigcommerceConfig
constructor(config: BigcommerceConfigOptions) {
this.config = {
...config,
get imageVariables() {
const { images } = this;
const { images } = this
return images
? {
imgSmallWidth: images.small?.width,
@@ -68,17 +68,17 @@ export class Config {
imgXLWidth: images.xl?.height,
imgXLHeight: images.xl?.height,
}
: undefined;
: undefined
},
};
}
}
getConfig() {
return this.config;
return this.config
}
setConfig(newConfig: Partial<BigcommerceConfig>) {
Object.assign(this.config, newConfig);
Object.assign(this.config, newConfig)
}
}
@@ -86,12 +86,12 @@ const config = new Config({
commerceUrl: API_URL,
apiToken: API_TOKEN,
fetch: fetchAPI,
});
})
export function getConfig() {
return config.getConfig();
return config.getConfig()
}
export function setConfig(newConfig: Partial<BigcommerceConfig>) {
return config.setConfig(newConfig);
return config.setConfig(newConfig)
}

View File

@@ -1,6 +1,6 @@
import type { GetAllProductPathsQuery } from 'lib/bigcommerce/schema';
import type { RecursivePartial, RecursiveRequired } from '../utils/types';
import { BigcommerceConfig, getConfig } from '..';
import type { GetAllProductPathsQuery } from 'lib/bigcommerce/schema'
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import { BigcommerceConfig, getConfig } from '..'
export const getAllProductPathsQuery = /* GraphQL */ `
query getAllProductPaths {
@@ -14,41 +14,41 @@ export const getAllProductPathsQuery = /* GraphQL */ `
}
}
}
`;
`
export interface GetAllProductPathsResult<T> {
products: T extends GetAllProductPathsQuery
? NonNullable<T['site']['products']['edges']>
: unknown;
: unknown
}
async function getAllProductPaths(opts?: {
query?: string;
config?: BigcommerceConfig;
}): Promise<GetAllProductPathsResult<GetAllProductPathsQuery>>;
query?: string
config?: BigcommerceConfig
}): Promise<GetAllProductPathsResult<GetAllProductPathsQuery>>
async function getAllProductPaths<T, V = any>(opts: {
query: string;
config?: BigcommerceConfig;
}): Promise<GetAllProductPathsResult<T>>;
query: string
config?: BigcommerceConfig
}): Promise<GetAllProductPathsResult<T>>
async function getAllProductPaths({
query = getAllProductPathsQuery,
config = getConfig(),
}: {
query?: string;
config?: BigcommerceConfig;
query?: string
config?: BigcommerceConfig
} = {}): Promise<GetAllProductPathsResult<GetAllProductPathsQuery>> {
// RecursivePartial forces the method to check for every prop in the data, which is
// required in case there's a custom `query`
const data = await config.fetch<RecursivePartial<GetAllProductPathsQuery>>(
query
);
const products = data.site?.products?.edges;
)
const products = data.site?.products?.edges
return {
products: (products as RecursiveRequired<typeof products>) ?? [],
};
}
}
export default getAllProductPaths;
export default getAllProductPaths

View File

@@ -1,15 +1,10 @@
import type {
GetAllProductsQuery,
GetAllProductsQueryVariables,
} from 'lib/bigcommerce/schema';
import type { RecursivePartial, RecursiveRequired } from '../utils/types';
import { productInfoFragment } from '../fragments/product';
import {
BigcommerceConfig,
getConfig,
Images,
ProductImageVariables,
} from '..';
} from 'lib/bigcommerce/schema'
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import { productInfoFragment } from '../fragments/product'
import { BigcommerceConfig, getConfig, Images, ProductImageVariables } from '..'
export const getAllProductsQuery = /* GraphQL */ `
query getAllProducts(
@@ -40,53 +35,53 @@ export const getAllProductsQuery = /* GraphQL */ `
}
${productInfoFragment}
`;
`
export interface GetAllProductsResult<T> {
products: T extends GetAllProductsQuery
? NonNullable<T['site']['products']['edges']>
: unknown;
: unknown
}
export type ProductVariables = Images &
Omit<GetAllProductsQueryVariables, keyof ProductImageVariables>;
Omit<GetAllProductsQueryVariables, keyof ProductImageVariables>
async function getAllProducts(opts?: {
query?: string;
variables?: ProductVariables;
config?: BigcommerceConfig;
}): Promise<GetAllProductsResult<GetAllProductsQuery>>;
query?: string
variables?: ProductVariables
config?: BigcommerceConfig
}): Promise<GetAllProductsResult<GetAllProductsQuery>>
async function getAllProducts<T, V = any>(opts: {
query: string;
variables?: V;
config?: BigcommerceConfig;
}): Promise<GetAllProductsResult<T>>;
query: string
variables?: V
config?: BigcommerceConfig
}): Promise<GetAllProductsResult<T>>
async function getAllProducts({
query = getAllProductsQuery,
variables: vars,
config = getConfig(),
}: {
query?: string;
variables?: ProductVariables;
config?: BigcommerceConfig;
query?: string
variables?: ProductVariables
config?: BigcommerceConfig
} = {}): Promise<GetAllProductsResult<GetAllProductsQuery>> {
const variables: GetAllProductsQueryVariables = {
...config.imageVariables,
...vars,
};
}
// RecursivePartial forces the method to check for every prop in the data, which is
// required in case there's a custom `query`
const data = await config.fetch<RecursivePartial<GetAllProductsQuery>>(
query,
{ variables }
);
const products = data.site?.products?.edges;
)
const products = data.site?.products?.edges
return {
products: (products as RecursiveRequired<typeof products>) ?? [],
};
}
}
export default getAllProducts;
export default getAllProducts

View File

@@ -1,10 +1,10 @@
import type {
GetProductQuery,
GetProductQueryVariables,
} from 'lib/bigcommerce/schema';
import type { RecursivePartial, RecursiveRequired } from '../utils/types';
import { productInfoFragment } from '../fragments/product';
import { BigcommerceConfig, getConfig, Images } from '..';
} from 'lib/bigcommerce/schema'
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import { productInfoFragment } from '../fragments/product'
import { BigcommerceConfig, getConfig, Images } from '..'
export const getProductQuery = /* GraphQL */ `
query getProduct(
@@ -31,55 +31,55 @@ export const getProductQuery = /* GraphQL */ `
}
${productInfoFragment}
`;
`
export interface GetProductResult<T> {
product?: T extends GetProductQuery
? Extract<T['site']['route']['node'], { __typename: 'Product' }>
: unknown;
: unknown
}
export type ProductVariables = Images &
({ path: string; slug?: never } | { path?: never; slug: string });
({ path: string; slug?: never } | { path?: never; slug: string })
async function getProduct(opts: {
query?: string;
variables: ProductVariables;
config?: BigcommerceConfig;
}): Promise<GetProductResult<GetProductQuery>>;
query?: string
variables: ProductVariables
config?: BigcommerceConfig
}): Promise<GetProductResult<GetProductQuery>>
async function getProduct<T, V = any>(opts: {
query: string;
variables: V;
config?: BigcommerceConfig;
}): Promise<GetProductResult<T>>;
query: string
variables: V
config?: BigcommerceConfig
}): Promise<GetProductResult<T>>
async function getProduct({
query = getProductQuery,
variables: { slug, ...vars },
config = getConfig(),
}: {
query?: string;
variables: ProductVariables;
config?: BigcommerceConfig;
query?: string
variables: ProductVariables
config?: BigcommerceConfig
}): Promise<GetProductResult<GetProductQuery>> {
const variables: GetProductQueryVariables = {
...config.imageVariables,
...vars,
path: slug ? `/${slug}/` : vars.path!,
};
}
const data = await config.fetch<RecursivePartial<GetProductQuery>>(query, {
variables,
});
const product = data.site?.route?.node;
})
const product = data.site?.route?.node
if (product?.__typename === 'Product') {
return {
product: product as RecursiveRequired<typeof product>,
};
}
}
return {};
return {}
}
export default getProduct;
export default getProduct

View File

@@ -1,11 +1,11 @@
import { CommerceAPIFetchOptions } from 'lib/commerce/api';
import { getConfig } from '..';
import { CommerceAPIFetchOptions } from 'lib/commerce/api'
import { getConfig } from '..'
export default async function fetchAPI<Q, V = any>(
query: string,
{ variables, preview }: CommerceAPIFetchOptions<V> = {}
): Promise<Q> {
const config = getConfig();
const config = getConfig()
const res = await fetch(config.commerceUrl + (preview ? '/preview' : ''), {
method: 'POST',
headers: {
@@ -16,12 +16,12 @@ export default async function fetchAPI<Q, V = any>(
query,
variables,
}),
});
})
const json = await res.json();
const json = await res.json()
if (json.errors) {
console.error(json.errors);
throw new Error('Failed to fetch API');
console.error(json.errors)
throw new Error('Failed to fetch API')
}
return json.data;
return json.data
}

View File

@@ -1,7 +1,7 @@
export type RecursivePartial<T> = {
[P in keyof T]?: RecursivePartial<T[P]>;
};
[P in keyof T]?: RecursivePartial<T[P]>
}
export type RecursiveRequired<T> = {
[P in keyof T]-?: RecursiveRequired<T[P]>;
};
[P in keyof T]-?: RecursiveRequired<T[P]>
}

View File

@@ -1,14 +1,14 @@
import {
CartProvider as CommerceCartProvider,
useCart as useCommerceCart,
} from 'lib/commerce/cart';
} from 'lib/commerce/cart'
export type Cart = any;
export type Cart = any
export function CartProvider({ children }) {
return <CommerceCartProvider>{children}</CommerceCartProvider>;
return <CommerceCartProvider>{children}</CommerceCartProvider>
}
export function useCart() {
return useCommerceCart<Cart>();
return useCommerceCart<Cart>()
}

View File

@@ -2,38 +2,38 @@ import {
CommerceProvider as CoreCommerceProvider,
Connector,
useCommerce as useCoreCommerce,
} from 'lib/commerce';
} from 'lib/commerce'
async function getText(res: Response) {
try {
return (await res.text()) || res.statusText;
return (await res.text()) || res.statusText
} catch (error) {
return res.statusText;
return res.statusText
}
}
async function getError(res: Response) {
if (res.headers.get('Content-Type')?.includes('application/json')) {
const data = await res.json();
return data.errors[0];
const data = await res.json()
return data.errors[0]
}
return { message: await getText(res) };
return { message: await getText(res) }
}
async function fetcher(url: string, query: string) {
const res = await fetch(url);
const res = await fetch(url)
if (res.ok) {
return res.json();
return res.json()
}
throw await getError(res);
throw await getError(res)
}
export const bigcommerce: Connector = {
locale: 'en-us',
fetcher,
};
}
// TODO: The connector should be extendable when a developer is using it
export function CommerceProvider({ children }) {
@@ -41,7 +41,7 @@ export function CommerceProvider({ children }) {
<CoreCommerceProvider connector={bigcommerce}>
{children}
</CoreCommerceProvider>
);
)
}
export const useCommerce = () => useCoreCommerce();
export const useCommerce = () => useCoreCommerce()

View File

@@ -1,105 +1,105 @@
import { useState, useCallback } from "react";
import useSWR, { mutate } from "swr";
import { useState, useCallback } from 'react'
import useSWR, { mutate } from 'swr'
async function getText(res) {
try {
return (await res.text()) || res.statusText;
return (await res.text()) || res.statusText
} catch (error) {
return res.statusText;
return res.statusText
}
}
async function getError(res) {
if (res.headers.get("Content-Type")?.includes("application/json")) {
const data = await res.json();
return data.errors[0];
if (res.headers.get('Content-Type')?.includes('application/json')) {
const data = await res.json()
return data.errors[0]
}
return { message: await getText(res) };
return { message: await getText(res) }
}
async function fetcher(url) {
const res = await fetch(url);
const res = await fetch(url)
if (res.status === 200) {
return res.json();
return res.json()
}
throw await getError(res);
throw await getError(res)
}
export function useCart() {
return useSWR("/api/cart", fetcher);
return useSWR('/api/cart', fetcher)
}
export function useAddToCart() {
const [{ addingToCart, error }, setStatus] = useState({
addingToCart: false,
});
})
const addToCart = useCallback(async ({ product }) => {
setStatus({ addingToCart: true });
setStatus({ addingToCart: true })
const res = await fetch("/api/cart", {
method: "POST",
const res = await fetch('/api/cart', {
method: 'POST',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
body: JSON.stringify({ product }),
});
})
// Product added as expected
if (res.status === 200) {
setStatus({ addingToCart: false });
return mutate("/api/cart");
setStatus({ addingToCart: false })
return mutate('/api/cart')
}
const error = await getError(res);
const error = await getError(res)
console.error("Adding product to cart failed with:", res.status, error);
setStatus({ addingToCart: false, error });
}, []);
console.error('Adding product to cart failed with:', res.status, error)
setStatus({ addingToCart: false, error })
}, [])
return { addToCart, addingToCart, error };
return { addToCart, addingToCart, error }
}
export function useUpdateCart() {
const [{ updatingCart, error }, setStatus] = useState({
updatingCart: false,
});
})
const updateCart = useCallback(async ({ product, item }) => {
setStatus({ updatingCart: true });
setStatus({ updatingCart: true })
const res = await fetch(
`/api/cart?itemId=${item.id}`,
product.quantity < 1
? { method: "DELETE" }
? { method: 'DELETE' }
: {
method: "PUT",
method: 'PUT',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
body: JSON.stringify({ product }),
}
);
)
// Product updated as expected
if (res.status === 200) {
setStatus({ updatingCart: false });
return mutate("/api/cart");
setStatus({ updatingCart: false })
return mutate('/api/cart')
}
const error = await getError(res);
const error = await getError(res)
console.error("Update to cart failed with:", res.status, error);
setStatus({ updatingCart: false, error });
}, []);
console.error('Update to cart failed with:', res.status, error)
setStatus({ updatingCart: false, error })
}, [])
return { updateCart, updatingCart, error };
return { updateCart, updatingCart, error }
}
export function useRemoveFromCart() {
const { updateCart, updatingCart, error } = useUpdateCart();
const { updateCart, updatingCart, error } = useUpdateCart()
const removeFromCart = async ({ item }) => {
updateCart({ item, product: { quantity: 0 } });
};
updateCart({ item, product: { quantity: 0 } })
}
return { removeFromCart, removingFromCart: updatingCart, error };
return { removeFromCart, removingFromCart: updatingCart, error }
}

View File

@@ -1,15 +1,15 @@
export interface CommerceAPIConfig {
commerceUrl: string;
apiToken: string;
commerceUrl: string
apiToken: string
fetch<Q, V = any>(
query: string,
queryData?: CommerceAPIFetchOptions<V>
): Promise<Q>;
): Promise<Q>
}
export interface CommerceAPIFetchOptions<V> {
variables?: V;
preview?: boolean;
variables?: V
preview?: boolean
}
// TODO: define interfaces for all the available operations

View File

@@ -1,37 +1,37 @@
import { createContext, useContext } from 'react';
import useSWR, { responseInterface } from 'swr';
import { useCommerce } from '.';
import { createContext, useContext } from 'react'
import useSWR, { responseInterface } from 'swr'
import { useCommerce } from '.'
export type Cart = any;
export type Cart = any
export type CartResponse<C extends Cart> = responseInterface<C, Error> & {
isEmpty: boolean;
};
isEmpty: boolean
}
const CartContext = createContext<CartResponse<Cart>>(null);
const CartContext = createContext<CartResponse<Cart>>(null)
function getCartCookie() {
// TODO: Figure how the cart should be persisted
return null;
return null
}
export function CartProvider({ children }) {
const { hooks, fetcher } = useCommerce<Cart>();
const { useCart } = hooks;
const cartId = getCartCookie();
const { hooks, fetcher } = useCommerce<Cart>()
const { useCart } = hooks
const cartId = getCartCookie()
const response = useSWR(
() => (cartId ? [useCart.url, useCart.query, useCart.resolver] : null),
fetcher
);
const isEmpty = true;
)
const isEmpty = true
return (
<CartContext.Provider value={{ ...response, isEmpty }}>
{children}
</CartContext.Provider>
);
)
}
export function useCart<C extends Cart>() {
return useContext(CartContext) as CartResponse<C>;
return useContext(CartContext) as CartResponse<C>
}

View File

@@ -1,29 +1,29 @@
import { createContext, ReactNode, useContext } from 'react';
import { createContext, ReactNode, useContext } from 'react'
const Commerce = createContext<Connector>(null);
const Commerce = createContext<Connector>(null)
export type CommerceProps = {
children?: ReactNode;
connector: Connector;
};
children?: ReactNode
connector: Connector
}
export type Connector = {
fetcher: Fetcher<any>;
locale: string;
};
fetcher: Fetcher<any>
locale: string
}
export type Fetcher<T> = (...args: any) => T | Promise<T>;
export type Fetcher<T> = (...args: any) => T | Promise<T>
export function CommerceProvider({ children, connector }: CommerceProps) {
if (!connector) {
throw new Error(
'CommerceProvider requires a valid headless commerce connector'
);
)
}
return <Commerce.Provider value={connector}>{children}</Commerce.Provider>;
return <Commerce.Provider value={connector}>{children}</Commerce.Provider>
}
export function useCommerce<T extends Connector>() {
return useContext(Commerce) as T;
return useContext(Commerce) as T
}