fix(i18n): close shared ui gaps
This commit is contained in:
@@ -515,7 +515,7 @@ export default function AddJobModal({ open, onClose, onCreated, initialUrl }: Pr
|
||||
<ListItem key={match.id} sx={{ px: 0 }}>
|
||||
<ListItemText
|
||||
primary={`${match.company} - ${match.jobTitle}`}
|
||||
secondary={`${match.reason} • ${match.status} • ${new Date(match.dateApplied).toLocaleDateString()}`}
|
||||
secondary={`${match.reason} • ${match.status} • ${new Date(match.dateApplied).toLocaleDateString(language === "nb" ? "nb-NO" : "en")}`}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
|
||||
@@ -488,7 +488,7 @@ export default function Correspondence({ jobId, jobContext }: { jobId: number; j
|
||||
) : null}
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", gap: 1, alignItems: "flex-end", mt: 0.75 }}>
|
||||
<Typography variant="caption" sx={{ color: "text.secondary" }}>
|
||||
{isMe ? t("correspondenceMe") : t("correspondenceCompany")}{m.channel ? ` - ${m.channel}` : ""}{m.date ? ` - ${new Date(m.date).toLocaleString()}` : ""}
|
||||
{isMe ? t("correspondenceMe") : t("correspondenceCompany")}{m.channel ? ` - ${m.channel}` : ""}{m.date ? ` - ${new Date(m.date).toLocaleString(language === "nb" ? "nb-NO" : "en")}` : ""}
|
||||
</Typography>
|
||||
<IconButton size="small" aria-label={t("correspondenceDeleteTitle")} onClick={() => void deleteMessage(m.id)} sx={{ color: "text.secondary" }}>
|
||||
<DeleteOutlineIcon fontSize="small" />
|
||||
@@ -654,7 +654,7 @@ export default function Correspondence({ jobId, jobContext }: { jobId: number; j
|
||||
))}
|
||||
</Box>
|
||||
) : null}
|
||||
{gmailStatus.lastSyncedAt ? <Chip label={t("correspondenceLastSynced", { date: new Date(gmailStatus.lastSyncedAt).toLocaleString() })} size="small" /> : null}
|
||||
{gmailStatus.lastSyncedAt ? <Chip label={t("correspondenceLastSynced", { date: new Date(gmailStatus.lastSyncedAt).toLocaleString(language === "nb" ? "nb-NO" : "en") })} size="small" /> : null}
|
||||
{gmailStatus.lastSyncAttemptedAt ? <Chip label={t("correspondenceSyncChecked", { date: new Date(gmailStatus.lastSyncAttemptedAt).toLocaleString(language === "nb" ? "nb-NO" : "en") })} size="small" variant="outlined" /> : null}
|
||||
{gmailStatus.lastSyncStatus === "error" && gmailStatus.lastSyncError ? <Chip label={t("correspondenceSyncIssue", { error: gmailStatus.lastSyncError })} size="small" color="warning" variant="outlined" /> : null}
|
||||
{linkedThreadIds.length > 0 ? (
|
||||
@@ -710,7 +710,7 @@ export default function Correspondence({ jobId, jobContext }: { jobId: number; j
|
||||
<ListItemButton sx={{ alignItems: "flex-start", px: 0, py: 1 }}>
|
||||
<ListItemText
|
||||
secondaryTypographyProps={{ component: "div" }}
|
||||
primary={<Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, alignItems: "center", flexWrap: "wrap" }}><Typography sx={{ fontWeight: 700 }}>{message.subject || t("correspondenceNoSubject")}</Typography><Typography variant="caption" sx={{ color: "text.secondary" }}>{message.date ? new Date(message.date).toLocaleString() : ""}</Typography></Box>}
|
||||
primary={<Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, alignItems: "center", flexWrap: "wrap" }}><Typography sx={{ fontWeight: 700 }}>{message.subject || t("correspondenceNoSubject")}</Typography><Typography variant="caption" sx={{ color: "text.secondary" }}>{message.date ? new Date(message.date).toLocaleString(language === "nb" ? "nb-NO" : "en") : ""}</Typography></Box>}
|
||||
secondary={<Box component="span" sx={{ mt: 0.5, display: "block" }}>
|
||||
<Typography component="span" variant="body2" sx={{ color: "text.primary", display: "block" }}>{t("correspondenceFromLabel", { value: message.from || t("correspondenceUnknown") })}</Typography>
|
||||
<Typography component="span" variant="body2" sx={{ color: "text.secondary", mt: 0.25, display: "block" }}>{message.snippet}</Typography>
|
||||
|
||||
@@ -654,7 +654,7 @@ export default function DashboardView() {
|
||||
<Box key={series.tag}>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", mb: 0.5, gap: 1 }}>
|
||||
<Typography variant="body2" sx={{ fontWeight: 800, overflowWrap: "anywhere" }}>{series.tag}</Typography>
|
||||
<Typography variant="caption" sx={{ color: "text.secondary" }}>{series.counts.reduce((sum, value) => sum + value, 0)} total</Typography>
|
||||
<Typography variant="caption" sx={{ color: "text.secondary" }}>{t("dashboardTotalCount", { count: series.counts.reduce((sum, value) => sum + value, 0) })}</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: `repeat(${series.counts.length}, 1fr)`, gap: 0.5 }}>
|
||||
{series.counts.map((count, i) => (
|
||||
|
||||
@@ -771,7 +771,7 @@ export default function JobTable({ refreshToken, pageSize, onPageSizeChange, col
|
||||
<Table size="small" sx={{ minWidth: 980 }}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell padding="checkbox"><Checkbox checked={selectedAllOnPage} indeterminate={selectedIds.length > 0 && !selectedAllOnPage} onChange={(e) => toggleSelectAll(e.target.checked)} /></TableCell>
|
||||
<TableCell padding="checkbox"><Checkbox inputProps={{ "aria-label": t("jobTableSelectAll") }} checked={selectedAllOnPage} indeterminate={selectedIds.length > 0 && !selectedAllOnPage} onChange={(e) => toggleSelectAll(e.target.checked)} /></TableCell>
|
||||
<TableCell sortDirection={sortBy === "company" ? sortDir : false}><TableSortLabel active={sortBy === "company"} direction={sortBy === "company" ? sortDir : "asc"} onClick={() => requestSort("company")}>{t("jobTableCompany")}</TableSortLabel></TableCell>
|
||||
<TableCell sortDirection={sortBy === "jobTitle" ? sortDir : false}><TableSortLabel active={sortBy === "jobTitle"} direction={sortBy === "jobTitle" ? sortDir : "asc"} onClick={() => requestSort("jobTitle")}>{t("jobTableRole")}</TableSortLabel></TableCell>
|
||||
<TableCell sortDirection={sortBy === "location" ? sortDir : false}><TableSortLabel active={sortBy === "location"} direction={sortBy === "location" ? sortDir : "asc"} onClick={() => requestSort("location")}>{t("jobTableLocation")}</TableSortLabel></TableCell>
|
||||
@@ -809,7 +809,7 @@ export default function JobTable({ refreshToken, pageSize, onPageSizeChange, col
|
||||
"&:focus-visible": { outline: "3px solid", outlineColor: "primary.main", outlineOffset: -3 },
|
||||
}}
|
||||
>
|
||||
<TableCell padding="checkbox"><Checkbox checked={isSelected} onChange={(e) => toggleSelected(job.id, e.target.checked)} /></TableCell>
|
||||
<TableCell padding="checkbox"><Checkbox inputProps={{ "aria-label": t("jobTableSelectJob", { title: job.jobTitle }) }} checked={isSelected} onChange={(e) => toggleSelected(job.id, e.target.checked)} /></TableCell>
|
||||
<TableCell sx={{ minWidth: 140, fontWeight: 700 }}>{job.company?.name ?? ""}</TableCell>
|
||||
<TableCell>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }}>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { Alert, Button, IconButton, Stack, Typography } from "@mui/material";
|
||||
import { useOptionalI18n } from "../i18n/I18nProvider";
|
||||
|
||||
type Props = {
|
||||
featureKey: string;
|
||||
@@ -13,6 +14,7 @@ function storageKey(featureKey: string) {
|
||||
}
|
||||
|
||||
export default function ProFeatureNotice({ featureKey, title, children }: Props) {
|
||||
const i18n = useOptionalI18n();
|
||||
const [dismissed, setDismissed] = useState(() => {
|
||||
if (typeof window === "undefined") return false;
|
||||
try {
|
||||
@@ -38,8 +40,8 @@ export default function ProFeatureNotice({ featureKey, title, children }: Props)
|
||||
severity="info"
|
||||
action={(
|
||||
<Stack direction="row" spacing={0.5} alignItems="center">
|
||||
<Button href="/settings" size="small">View Pro</Button>
|
||||
<IconButton size="small" aria-label={`Dismiss ${title}`} onClick={dismiss}>
|
||||
<Button href="/settings" size="small">{i18n?.t("proFeatureView") ?? "View Pro"}</Button>
|
||||
<IconButton size="small" aria-label={i18n?.t("proFeatureDismiss", { title }) ?? `Dismiss ${title}`} onClick={dismiss}>
|
||||
<CloseIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from "react";
|
||||
|
||||
import { Autocomplete, Chip, TextField } from "@mui/material";
|
||||
import { useI18n } from "../i18n/I18nProvider";
|
||||
|
||||
export default function TagsInput({
|
||||
label = "Tags",
|
||||
label,
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
@@ -11,6 +12,7 @@ export default function TagsInput({
|
||||
value: string[];
|
||||
onChange: (next: string[]) => void;
|
||||
}) {
|
||||
const { t } = useI18n();
|
||||
return (
|
||||
<Autocomplete
|
||||
multiple
|
||||
@@ -28,7 +30,7 @@ export default function TagsInput({
|
||||
<Chip variant="outlined" label={option} {...getTagProps({ index })} key={option} size="small" />
|
||||
))
|
||||
}
|
||||
renderInput={(params) => <TextField {...params} label={label} placeholder="Add a tag and press Enter" />}
|
||||
renderInput={(params) => <TextField {...params} label={label ?? t("cvEditorTags")} placeholder={t("tagsInputPlaceholder")} />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user