fix(settings): pair date-of-birth with language in one grid row

Moves the language select into the same `grid sm:grid-cols-2` row as
date of birth and drops the standalone language wrapper plus its
`sm:max-w-xs` clamp. The profile form now carries a uniform two-cell
rhythm from top to bottom instead of alternating between paired and
single-cell rows. Updates the mobile-consistency e2e assertion to match
the new contract: dob + language MUST share a grid row.
This commit is contained in:
Marc-André Bombeck committed 2026-05-15 16:26:26 +02:00
1 parent 0f5369131e
commit a04e119cac
2 files changed
+31 -32

No files matched your search

+7 -6
View File
@@ -115,15 +115,16 @@ test.describe("Settings mobile consistency (Pixel 5)", () => {
}
});
test("/settings/account: Sprache select is in its own row, not paired with date-of-birth", async ({
test("/settings/account: Sprache select shares one grid row with date-of-birth", async ({
page,
}) => {
await page.goto("/settings/account", { waitUntil: "networkidle" });
await page.waitForLoadState("networkidle");
// The Sprache native select must NOT live inside the same `grid`
// ancestor as the date-of-birth input. Pre-fix they shared
// `<div class="grid sm:grid-cols-2"> dob | language </div>`.
// The v1.4.27 R1 settings audit pairs date-of-birth with language
// in a single `grid sm:grid-cols-2` row so the profile form keeps
// a uniform two-column rhythm and the language field no longer
// sits alone at the bottom with a `sm:max-w-xs` clamp.
const sharedGrid = await page.evaluate(() => {
const lang = document.getElementById("language-select");
const dob = document.getElementById("dob");
@@ -137,8 +138,8 @@ test.describe("Settings mobile consistency (Pixel 5)", () => {
});
expect(sharedGrid.found, "language + dob fields must exist").toBe(true);
expect(sharedGrid.sharedGrid, "language + dob must NOT share a grid").toBe(
false,
expect(sharedGrid.sharedGrid, "language + dob must share a grid").toBe(
true,
);
});
+24 -26
View File
@@ -402,13 +402,12 @@ export function AccountSection() {
</div>
</div>
{/* Date of birth pairs with the height/gender block above —
all three are "biological profile" data the app uses for
BMI + BP target calculations. Language is handled as its
own row below: it's a UI preference (cookie-backed),
not a profile attribute, so v1.4.19 A6 lifted it out of
the dob/language pair where users mistook it for a
per-account locale setting. */}
{/* Date of birth + language share one paired grid row so the
profile form keeps a single rhythm (every row two cells
wide on sm+). Date of birth is the bottom of the
biological-profile block; language is the only UI
preference on this card. They sit together to close the
"single-cell row" gap that broke the form's grid. */}
<div className="grid gap-4 sm:grid-cols-2">
<div className="space-y-2">
<Label htmlFor="dob">{t("settings.dateOfBirth")}</Label>
@@ -422,29 +421,28 @@ export function AccountSection() {
{t("settings.dateOfBirthHint")}
</p>
</div>
<div className="space-y-2">
<Label htmlFor="language-select">{t("settings.language")}</Label>
<select
id="language-select"
value={locale}
onChange={(e) => setLocale(e.target.value as Locale)}
className={NATIVE_SELECT_CLASS}
>
{locales.map((loc) => (
<option key={loc} value={loc}>
{localeLabels[loc as Locale]}
</option>
))}
</select>
<p className="text-muted-foreground text-xs">
{t("settings.languageDescription")}
</p>
</div>
</div>
<TimezonePicker value={timezone} onChange={setTimezone} />
<div className="space-y-2">
<Label htmlFor="language-select">{t("settings.language")}</Label>
<select
id="language-select"
value={locale}
onChange={(e) => setLocale(e.target.value as Locale)}
className={`${NATIVE_SELECT_CLASS} sm:max-w-xs`}
>
{locales.map((loc) => (
<option key={loc} value={loc}>
{localeLabels[loc as Locale]}
</option>
))}
</select>
<p className="text-muted-foreground text-xs">
{t("settings.languageDescription")}
</p>
</div>
{saveMsg && (
<p
role="alert"