import { useQuery, useMutation, useQueryClient, useInfiniteQuery, } from "@tanstack/react-query"; import { apiClient, Trigger, CreateTriggerPayload } from "@/lib/api"; export const triggerKeys = { all: () => ["triggers"] as const, lists: () => [...triggerKeys.all(), "list"] as const, list: (filters?: TriggerFilters) => [...triggerKeys.lists(), filters] as const, detail: (id: string) => [...triggerKeys.all(), "detail", id] as const, }; interface TriggerFilters { from?: string; // ISO date to?: string; // ISO date limit?: number; } // Queries // Fetch a paginated list of mood entries. // On cold start, returns cached data instantly then revalidates. export const useTriggers = (filters?: TriggerFilters) => { return useQuery({ queryKey: triggerKeys.list(filters), queryFn: () => apiClient.getTriggers(filters), }); }; // Single entry detail export const useTrigger = (id: string) => { return useQuery({ queryKey: triggerKeys.detail(id), queryFn: () => apiClient.getTrigger(id), enabled: !!id, }); }; // MUTATIONS // Create a new mood entry // Optimistically adds to cache, rolls back on failure export const useCreateTrigger = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: (payload: CreateTriggerPayload) => apiClient.createTrigger(payload), // Optimistic update so that the UI reflects the new entry immediately onMutate: async (payload) => { // Cancel any in-flight refetches so they don't overwrite our optimistic update await queryClient.cancelQueries({ queryKey: triggerKeys.lists() }); // Snapshot current cache so we can roll back const previous = queryClient.getQueryData(triggerKeys.list()); // Inject a temporary optimistic record // TODO: might as well create a shared attrs that we're keeping it queryClient.setQueryData(triggerKeys.list(), (old: Trigger[] = []) => [ { ...payload, id: `temp-${Date.now()}`, createdAt: new Date().toISOString(), _optimistic: true, }, ...old, ]); return { previous }; }, // On error, roll back to the snapshot onError: (_err, _payload, context) => { if (context?.previous) { queryClient.setQueryData(triggerKeys.list(), context.previous); } }, // On success, replace optimistic record with real one from server onSuccess: () => { queryClient.invalidateQueries({ queryKey: triggerKeys.lists() }); }, }); }; // Delete a mood entry with optimistic removal export const useDeleteTrigger = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => apiClient.deleteTrigger(id), onMutate: async (id) => { await queryClient.cancelQueries({ queryKey: triggerKeys.lists() }); const previous = queryClient.getQueryData(triggerKeys.list()); queryClient.setQueryData(triggerKeys.list(), (old: Trigger[] = []) => old.filter((e) => e.id !== id), ); return { previous }; }, onError: (_err, _id, context) => { if (context?.previous) { queryClient.setQueryData(triggerKeys.list(), context.previous); } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: triggerKeys.lists() }); }, }); };