Polish catalog studio: undo delete, save status pill, faster totals
This commit is contained in:
1 parent
6e0ffff94b
commit
67430e7e9d
5 files changed
+187
-9
No files matched your search
@@ -2,6 +2,7 @@
|
||||
|
||||
import {
|
||||
AlertCircle,
|
||||
Check,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Languages,
|
||||
@@ -12,7 +13,7 @@ import {
|
||||
Settings,
|
||||
} from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { updateCatalogPage } from "@/actions/catalog";
|
||||
import { updateBcPage } from "@/actions/catalog-bc";
|
||||
@@ -135,6 +136,15 @@ function InlineEditorSession({
|
||||
const [page, setPage] = useState<PageDetail | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [justSaved, setJustSaved] = useState(false);
|
||||
const savedTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (savedTimer.current) clearTimeout(savedTimer.current);
|
||||
},
|
||||
[],
|
||||
);
|
||||
const [form, setForm] = useState<FormState>({});
|
||||
const [original, setOriginal] = useState<FormState>({});
|
||||
const [showTexts, setShowTexts] = useState(false);
|
||||
@@ -308,6 +318,9 @@ function InlineEditorSession({
|
||||
if (!request.isCurrent()) return;
|
||||
if (!result.ok) throw new Error(result.error || "Failed to save");
|
||||
toast.success(tActions("saved"));
|
||||
setJustSaved(true);
|
||||
if (savedTimer.current) clearTimeout(savedTimer.current);
|
||||
savedTimer.current = setTimeout(() => setJustSaved(false), 2500);
|
||||
setOriginal({ ...form });
|
||||
setPage((prev) =>
|
||||
prev
|
||||
@@ -387,14 +400,32 @@ function InlineEditorSession({
|
||||
>
|
||||
{form.pageLayout as string}
|
||||
</Badge>
|
||||
{(isDirty || offersDirty) && (
|
||||
{saving ? (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="h-4 px-1.5 text-[9px] text-[var(--admin-warning)] border-[var(--admin-warning-border)] bg-[var(--admin-warning-subtle)]"
|
||||
className="h-4 px-1.5 text-[9px] text-[var(--admin-info)] border-[var(--admin-info-border)] bg-[var(--admin-info-subtle)]"
|
||||
>
|
||||
<AlertCircle className="h-2.5 w-2.5 mr-0.5" />
|
||||
{t("unsaved")}
|
||||
<Loader2 className="h-2.5 w-2.5 mr-0.5 animate-spin" />
|
||||
{tActions("saving")}
|
||||
</Badge>
|
||||
) : justSaved && !isDirty && !offersDirty ? (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="h-4 px-1.5 text-[9px] text-[var(--admin-success)] border-[var(--admin-success-border)] bg-[var(--admin-success-subtle)]"
|
||||
>
|
||||
<Check className="h-2.5 w-2.5 mr-0.5" />
|
||||
{tActions("saved")}
|
||||
</Badge>
|
||||
) : (
|
||||
(isDirty || offersDirty) && (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="h-4 px-1.5 text-[9px] text-[var(--admin-warning)] border-[var(--admin-warning-border)] bg-[var(--admin-warning-subtle)]"
|
||||
>
|
||||
<AlertCircle className="h-2.5 w-2.5 mr-0.5" />
|
||||
{t("unsaved")}
|
||||
</Badge>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
|
||||
Reference in new issue
Block a user