feat(download): show a toast + button check when a file is saved

The desktop (Tauri) app has no native download UI, so FileSaver.saveAs saved
files silently — no visual or audio confirmation. Users re-clicked because
nothing said it worked (one report: 5 copies of the same file). Add a small
useSaveFile() hook that saves AND raises a 'Downloaded <filename>' toast, and
route every download call site through it (file attachments, image viewer, PDF
viewer, plus the recovery-key / key-backup exports). The file-message download
button also shows a green check on success.

Toast system extended with an optional iconSrc so system toasts render an icon
instead of an avatar/initials, and an empty roomName is no longer rendered.

Tests: createDownloadToast covered; 701/701 pass; typecheck + build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 22:30:57 -04:00
parent f12175e76f
commit fd9e4a9802
10 changed files with 91 additions and 23 deletions
@@ -1,8 +1,8 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import FileSaver from 'file-saver';
import classNames from 'classnames';
import { Box, Chip, Header, Icon, IconButton, Icons, Text, as } from 'folds';
import { useSaveFile } from '../../hooks/useSaveFile';
import * as css from './ImageViewer.css';
import { useZoom } from '../../hooks/useZoom';
import { usePan } from '../../hooks/usePan';
@@ -17,12 +17,13 @@ export type ImageViewerProps = {
export const ImageViewer = as<'div', ImageViewerProps>(
({ className, alt, src, requestClose, ...props }, ref) => {
const { t } = useTranslation();
const saveFile = useSaveFile();
const { zoom, zoomIn, zoomOut, setZoom } = useZoom(0.2);
const { pan, cursor, onMouseDown } = usePan(zoom !== 1);
const handleDownload = async () => {
const fileContent = await downloadMedia(src);
FileSaver.saveAs(fileContent, alt);
saveFile(fileContent, alt);
};
return (