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 [open, setOpen] = useState(false);
|
||||
const [downloadOpen, setDownloadOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (state.ok) {
|
||||
@@ -252,6 +253,20 @@ function FileRow({ file }: { file: JobFileWithUrl }) {
|
||||
}
|
||||
}, [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 (
|
||||
<li className="flex items-center gap-3 px-3 py-2">
|
||||
<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">
|
||||
{JOB_FILE_KIND_LABELS[file.kind] ?? file.kind}
|
||||
</Badge>
|
||||
<Button asChild size="sm" variant="outline">
|
||||
<a href={file.url} target="_blank" rel="noopener noreferrer" download={file.name}>
|
||||
<Dialog open={downloadOpen} onOpenChange={setDownloadOpen}>
|
||||
<Button size="sm" variant="outline" onClick={() => setDownloadOpen(true)}>
|
||||
<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}>
|
||||
<Button size="sm" variant="outline" onClick={() => setOpen(true)}>
|
||||
<Trash2 className="size-4" />
|
||||
|
||||
Reference in New Issue
Block a user