41 lines
1.5 KiB
TypeScript
41 lines
1.5 KiB
TypeScript
import { useCallback, useRef } from 'react';
|
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
import { useClient } from 'hooks/useClient';
|
|
import { useAuth } from 'hooks/useAuth';
|
|
import type { UserState } from './types/user-settings';
|
|
|
|
const QUERY_KEY = ['USER_STATE'];
|
|
|
|
export function useUserState<T>(key: string, defaultValue: T): [T, (value: T | ((prev: T) => T)) => void, boolean] {
|
|
const client = useClient();
|
|
const { isAuthenticated } = useAuth();
|
|
const queryClient = useQueryClient();
|
|
const clientRef = useRef(client);
|
|
clientRef.current = client;
|
|
|
|
const { data: state = {}, isSuccess } = useQuery<UserState>({
|
|
queryKey: QUERY_KEY,
|
|
enabled: isAuthenticated,
|
|
queryFn: () => client.get<UserState>('/user/state'),
|
|
staleTime: Infinity,
|
|
});
|
|
|
|
const value = key in state ? (state[key] as T) : defaultValue;
|
|
|
|
const setValue = useCallback(
|
|
(update: T | ((prev: T) => T)) => {
|
|
const currentState = queryClient.getQueryData<UserState>(QUERY_KEY) ?? {};
|
|
const currentValue = key in currentState ? (currentState[key] as T) : defaultValue;
|
|
const newValue = typeof update === 'function' ? (update as (prev: T) => T)(currentValue) : update;
|
|
|
|
queryClient.setQueryData(QUERY_KEY, { ...currentState, [key]: newValue });
|
|
|
|
// Immediate fire-and-forget PATCH
|
|
clientRef.current.patch('/user/state', { [key]: newValue }).catch(() => {});
|
|
},
|
|
[key, defaultValue, queryClient],
|
|
);
|
|
|
|
return [value, setValue, isSuccess];
|
|
}
|