feat(jobs): confirm-before-download dialog so users see what's happening
Files were grabbed via a plain anchor with the 'download' attribute, so clicking the icon just spawned a silent browser download — nothing in the UI moved, and users (especially labs receiving scans) couldn't tell whether the click registered. Wrapped the download button in a confirm dialog that mirrors the existing delete flow: title 'Dosya indirilsin mi?', filename + size in the body, Vazgeç / İndir buttons. The 'İndir' button programmatically clicks a hidden anchor pointing at the /api/.../download proxy and surfaces a 'İndirme başladı.' toast with the filename so there's a clear visual ack even before the OS download tray pops.
This commit is contained in:
@@ -242,6 +242,7 @@ function FileRow({ file }: { file: JobFileWithUrl }) {
|
|||||||
);
|
);
|
||||||
const [, startTransition] = useTransition();
|
const [, startTransition] = useTransition();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
const [downloadOpen, setDownloadOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.ok) {
|
if (state.ok) {
|
||||||
@@ -252,6 +253,20 @@ function FileRow({ file }: { file: JobFileWithUrl }) {
|
|||||||
}
|
}
|
||||||
}, [state]);
|
}, [state]);
|
||||||
|
|
||||||
|
function triggerDownload() {
|
||||||
|
// Use a programmatic anchor click — the server route streams the file
|
||||||
|
// with Content-Disposition: attachment, so the browser hands it straight
|
||||||
|
// to the download manager. Toast confirms it left our side.
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = file.url;
|
||||||
|
a.download = file.name;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
setDownloadOpen(false);
|
||||||
|
toast.success("İndirme başladı.", { description: file.name });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="flex items-center gap-3 px-3 py-2">
|
<li className="flex items-center gap-3 px-3 py-2">
|
||||||
<span className="text-muted-foreground">{kindIcon(file.kind)}</span>
|
<span className="text-muted-foreground">{kindIcon(file.kind)}</span>
|
||||||
@@ -264,11 +279,31 @@ function FileRow({ file }: { file: JobFileWithUrl }) {
|
|||||||
<Badge variant="outline" className="hidden sm:inline-flex">
|
<Badge variant="outline" className="hidden sm:inline-flex">
|
||||||
{JOB_FILE_KIND_LABELS[file.kind] ?? file.kind}
|
{JOB_FILE_KIND_LABELS[file.kind] ?? file.kind}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Button asChild size="sm" variant="outline">
|
<Dialog open={downloadOpen} onOpenChange={setDownloadOpen}>
|
||||||
<a href={file.url} target="_blank" rel="noopener noreferrer" download={file.name}>
|
<Button size="sm" variant="outline" onClick={() => setDownloadOpen(true)}>
|
||||||
<Download className="size-4" />
|
<Download className="size-4" />
|
||||||
</a>
|
</Button>
|
||||||
</Button>
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Dosya indirilsin mi?</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
<span className="font-medium">{file.name}</span>
|
||||||
|
<span className="text-muted-foreground"> · {formatSize(file.size)}</span>
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<DialogFooter>
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button type="button" variant="outline">
|
||||||
|
Vazgeç
|
||||||
|
</Button>
|
||||||
|
</DialogClose>
|
||||||
|
<Button type="button" onClick={triggerDownload}>
|
||||||
|
<Download className="size-4" />
|
||||||
|
İndir
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<Button size="sm" variant="outline" onClick={() => setOpen(true)}>
|
<Button size="sm" variant="outline" onClick={() => setOpen(true)}>
|
||||||
<Trash2 className="size-4" />
|
<Trash2 className="size-4" />
|
||||||
|
|||||||
Reference in New Issue
Block a user