feat(admin): reorganize housekeeping and strengthen shared workflows
CI / check (push) Successful in 1m5s
CI / deploy (push) Successful in 1m4s

This commit is contained in:
Simo committed 2026-09-06 17:17:30 +02:00
1 parent 35f66d879f
commit a070004e7b
35 files changed
+1667 -462

No files matched your search

+20 -5
View File
@@ -1,7 +1,8 @@
"use client";
import { useRouter } from "next/navigation";
import { useTransition } from "react";
import { useTranslations } from "next-intl";
import { useRef, useState, useTransition } from "react";
import { toast } from "sonner";
import type { ActionResult } from "@/lib/safe-action-shared";
@@ -35,13 +36,19 @@ interface RunOptions {
* run(() => deleteNews(id), { redirectTo: '/admin/news' })
*/
export function useServerAction(options: UseServerActionOptions = {}) {
const t = useTranslations("pages.admin.actions");
const locked = useRef(false);
const [fieldErrors, setFieldErrors] = useState<Record<string, string[]>>({});
const [isPending, startTransition] = useTransition();
const router = useRouter();
function run(action: () => Promise<unknown>, opts: RunOptions = {}) {
if (locked.current) return;
locked.current = true;
setFieldErrors({});
const {
successMessage = "Saved successfully.",
errorMessage = "An error occurred.",
successMessage = t("saved"),
errorMessage = t("error"),
redirectTo,
onSuccess,
onError,
@@ -61,16 +68,24 @@ export function useServerAction(options: UseServerActionOptions = {}) {
else router.refresh();
}
} else {
toast.error(result.error || errorMessage);
setFieldErrors(result.fieldErrors ?? {});
toast.error(result.error || errorMessage, {
description:
Object.values(result.fieldErrors ?? {})
.flat()
.join(" · ") || undefined,
});
onError?.();
}
} catch (err) {
console.error("[useServerAction] Unexpected error:", err);
toast.error(errorMessage);
onError?.();
} finally {
locked.current = false;
}
});
}
return { run, isPending };
return { run, isPending, fieldErrors };
}