Skip to content

Instantly share code, notes, and snippets.

@mshick
Created May 18, 2022 17:56
Show Gist options
  • Save mshick/fdca0ac96951c7ff7222751daca7af55 to your computer and use it in GitHub Desktop.
Save mshick/fdca0ac96951c7ff7222751daca7af55 to your computer and use it in GitHub Desktop.
jotai-scratch
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