'use client' import { useRouter } from 'next/navigation' import { useTransition } from 'react' import { toast } from 'sonner' import type { ActionResult } from '@/lib/safe-action-shared' interface UseServerActionOptions { /** Where to redirect after a successful action (optional) */ redirectOnSuccess?: string } interface RunOptions { successMessage?: string errorMessage?: string /** Override redirect path for this specific call */ redirectTo?: string /** Called on success with the result data. Overrides default router.refresh(). */ onSuccess?: (data: Record) => void } /** * Hook that wraps a server action with loading state, toast notifications, * and optional redirect/refresh. Drop-in replacement for useAdminForm. * * @example * const { run, isPending } = useServerAction() * * // Submit * run(() => updateNews({ id, ...data }), { successMessage: 'Saved!' }) * * // Delete with redirect * run(() => deleteNews(id), { redirectTo: '/admin/news' }) */ export function useServerAction(options: UseServerActionOptions = {}) { const [isPending, startTransition] = useTransition() const router = useRouter() function run(action: () => Promise, opts: RunOptions = {}) { const { successMessage = 'Saved successfully.', errorMessage = 'An error occurred.', redirectTo, onSuccess, } = opts startTransition(async () => { try { const result = await action() if (!result || result.ok) { toast.success(successMessage) if (onSuccess) { onSuccess((result?.data ?? {}) as Record) } else { const target = redirectTo || options.redirectOnSuccess if (target) router.push(target) else router.refresh() } } else { toast.error(result.error || errorMessage) } } catch (err) { console.error('[useServerAction] Unexpected error:', err) toast.error(errorMessage) } }) } return { run, isPending } }