All files / packages/app/providers stored-data.tsx

100% Statements 35/35
100% Branches 0/0
95.45% Functions 21/22
100% Lines 34/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103                    332x 10504x                       332x     7904x 7904x 7904x 326x     6898x 1313x   7904x 1313x   7904x   10504x 993x 12803x         12803x 12803x         7904x   10504x 2x   2x 2x         7904x   7904x 10504x       7904x   7904x 10504x       7904x   7904x   60472x 60472x       7904x     7904x                        
import React from "react";
 
import { fromEntries, keys } from "remeda";
 
import { StoreContext } from "~app/contexts/store-context";
import { StoreDataContext } from "~app/contexts/store-data-context";
import type { StoreStates, StoreValues } from "~app/utils/store-data";
import { getStoreStatesFromValues, schemas } from "~app/utils/store-data";
import { updateSetStateAction } from "~utils/react";
 
const resolveState = (values: StoreValues) =>
	fromEntries(keys(schemas).map((key) => [key, values[key]])) as StoreValues;
 
type SetValues = {
	[K in keyof StoreStates]: StoreStates[K][1];
};
 
type DeleteValues = {
	[K in keyof StoreStates]: StoreStates[K][2];
};
 
type StoreKey = keyof StoreStates;
 
export const StoredDataProvider: React.FC<React.PropsWithChildren> = ({
	children,
}) => {
	const { setItem, deleteItem, getInitialItems } = React.use(StoreContext);
	const initialItems = getInitialItems();
	const mounted = React.useSyncExternalStore(
		() => () => {
			/* empty */
		},
		() => true,
		() => false,
	);
	const [ssrState, setSsrState] = React.useState<StoreValues>(() =>
		resolveState(initialItems),
	);
	const updateValue = React.useCallback(
		<K extends StoreKey>(key: K) =>
			(setStateAction: React.SetStateAction<(typeof ssrState)[K]>) => {
				setSsrState((prevState) => {
					const nextState = updateSetStateAction(
						setStateAction,
						prevState[key],
					);
					// Updating a store value and updating local state in the same time
					setItem(key, nextState);
					return { ...prevState, [key]: nextState };
				});
			},
		[setItem],
	);
	const deleteValue = React.useCallback(
		<K extends StoreKey>(key: K) =>
			() => {
				setSsrState((prevState) => {
					// Removing a store value and updating local state in the same time
					deleteItem(key);
					return { ...prevState, [key]: schemas[key].parse(undefined) };
				});
			},
		[deleteItem],
	);
	const ssrSetValues = React.useMemo<SetValues>(
		() =>
			fromEntries(
				keys(schemas).map((key) => [key, updateValue(key)]),
			) as SetValues,
		[updateValue],
	);
	const ssrDeleteValues = React.useMemo<DeleteValues>(
		() =>
			fromEntries(
				keys(schemas).map((key) => [key, deleteValue(key)]),
			) as DeleteValues,
		[deleteValue],
	);
	const ssrStates = React.useMemo(
		() =>
			getStoreStatesFromValues(
				ssrState,
				(key) => ssrSetValues[key],
				(key) => ssrDeleteValues[key],
			),
		[ssrState, ssrSetValues, ssrDeleteValues],
	);
	return (
		<StoreDataContext
			value={React.useMemo(
				() => ({
					isFirstRender: !mounted,
					nowTimestamp: initialItems.nowTimestamp,
					...ssrStates,
				}),
				[ssrStates, initialItems.nowTimestamp, mounted],
			)}
		>
			{children}
		</StoreDataContext>
	);
};