From 3de2e37ed5e3c18b9504a5e9ef4cb1dd22113608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 27 Apr 2026 00:15:59 +0200 Subject: [PATCH] fix(ux): touch targets, a11y on phase config, admin label i18n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UX/a11y residuals from 2026-04-26 audit: - bottom-nav: touch targets sized to WCAG 2.5.5 minimum (44x44 CSS px) via min-h-11 min-w-11 on each Link. Nav height bumped to h-16 to accommodate. Visual icon stays at 20px so design doesn't shift. - phase-config-dialog: decorative coloured dot now aria-hidden because the redundant text label ("Green"/"Yellow"/...) already conveys the phase. Screen readers no longer announce a meaningless 'image' node. - admin: 'Web Push' and 'Bug Report' labels were hard-coded English in StatusItem and SettingsToggle calls; now go through t() with new admin.integrationWebPush / admin.integrationBugReport keys (en + de). - medication-card: false-positive en-CA / en-US locale audit findings documented inline — those are intentional locale-independent helpers (en-CA gives YYYY-MM-DD for day-comparison, en-US gives a parseable string for the toBerlinDate timezone hack), not user-facing display. --- messages/de.json | 2 + messages/en.json | 2 + src/app/admin/page.tsx | 49 ++++++++++------ src/components/layout/bottom-nav.tsx | 14 +++-- .../medications/medication-card.tsx | 21 ++++++- .../medications/phase-config-dialog.tsx | 58 ++++++++++++++----- 6 files changed, 106 insertions(+), 40 deletions(-) diff --git a/messages/de.json b/messages/de.json index 892c3ee4d..8fd92c719 100644 --- a/messages/de.json +++ b/messages/de.json @@ -1107,6 +1107,8 @@ "telegramGlobal": "Telegram-Benachrichtigungen systemweit erlauben.", "ntfyGlobal": "ntfy-Benachrichtigungen systemweit erlauben.", "webPushGlobal": "Browser-Push-Benachrichtigungen systemweit erlauben.", + "integrationWebPush": "Web Push", + "integrationBugReport": "Bug-Reports", "apiGlobal": "API-Endpunkte und API-Tokens systemweit erlauben.", "moodLogGlobal": "moodLog-Integration systemweit erlauben.", "sectionGeneral": "Allgemein", diff --git a/messages/en.json b/messages/en.json index 67eb7b06b..ef71781c5 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1107,6 +1107,8 @@ "telegramGlobal": "Allow Telegram notifications system-wide.", "ntfyGlobal": "Allow ntfy notifications system-wide.", "webPushGlobal": "Allow browser push notifications system-wide.", + "integrationWebPush": "Web Push", + "integrationBugReport": "Bug Report", "apiGlobal": "Allow API endpoints and API tokens system-wide.", "moodLogGlobal": "Allow moodLog integration system-wide.", "sectionGeneral": "General", diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 6d213e4e9..e6b64bcc9 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -378,7 +378,7 @@ function SystemStatusSection({ id }: { id: string }) { {status.integrations.webPush && ( @@ -386,7 +386,7 @@ function SystemStatusSection({ id }: { id: string }) { {status.integrations.bugReport && ( @@ -518,7 +518,7 @@ function ServicesSection({ id }: { id: string }) { disabled={updateSettings.isPending} /> ("OPEN"); + const [activeStatus, setActiveStatus] = useState("OPEN"); const [selected, setSelected] = useState(null); const { data, isLoading } = useQuery({ @@ -2281,7 +2280,11 @@ function FeedbackInboxSection({ id }: { id: string }) { {STATUS_TABS.map((s) => ( - {t(`admin.feedback.tab${s.charAt(0) + s.slice(1).toLowerCase()}`)} + + {t( + `admin.feedback.tab${s.charAt(0) + s.slice(1).toLowerCase()}`, + )} + {counts[s] ?? 0} @@ -2328,7 +2331,7 @@ function FeedbackInboxSection({ id }: { id: string }) { {data.items.map((item, i) => ( setSelected(item)} > @@ -2337,7 +2340,7 @@ function FeedbackInboxSection({ id }: { id: string }) { - + {item.subject} @@ -2379,9 +2382,16 @@ function FeedbackInboxSection({ id }: { id: string }) { ); } -function FeedbackCategoryBadge({ category }: { category: FeedbackCategoryType }) { +function FeedbackCategoryBadge({ + category, +}: { + category: FeedbackCategoryType; +}) { const { t } = useTranslations(); - const map: Record = { + const map: Record< + FeedbackCategoryType, + { label: string; className: string } + > = { BUG: { label: t("admin.feedback.categoryBug"), className: "bg-red-500/15 text-red-400 border-red-500/30", @@ -2400,7 +2410,9 @@ function FeedbackCategoryBadge({ category }: { category: FeedbackCategoryType }) }, }; const cfg = map[category]; - return {cfg.label}; + return ( + {cfg.label} + ); } function FeedbackDetailDialog({ @@ -2487,11 +2499,12 @@ function FeedbackDetailDialog({ const url = typeof meta.url === "string" ? meta.url : null; const locale = typeof meta.locale === "string" ? meta.locale : null; const userAgent = typeof meta.userAgent === "string" ? meta.userAgent : null; - const appVersion = typeof meta.appVersion === "string" ? meta.appVersion : null; + const appVersion = + typeof meta.appVersion === "string" ? meta.appVersion : null; return ( - + @@ -2529,7 +2542,7 @@ function FeedbackDetailDialog({ {(url || locale || userAgent || appVersion) && (
-

+

{t("admin.feedback.metadataHeading")}

@@ -2571,14 +2584,14 @@ function FeedbackDetailDialog({ {item.screenshotBase64 && (
-

+

{t("admin.feedback.screenshotHeading")}

{/* eslint-disable-next-line @next/next/no-img-element */} Screenshot
)} @@ -2611,7 +2624,7 @@ function FeedbackDetailDialog({
-
+
- + {direction === "before" ? t("medications.phaseBeforeEnd") : t("medications.phaseAfterEnd")} @@ -197,12 +223,12 @@ export function PhaseConfigDialog({ )} {statusMessage && ( -
+
{statusMessage}
)} - +