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:
@@ -21,6 +21,7 @@ import {
|
||||
import { formatBytes, formatDate } from "@/lib/format";
|
||||
import type { SimilarityCheck } from "@/lib/types";
|
||||
import { useE621 } from "@/store/e621";
|
||||
import { toast } from "@/store/toasts";
|
||||
|
||||
const VIDEO_RE = /\.(mp4|webm)$/i;
|
||||
|
||||
@@ -39,12 +40,10 @@ export default function SimilarPage() {
|
||||
const [check, setCheck] = useState<SimilarityCheck | null>(null);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [percent, setPercent] = useState(0);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [dragging, setDragging] = useState(false);
|
||||
|
||||
const [iqdb, setIqdb] = useState<E621IqdbResult[] | null>(null);
|
||||
const [iqdbBusy, setIqdbBusy] = useState(false);
|
||||
const [iqdbError, setIqdbError] = useState<string | null>(null);
|
||||
const [selected, setSelected] = useState<E621IqdbResult | null>(null);
|
||||
|
||||
const configured = Boolean(credentials?.configured);
|
||||
@@ -57,10 +56,10 @@ export default function SimilarPage() {
|
||||
setFile(null);
|
||||
setIqdb(null);
|
||||
setSelected(null);
|
||||
setError(null);
|
||||
setIqdbError(null);
|
||||
if (inputRef.current) inputRef.current.value = "";
|
||||
toast.ok("Temporary copy deleted.");
|
||||
},
|
||||
onError: (error) => toast.error(errorMessage(error)),
|
||||
});
|
||||
|
||||
async function startCheck(selectedFile: File) {
|
||||
@@ -68,8 +67,6 @@ export default function SimilarPage() {
|
||||
setCheck(null);
|
||||
setIqdb(null);
|
||||
setSelected(null);
|
||||
setError(null);
|
||||
setIqdbError(null);
|
||||
setPercent(0);
|
||||
setUploading(true);
|
||||
try {
|
||||
@@ -82,7 +79,7 @@ export default function SimilarPage() {
|
||||
setCheck(data);
|
||||
void queryClient.invalidateQueries({ queryKey: ["files"] });
|
||||
} catch (err) {
|
||||
setError(errorMessage(err));
|
||||
toast.error(errorMessage(err));
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
@@ -98,7 +95,7 @@ export default function SimilarPage() {
|
||||
);
|
||||
setIqdb(results);
|
||||
} catch (err) {
|
||||
setIqdbError(e621ErrorMessage(err));
|
||||
toast.error(e621ErrorMessage(err));
|
||||
} finally {
|
||||
setIqdbBusy(false);
|
||||
}
|
||||
@@ -183,8 +180,6 @@ export default function SimilarPage() {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{error ? <p className="text-sm text-ctp-red">{error}</p> : null}
|
||||
|
||||
{check ? (
|
||||
<div className="grid gap-6 lg:grid-cols-[320px_minmax(0,1fr)]">
|
||||
<aside className="flex flex-col gap-4">
|
||||
@@ -359,8 +354,6 @@ export default function SimilarPage() {
|
||||
</Link>{" "}
|
||||
to reverse-search this image on e621.
|
||||
</p>
|
||||
) : iqdbError ? (
|
||||
<p className="mt-3 text-xs text-ctp-red">{iqdbError}</p>
|
||||
) : iqdbBusy && !iqdb ? (
|
||||
<div className="mt-3 flex justify-center py-4">
|
||||
<Spinner className="h-4 w-4" />
|
||||
|
||||
Reference in New Issue
Block a user