Files
EpicNext-Cms/src/hooks/use-server-action.ts
T
SimoandCursor b52e25578d
Local Build and Deploy / deploy (push) Successful in 1m18s
Harden catalog admin: fix translate/quick-add, RCON sync, and confirm UX.
Restore broken Quick Add search, correct Translate saves to items_base and FurnitureData, reparent page deletes, sync RCON on create/toggle/BC mutations, and replace native confirms/prompts with dialogs.

Co-authored-by: Cursor <[email protected]>
2026-07-17 21:12:58 +02:00

77 lines
2.1 KiB
TypeScript

"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<string, unknown>) => void;
/** Called when the action fails or throws */
onError?: () => 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<unknown>, opts: RunOptions = {}) {
const {
successMessage = "Saved successfully.",
errorMessage = "An error occurred.",
redirectTo,
onSuccess,
onError,
} = opts;
startTransition(async () => {
try {
const result = (await action()) as ActionResult | undefined;
if (!result || result.ok) {
toast.success(successMessage);
if (onSuccess) {
onSuccess((result?.data ?? {}) as Record<string, unknown>);
} else {
const target = redirectTo || options.redirectOnSuccess;
if (target) router.push(target);
else router.refresh();
}
} else {
toast.error(result.error || errorMessage);
onError?.();
}
} catch (err) {
console.error("[useServerAction] Unexpected error:", err);
toast.error(errorMessage);
onError?.();
}
});
}
return { run, isPending };
}