forked from crowetic/commerce
First try at trying to create extendable hooks
This commit is contained in:
parent
4387358451
commit
381b19e820
13
lib/bigcommerce/cart.tsx
Normal file
13
lib/bigcommerce/cart.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import {
|
||||||
|
CartProvider as CommerceCartProvider,
|
||||||
|
useCart as useCommerceCart,
|
||||||
|
} from '../commerce/cart';
|
||||||
|
import { Cart } from './index';
|
||||||
|
|
||||||
|
export function CartProvider({ children }) {
|
||||||
|
return <CommerceCartProvider>{children}</CommerceCartProvider>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCart() {
|
||||||
|
return useCommerceCart<Cart>();
|
||||||
|
}
|
78
lib/bigcommerce/index.tsx
Normal file
78
lib/bigcommerce/index.tsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import {
|
||||||
|
CommerceProvider,
|
||||||
|
Connector,
|
||||||
|
HookResolver,
|
||||||
|
useCommerce as useComm,
|
||||||
|
} from '../commerce';
|
||||||
|
|
||||||
|
export type Cart = any;
|
||||||
|
|
||||||
|
async function getText(res: Response) {
|
||||||
|
try {
|
||||||
|
return (await res.text()) || res.statusText;
|
||||||
|
} catch (error) {
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
return { message: await getText(res) };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetcher(
|
||||||
|
url: string,
|
||||||
|
query: string,
|
||||||
|
resolver: HookResolver<Cart>
|
||||||
|
) {
|
||||||
|
const res = await fetch(url);
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw await getError(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const bigcommerce: Connector<Cart> = {
|
||||||
|
hooks: {
|
||||||
|
useCart: {
|
||||||
|
query: '',
|
||||||
|
resolver() {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
useAddItem: {
|
||||||
|
query: '',
|
||||||
|
resolver() {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
useUpdateItem: {
|
||||||
|
query: '',
|
||||||
|
resolver() {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
useRemoveItem: {
|
||||||
|
query: '',
|
||||||
|
resolver() {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
locale: 'en-us',
|
||||||
|
fetcher,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: The connector should be extendable when a developer is using it
|
||||||
|
export function BigcommerceProvider({ children }) {
|
||||||
|
return (
|
||||||
|
<CommerceProvider connector={bigcommerce}>{children}</CommerceProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCommerce = () => useComm<Cart>();
|
35
lib/commerce/cart.tsx
Normal file
35
lib/commerce/cart.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { createContext, useContext } from 'react';
|
||||||
|
import useSWR, { responseInterface } from 'swr';
|
||||||
|
import { Cart, useCommerce } from '.';
|
||||||
|
|
||||||
|
export type CartResponse<C extends Cart> = responseInterface<C, Error> & {
|
||||||
|
isEmpty: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CartContext = createContext<CartResponse<Cart>>(null);
|
||||||
|
|
||||||
|
function getCartCookie() {
|
||||||
|
// TODO: Figure how the cart should be persisted
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CartProvider({ children }) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CartContext.Provider value={{ ...response, isEmpty }}>
|
||||||
|
{children}
|
||||||
|
</CartContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCart<C extends Cart>() {
|
||||||
|
return useContext(CartContext) as CartResponse<C>;
|
||||||
|
}
|
53
lib/commerce/index.tsx
Normal file
53
lib/commerce/index.tsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { createContext, ReactNode, useContext } from 'react';
|
||||||
|
|
||||||
|
const Commerce = createContext<Connector<any>>(null);
|
||||||
|
|
||||||
|
export type Cart = any;
|
||||||
|
|
||||||
|
export type CommerceProps<C extends Cart> = {
|
||||||
|
children?: ReactNode;
|
||||||
|
connector: Connector<C>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Connector<C extends Cart> = {
|
||||||
|
hooks: {
|
||||||
|
useCart: Hook<C>;
|
||||||
|
useAddItem: Hook<C>;
|
||||||
|
useUpdateItem: Hook<C>;
|
||||||
|
useRemoveItem: Hook<C>;
|
||||||
|
};
|
||||||
|
fetcher: Fetcher<any>;
|
||||||
|
locale: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Hook<T extends any> = {
|
||||||
|
query?: string;
|
||||||
|
url?: string;
|
||||||
|
resolver: HookResolver<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HookResolver<T> = (
|
||||||
|
fetcher: Fetcher<T>,
|
||||||
|
context: ResolverContext
|
||||||
|
) => T | Promise<T>;
|
||||||
|
|
||||||
|
export type Fetcher<T> = (...args: any) => T | Promise<T>;
|
||||||
|
|
||||||
|
export type ResolverContext = {
|
||||||
|
query?: string;
|
||||||
|
locale: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function CommerceProvider({ children, connector }: CommerceProps<Cart>) {
|
||||||
|
if (!connector) {
|
||||||
|
throw new Error(
|
||||||
|
'CommerceProvider requires a valid headless commerce connector'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Commerce.Provider value={connector}>{children}</Commerce.Provider>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCommerce<C extends Cart>() {
|
||||||
|
return useContext(Commerce) as Connector<C>;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user