feat: toast popup for save status — 'Сохранено' or error, no layout jump

This commit is contained in:
2026-03-24 22:55:13 +03:00
parent 8ecebe686c
commit eb6ec5aeb6
2 changed files with 20 additions and 5 deletions

View File

@@ -51,6 +51,7 @@ export function SectionEditor<T>({
} catch { } catch {
setStatus("error"); setStatus("error");
setError("Ошибка сохранения"); setError("Ошибка сохранения");
setTimeout(() => setStatus((s) => (s === "error" ? "idle" : s)), 4000);
} }
}, [sectionKey]); }, [sectionKey]);

View File

@@ -416,6 +416,7 @@ export default function OpenDayAdminPage() {
const [classes, setClasses] = useState<OpenDayClass[]>([]); const [classes, setClasses] = useState<OpenDayClass[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const [saveStatus, setSaveStatus] = useState<"idle" | "saved" | "error">("idle");
const [trainers, setTrainers] = useState<string[]>([]); const [trainers, setTrainers] = useState<string[]>([]);
const [styles, setStyles] = useState<string[]>([]); const [styles, setStyles] = useState<string[]>([]);
const [halls, setHalls] = useState<string[]>([]); const [halls, setHalls] = useState<string[]>([]);
@@ -455,12 +456,18 @@ export default function OpenDayAdminPage() {
if (saveTimerRef.current) clearTimeout(saveTimerRef.current); if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
saveTimerRef.current = setTimeout(async () => { saveTimerRef.current = setTimeout(async () => {
setSaving(true); setSaving(true);
await adminFetch("/api/admin/open-day", { try {
method: "PUT", const res = await adminFetch("/api/admin/open-day", {
headers: { "Content-Type": "application/json" }, method: "PUT",
body: JSON.stringify(updated), headers: { "Content-Type": "application/json" },
}); body: JSON.stringify(updated),
});
setSaveStatus(res.ok ? "saved" : "error");
} catch {
setSaveStatus("error");
}
setSaving(false); setSaving(false);
setTimeout(() => setSaveStatus("idle"), 2000);
}, 800); }, 800);
}, },
[] []
@@ -528,6 +535,13 @@ export default function OpenDayAdminPage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
{saveStatus !== "idle" && (
<div className={`fixed bottom-4 right-4 z-50 flex items-center gap-2 rounded-lg border px-3 py-2 text-sm shadow-lg animate-in slide-in-from-right ${
saveStatus === "saved" ? "bg-emerald-950/90 border-emerald-500/30 text-emerald-200" : "bg-red-950/90 border-red-500/30 text-red-200"
}`}>
{saveStatus === "saved" ? "Сохранено" : "Ошибка сохранения"}
</div>
)}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h1 className="text-2xl font-bold">День открытых дверей</h1> <h1 className="text-2xl font-bold">День открытых дверей</h1>