Toast action results and confirm destructive actions in one dialog
Inline banners and per-row status text reported action results all over the app; they are replaced by a small toast stack (bottom-right, Level 3 floating well styling) that only speaks for actions: successes fade, errors stay until dismissed, and form-field validation stays inline. Destructive actions no longer use bespoke inline confirm steps (the library detail's Confirm delete button) or fire immediately (duplicate copies/items, delete page selections, temp cleanup, upload discard, job cancellation): they all go through one promise-based confirm dialog (confirmAction) with a danger variant, Escape/backdrop to cancel.
This commit is contained in:
@@ -34,7 +34,9 @@ import type {
|
||||
TempUpload,
|
||||
} from "@/lib/types";
|
||||
import { useAuth } from "@/store/auth";
|
||||
import { confirmAction } from "@/store/confirm";
|
||||
import { useE621 } from "@/store/e621";
|
||||
import { toast } from "@/store/toasts";
|
||||
|
||||
type UploadStatus = "queued" | "uploading" | "done" | "error";
|
||||
|
||||
@@ -241,7 +243,7 @@ function MetadataModal({
|
||||
void queryClient.invalidateQueries({ queryKey: ["files"] });
|
||||
onClose();
|
||||
} catch (err) {
|
||||
setError(describeError(err));
|
||||
toast.error(describeError(err));
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
@@ -284,11 +286,22 @@ function MetadataModal({
|
||||
});
|
||||
}
|
||||
|
||||
function discardUpload() {
|
||||
void api(`/api/uploads/${temp.temp_id}/`, { method: "DELETE" }).then(() => {
|
||||
void queryClient.invalidateQueries({ queryKey: ["uploads"] });
|
||||
onClose();
|
||||
async function discardUpload() {
|
||||
const confirmed = await confirmAction({
|
||||
title: "Discard this upload?",
|
||||
description: `${temp.original_filename} is deleted from the staging folder; it never entered the library.`,
|
||||
confirmLabel: "Discard",
|
||||
danger: true,
|
||||
});
|
||||
if (!confirmed) return;
|
||||
try {
|
||||
await api(`/api/uploads/${temp.temp_id}/`, { method: "DELETE" });
|
||||
void queryClient.invalidateQueries({ queryKey: ["uploads"] });
|
||||
toast.ok("Upload discarded.");
|
||||
onClose();
|
||||
} catch (error) {
|
||||
toast.error(errorMessage(error));
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -416,7 +429,7 @@ function MetadataModal({
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={discardUpload}
|
||||
onClick={() => void discardUpload()}
|
||||
className="mt-2 rounded-md px-1.5 py-0.5 font-mono text-[10px] text-ctp-red transition hover:bg-ctp-red/15"
|
||||
>
|
||||
discard this upload
|
||||
@@ -591,9 +604,7 @@ function MetadataModal({
|
||||
)}
|
||||
|
||||
{error ? (
|
||||
<p className="rounded-md border border-ctp-red/30 bg-ctp-red/10 px-3 py-2 text-sm text-ctp-red">
|
||||
{error}
|
||||
</p>
|
||||
<p className="text-xs text-ctp-red">{error}</p>
|
||||
) : null}
|
||||
{busy ? (
|
||||
<p className="flex items-center gap-2 text-xs text-ctp-overlay0">
|
||||
|
||||
Reference in New Issue
Block a user