From a238ae48d14327c6c93d10fd499bd55d7707d712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 14 May 2026 22:30:58 +0200 Subject: [PATCH] fix(design): pin acknowledgment dialog footer + i18n back-button + drop GoalsChipPicker storage block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three small surface fixes consolidated because each is a one-touch change on a separate file: - `ResearchModeAcknowledgmentDialog`: the entire `DialogContent` scrolled at `max-h-[90vh] overflow-y-auto`, which pushed the Acknowledge / Cancel CTAs below the fold on phone-class viewports. Move scrolling onto the body section only so the header and footer stay pinned. - Medication history page back-button rendered the literal "Zurück" instead of going through `t()`. Wire the new `medications.back` key across all six locale bundles. - `GoalsChipPicker` shipped a localStorage persistence block scoped by user id, but no consumer reads the same key. Drop the storage layer (and the unused `goalsStorageKey` / `ONBOARDING_GOALS_STORAGE_PREFIX` exports) until v1.4.26 lands the `User.onboardingGoals` column the picker is meant to feed. --- messages/de.json | 1 + messages/en.json | 1 + messages/es.json | 1 + messages/fr.json | 1 + messages/it.json | 1 + messages/pl.json | 1 + src/app/medications/[id]/history/page.tsx | 2 +- .../ResearchModeAcknowledgmentDialog.tsx | 9 ++- src/components/onboarding/GoalsChipPicker.tsx | 76 ++++--------------- 9 files changed, 29 insertions(+), 64 deletions(-) diff --git a/messages/de.json b/messages/de.json index b3bd516ea..dc7bff436 100644 --- a/messages/de.json +++ b/messages/de.json @@ -444,6 +444,7 @@ "daysFri": "Fr", "daysSat": "Sa", "intakeHistoryTitle": "Einnahme-Verlauf", + "back": "Zurück", "newIntake": "Hinzufügen", "editIntake": "Einnahme bearbeiten", "intakeScheduledFor": "Geplant", diff --git a/messages/en.json b/messages/en.json index eee305e86..18ee87c63 100644 --- a/messages/en.json +++ b/messages/en.json @@ -444,6 +444,7 @@ "daysFri": "Fri", "daysSat": "Sat", "intakeHistoryTitle": "Intake History", + "back": "Back", "newIntake": "Add", "editIntake": "Edit Intake", "intakeScheduledFor": "Scheduled", diff --git a/messages/es.json b/messages/es.json index 67b71303e..228bb3bf5 100644 --- a/messages/es.json +++ b/messages/es.json @@ -444,6 +444,7 @@ "daysFri": "Fri", "daysSat": "Sat", "intakeHistoryTitle": "Intake History", + "back": "Atrás", "newIntake": "Añadir", "editIntake": "Edit Intake", "intakeScheduledFor": "Scheduled", diff --git a/messages/fr.json b/messages/fr.json index b920432d4..3a5d59645 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -444,6 +444,7 @@ "daysFri": "Fri", "daysSat": "Sat", "intakeHistoryTitle": "Intake History", + "back": "Retour", "newIntake": "Ajouter", "editIntake": "Edit Intake", "intakeScheduledFor": "Scheduled", diff --git a/messages/it.json b/messages/it.json index 8f108bbd6..ef36b45f7 100644 --- a/messages/it.json +++ b/messages/it.json @@ -444,6 +444,7 @@ "daysFri": "Fri", "daysSat": "Sat", "intakeHistoryTitle": "Intake History", + "back": "Indietro", "newIntake": "Aggiungi", "editIntake": "Edit Intake", "intakeScheduledFor": "Scheduled", diff --git a/messages/pl.json b/messages/pl.json index a6375aeea..36c637331 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -444,6 +444,7 @@ "daysFri": "Fri", "daysSat": "Sat", "intakeHistoryTitle": "Intake History", + "back": "Wstecz", "newIntake": "Dodaj", "editIntake": "Edit Intake", "intakeScheduledFor": "Scheduled", diff --git a/src/app/medications/[id]/history/page.tsx b/src/app/medications/[id]/history/page.tsx index aa8cfb163..4904d5fbd 100644 --- a/src/app/medications/[id]/history/page.tsx +++ b/src/app/medications/[id]/history/page.tsx @@ -66,7 +66,7 @@ export default function IntakeHistoryPage({ > - Zurück + {t("medications.back")} diff --git a/src/components/medications/ResearchModeAcknowledgmentDialog.tsx b/src/components/medications/ResearchModeAcknowledgmentDialog.tsx index c447f0974..59852c5d9 100644 --- a/src/components/medications/ResearchModeAcknowledgmentDialog.tsx +++ b/src/components/medications/ResearchModeAcknowledgmentDialog.tsx @@ -134,7 +134,7 @@ export function ResearchModeAcknowledgmentDialog({ @@ -146,7 +146,12 @@ export function ResearchModeAcknowledgmentDialog({ -
+ {/* Only the body scrolls; header + footer stay pinned so the + Acknowledge / Cancel CTAs are always reachable without + scrolling on small viewports (the previous markup scrolled + the entire DialogContent, pushing the footer below the + fold on iPhone-class heights). */} +
= [ }, ]; -export function goalsStorageKey(userId: string): string { - return `${ONBOARDING_GOALS_STORAGE_PREFIX}:${userId}`; -} - -function readGoalsFromStorage( - storageKey: string, -): Set { - if (typeof window === "undefined") return new Set(); - try { - const raw = window.localStorage.getItem(storageKey); - if (!raw) return new Set(); - const parsed = JSON.parse(raw) as unknown; - if (!Array.isArray(parsed)) return new Set(); - const allowed = new Set(GOAL_OPTIONS.map((o) => o.slug)); - const out = new Set(); - for (const v of parsed) { - if (typeof v === "string" && allowed.has(v)) { - out.add(v as OnboardingGoalSlug); - } - } - return out; - } catch { - /* corrupt entry — ignore */ - return new Set(); - } -} - export interface GoalsChipPickerProps { /** * The current user's id. Threaded in from the server step page - * (`getSession().user.id`) so the localStorage hydration can run - * synchronously in the state initializer and avoid the - * `react-hooks/set-state-in-effect` cascading-render anti-pattern. + * (`getSession().user.id`) so the v1.4.26 column write can reuse + * the same call site without a prop reshuffle. */ userId: string; } -export function GoalsChipPicker({ userId }: GoalsChipPickerProps) { +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function GoalsChipPicker({ userId: _userId }: GoalsChipPickerProps) { const { t } = useTranslations(); const router = useRouter(); const queryClient = useQueryClient(); - const storageKey = goalsStorageKey(userId); - - const [selected, setSelected] = useState>(() => - readGoalsFromStorage(storageKey), + const [selected, setSelected] = useState>( + () => new Set(), ); const [advancing, setAdvancing] = useState(false); @@ -149,20 +117,6 @@ export function GoalsChipPicker({ userId }: GoalsChipPickerProps) { }); }, []); - // Persist on every change. localStorage is cheap and the goal set is - // tiny — no need for a debounced effect here. - useEffect(() => { - if (typeof window === "undefined") return; - try { - window.localStorage.setItem( - storageKey, - JSON.stringify(Array.from(selected)), - ); - } catch { - /* quota or disabled — best-effort */ - } - }, [storageKey, selected]); - async function advance() { if (advancing) return; setAdvancing(true);