Skip to content

Instantly share code, notes, and snippets.

@Brettm12345
Created September 12, 2021 19:16
Show Gist options
  • Save Brettm12345/16864cc03bbb1a805f32f2bb53dcd066 to your computer and use it in GitHub Desktop.
Save Brettm12345/16864cc03bbb1a805f32f2bb53dcd066 to your computer and use it in GitHub Desktop.
Discount Provider With fp-ts
import {AllDiscountsQuery, useAllDiscountsQuery} from '../../generated/graphql';
import * as A from 'fp-ts/Array';
import * as O from 'fp-ts/Option';
import {flow, pipe} from 'fp-ts/function';
import constate from 'constate';
import {ApolloError} from '@apollo/client';
type ProductType = 'variant' | 'product';
type Discount<
T extends keyof AllDiscountsQuery['discounts'][0]
> = AllDiscountsQuery['discounts'][0][T][0];
type DiscountProductKey =
| 'bogo_buy'
| 'bogo_buy_variants'
| 'products'
| 'product_variants';
const variantKeys: DiscountProductKey[] = [
'bogo_buy_variants',
'product_variants',
];
const productKeys: DiscountProductKey[] = ['products', 'bogo_buy'];
type DiscountItem = Discount<DiscountProductKey>;
const discountEq = (id: number) => (item: DiscountItem): boolean =>
item.id === id;
const filterDiscounts = (id: number) => (
items: DiscountItem[]
): DiscountItem[] => items.filter(discountEq(id));
const checkDiscounts = (id: number) =>
flow(filterDiscounts(id), xs => xs.length > 0);
const any = (xs: boolean[]): boolean => xs.includes(true);
const hasDiscount = (id: number, type: ProductType) => (
discount: AllDiscountsQuery['discounts'][0]
) => {
const has = (key: DiscountProductKey) =>
pipe(discount[key], checkDiscounts(id));
type FilterByKeys = <A extends DiscountProductKey>(
keys: A[]
) => (discount: AllDiscountsQuery['discounts'][0]) => boolean;
const filterByKeys: FilterByKeys = keys => discount =>
pipe(keys.map(has), any);
const keys = type === 'variant' ? variantKeys : productKeys;
return pipe(discount, filterByKeys(keys));
};
type FindDiscountFn = (id: number) => AllDiscountsQuery['discounts'][0];
interface UseDiscountReturn {
byProduct: FindDiscountFn;
byVariant: FindDiscountFn;
loading: boolean;
error?: ApolloError;
}
export const useDiscountsState = (): UseDiscountReturn => {
const {data, loading, error} = useAllDiscountsQuery();
const findDiscount = (id: number, type: ProductType) =>
pipe(data.discounts, A.findFirst(hasDiscount(id, type)), O.toNullable);
const byVariant = (id: number) => findDiscount(id, 'variant');
const byProduct = (id: number) => findDiscount(id, 'product');
return {
byProduct,
byVariant,
loading,
error,
};
};
export const [CartProvider, useDiscounts] = constate(useDiscountsState);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment