Created
September 12, 2021 19:16
-
-
Save Brettm12345/16864cc03bbb1a805f32f2bb53dcd066 to your computer and use it in GitHub Desktop.
Discount Provider With fp-ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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