diff --git a/job-tracker-ui/src/components/Attachments.tsx b/job-tracker-ui/src/components/Attachments.tsx index ab3d300..beffe20 100644 --- a/job-tracker-ui/src/components/Attachments.tsx +++ b/job-tracker-ui/src/components/Attachments.tsx @@ -26,8 +26,9 @@ import DownloadIcon from "@mui/icons-material/Download"; import VisibilityOutlinedIcon from "@mui/icons-material/VisibilityOutlined"; import CloudUploadOutlinedIcon from "@mui/icons-material/CloudUploadOutlined"; -import { api } from "../api"; +import { api, getApiErrorMessage } from "../api"; import { useToast } from "../toast"; +import { useI18n } from "../i18n/I18nProvider"; import { useDialogActions } from "../dialogs"; interface AttachmentItem { @@ -63,6 +64,7 @@ function guessKind(fileName: string): string { export default function Attachments({ jobId }: { jobId: number }) { const { toast } = useToast(); + const { t } = useI18n(); const { confirmAction, promptForValue } = useDialogActions(); const [items, setItems] = useState([]); const [previewOpen, setPreviewOpen] = useState(false); @@ -105,13 +107,13 @@ export default function Attachments({ jobId }: { jobId: number }) { }); toast(files.length === 1 ? "File uploaded." : `${files.length} files uploaded.`, "success"); await load(); - } catch { - toast("Upload failed.", "error"); + } catch (error) { + toast(getApiErrorMessage(error, t("attachmentsUploadFailed")), "error"); } finally { setUploading(false); } }, - [jobId, load, toast], + [jobId, load, t, toast], ); const rename = async (a: AttachmentItem) => { @@ -119,10 +121,10 @@ export default function Attachments({ jobId }: { jobId: number }) { if (!next || next.trim() === a.fileName) return; try { await api.patch(`/attachments/${a.id}`, { fileName: next.trim() }); - toast("Renamed.", "success"); + toast(t("attachmentsRenamed"), "success"); await load(); - } catch { - toast("Rename failed.", "error"); + } catch (error) { + toast(getApiErrorMessage(error, t("attachmentsRenameFailed")), "error"); } }; @@ -130,10 +132,10 @@ export default function Attachments({ jobId }: { jobId: number }) { if (!(await confirmAction(`Delete attachment "${a.fileName}"?`, { title: "Delete attachment", confirmLabel: "Delete", destructive: true }))) return; try { await api.delete(`/attachments/${a.id}`); - toast("Deleted attachment.", "success"); + toast(t("attachmentsDeleted"), "success"); await load(); - } catch { - toast("Delete failed.", "error"); + } catch (error) { + toast(getApiErrorMessage(error, t("attachmentsDeleteFailed")), "error"); } }; @@ -159,8 +161,8 @@ export default function Attachments({ jobId }: { jobId: number }) { link.click(); link.remove(); window.setTimeout(() => URL.revokeObjectURL(url), 5000); - } catch { - toast("Download failed.", "error"); + } catch (error) { + toast(getApiErrorMessage(error, t("attachmentsDownloadFailed")), "error"); } }; @@ -170,8 +172,8 @@ export default function Attachments({ jobId }: { jobId: number }) { const url = await getBlobUrl(a.id); setPreview({ url, type: a.fileType || "", name: a.fileName }); setPreviewOpen(true); - } catch { - toast("Preview failed.", "error"); + } catch (error) { + toast(getApiErrorMessage(error, t("attachmentsPreviewFailed")), "error"); } }; @@ -183,18 +185,18 @@ export default function Attachments({ jobId }: { jobId: number }) { - Attachments ({count}) + {t("attachmentsTitle", { count })} - Upload resumes, cover letters, portfolios, and supporting files for this application. + {t("attachmentsSubtitle")} - - - + + + @@ -228,9 +230,9 @@ export default function Attachments({ jobId }: { jobId: number }) { textAlign: "center", }} > - Drag and drop files here + {t("attachmentsDragDrop")} - or use the upload button to choose documents from your device. + {t("attachmentsDragDropHelp")} {uploading ? : null} @@ -239,12 +241,12 @@ export default function Attachments({ jobId }: { jobId: number }) { - Name - Kind - Type - Size - Uploaded - Actions + {t("attachmentsName")} + {t("attachmentsKind")} + {t("attachmentsType")} + {t("attachmentsSize")} + {t("attachmentsUploaded")} + {t("attachmentsActions")} @@ -265,17 +267,17 @@ export default function Attachments({ jobId }: { jobId: number }) { {canPreview ? ( - void openPreview(a)} title="Preview"> + void openPreview(a)} title={t("attachmentsPreview")}> ) : null} - void download(a)} title="Download"> + void download(a)} title={t("attachmentsDownload")}> - void rename(a)} title="Rename"> + void rename(a)} title={t("attachmentsRename")}> - void remove(a)} title="Delete"> + void remove(a)} title={t("attachmentsDelete")}> @@ -288,7 +290,7 @@ export default function Attachments({ jobId }: { jobId: number }) { - No attachments yet. Upload a resume, cover letter, or portfolio to keep everything tied to this job. + {t("attachmentsEmpty")} @@ -298,7 +300,7 @@ export default function Attachments({ jobId }: { jobId: number }) { setPreviewOpen(false)} fullWidth maxWidth="md"> - Preview{preview?.name ? `: ${preview.name}` : ""} + {preview?.name ? t("attachmentsPreviewTitle", { name: preview.name }) : t("attachmentsPreview")} {!preview ? null : isImageType(preview.type) ? ( @@ -307,12 +309,12 @@ export default function Attachments({ jobId }: { jobId: number }) { ) : isPdfType(preview.type) ? (