Created
May 18, 2022 17:56
-
-
Save mshick/fdca0ac96951c7ff7222751daca7af55 to your computer and use it in GitHub Desktop.
jotai-scratch
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 { atom } from 'jotai'; | |
import { atomFamily } from 'jotai/utils'; | |
import type { SetOptional } from 'type-fest'; | |
export const STORAGE_KEY = 'cart'; | |
export type CartItemKey = { | |
_key: string; | |
}; | |
export type CartItem = { | |
_key: string; | |
id: string; | |
name: string; | |
href: string; | |
color: string; | |
price: string; | |
quantity: number; | |
imageSrc: string; | |
imageAlt: string; | |
interval: 'none' | 'day' | 'week' | 'month' | 'year'; | |
intervalCount: number; | |
}; | |
export type CartItemInput = SetOptional<CartItem, '_key' | 'interval' | 'intervalCount'>; | |
export const isCartOpenAtom = atom(false); | |
export const cartCheckoutResultAtom = atom<string>(''); | |
export const cartTimeoutMsAtom = atom<number>(0); | |
export const cartItemsAtom = atom<string[]>([]); | |
export function cartItemWithDefaults(item: CartItemInput): CartItem { | |
const interval = item.interval ?? 'none'; | |
const intervalCount = item.intervalCount ?? 0; | |
const _key = [item.id, interval, intervalCount].filter((x) => x).join(':'); | |
return { | |
_key, | |
interval, | |
intervalCount, | |
...item | |
}; | |
} | |
export const cartItemAtomFamily = atomFamily( | |
(item: CartItem) => atom(item), | |
(a: CartItem, b: CartItemKey) => a._key === b._key | |
); | |
export const addCartItem = (item: CartItemInput) => { | |
return cartItemAtomFamily(cartItemWithDefaults(item)); | |
}; | |
export const getCartItem = (key: CartItemKey) => { | |
return cartItemAtomFamily(key as CartItem); | |
}; | |
export const removeCartItem = (key: CartItemKey) => { | |
cartItemAtomFamily.remove(key as CartItem); | |
}; | |
export interface CartItemsSerializeAction { | |
type: 'serialize'; | |
callback: (value: string) => void; | |
} | |
export interface CartItemsDeserializeAction { | |
type: 'deserialize'; | |
value: string; | |
} | |
export const serializeCartItemsAtom = atom<null, CartItemsSerializeAction | CartItemsDeserializeAction>( | |
null, | |
(get, set, action) => { | |
if (action.type === 'serialize') { | |
const cartItems = get(cartItemsAtom); | |
const cartItemsMap: Record<string, CartItem> = {}; | |
cartItems.forEach((_key) => { | |
cartItemsMap[_key] = get(getCartItem({ _key })); | |
}); | |
const obj = { | |
cartItems, | |
cartItemsMap | |
}; | |
action.callback(JSON.stringify(obj)); | |
} else if (action.type === 'deserialize') { | |
const obj = JSON.parse(action.value); | |
obj.cartItems.forEach((_key: string) => { | |
const cartItem = obj.cartItemsMap[_key]; | |
set(addCartItem({ _key, ...cartItem }), cartItem); | |
}); | |
set(cartItemsAtom, obj.cartItems); | |
} | |
} | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment