'use client'; import { useOptimistic, useTransition } from 'react'; /** * Hook for optimistic updates with automatic rollback on error. * Uses React 19's useOptimistic + startTransition pattern. * * @example * const { optimisticData, isPending, mutate } = useOptimisticMutation( * tastings, * async (newTasting) => await saveTasting(newTasting) * ); */ export function useOptimisticMutation( initialData: T[], mutationFn: (input: TInput) => Promise<{ success: boolean; error?: string }> ) { const [isPending, startTransition] = useTransition(); const [optimisticData, addOptimistic] = useOptimistic( initialData, (currentData, newItem) => [...currentData, newItem as unknown as T] ); const mutate = async (input: TInput, optimisticValue: T) => { startTransition(async () => { // Immediately show optimistic update addOptimistic(input); // Perform actual mutation const result = await mutationFn(input); if (!result.success) { console.error('[OptimisticMutation] Failed:', result.error); // Note: React will automatically rollback on error } }); }; return { optimisticData, isPending, mutate, }; } /** * Simple optimistic state for single values (like ratings). */ export function useOptimisticValue( serverValue: T, updateFn: (value: T) => Promise<{ success: boolean }> ) { const [isPending, startTransition] = useTransition(); const [optimisticValue, setOptimistic] = useOptimistic(serverValue); const setValue = (value: T) => { startTransition(async () => { setOptimistic(value); await updateFn(value); }); }; return { value: optimisticValue, isPending, setValue, }; }