mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 22:32:04 +00:00
Say when the onboarding profile step could not save a field
The baseline step submitted what you filled in and ignored the answer. The profile write is field-independent: it stores everything that validated and reports back what it declined. Nobody read that report here, so a value the server refused vanished between the input and the next screen and you moved on believing it was saved. It now says which field did not make it, using the name that sits next to the input you typed into, and keeps going with the rest that did save. When nothing could be saved at all, the step stays put and names the field that blocked it instead of a shrug. The wording and the field-naming come from the same place the account form in Settings uses, so the same refusal reads the same wherever you hit it.
This commit is contained in:
1 parent
340d1db6d9
commit
8e6880b04c
7 files changed
+463
-58
No files matched your search
@@ -1,8 +1,6 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
describeRejectedProfileField,
|
||||
resolveInitialTimezone,
|
||||
} from "../account-section-utils";
|
||||
import { describeRejectedProfileField } from "@/lib/profile/rejected-fields";
|
||||
import { resolveInitialTimezone } from "../account-section-utils";
|
||||
|
||||
describe("describeRejectedProfileField", () => {
|
||||
const t = (key: string) => `translated:${key}`;
|
||||
|
||||
@@ -61,44 +61,9 @@ export function statusText(
|
||||
return "key" in msg ? t(msg.key, msg.params) : msg.text;
|
||||
}
|
||||
|
||||
/** A single rejected-field entry from `applyProfileUpdate`'s wire shape
|
||||
* (`details.issues` on failure, `data.rejectedFields` on a partial
|
||||
* success) — `path` is the schema field name, never shown verbatim. */
|
||||
export interface RejectedProfileField {
|
||||
path: string;
|
||||
code: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a rejected field's schema `path` to the same i18n label already
|
||||
* shown next to that input on this screen. The server only ever knows
|
||||
* the field by its schema key (`heightCm`, `gender`, ...) — naming it
|
||||
* in a person-facing sentence is the client's job, using labels that
|
||||
* already exist and are already localized for this form.
|
||||
* Naming a rejected profile field is shared with the onboarding
|
||||
* baseline step — see `src/lib/profile/rejected-fields.ts`. This screen
|
||||
* uses the default label map, which points at the labels these inputs
|
||||
* already carry.
|
||||
*/
|
||||
const PROFILE_FIELD_LABEL_KEYS: Record<string, string> = {
|
||||
email: "auth.email",
|
||||
heightCm: "settings.height",
|
||||
dateOfBirth: "settings.dateOfBirth",
|
||||
gender: "settings.gender",
|
||||
fullName: "settings.identity.fullName",
|
||||
insurerName: "settings.identity.insurer",
|
||||
insuranceNumber: "settings.identity.insuranceNumber",
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the first rejected field's label, falling back to its raw
|
||||
* schema key for a field this screen has no input for (defensive —
|
||||
* every field `applyProfileUpdate` accepts from this form is mapped
|
||||
* above).
|
||||
*/
|
||||
export function describeRejectedProfileField(
|
||||
fields: RejectedProfileField[] | undefined,
|
||||
t: (key: string) => string,
|
||||
): string | null {
|
||||
const first = fields?.[0];
|
||||
if (!first) return null;
|
||||
const labelKey = PROFILE_FIELD_LABEL_KEYS[first.path];
|
||||
return labelKey ? t(labelKey) : first.path;
|
||||
}
|
||||
@@ -39,9 +39,11 @@ import { detectBrowserTimezone } from "@/lib/tz/format";
|
||||
import { apiFetchRaw } from "@/lib/api/api-fetch";
|
||||
import {
|
||||
describeRejectedProfileField,
|
||||
type RejectedProfileField,
|
||||
} from "@/lib/profile/rejected-fields";
|
||||
import {
|
||||
resolveInitialTimezone,
|
||||
statusText,
|
||||
type RejectedProfileField,
|
||||
type StatusMessage,
|
||||
} from "./account-section-utils";
|
||||
import { AvatarSection } from "./avatar-section";
|
||||
|
||||
Reference in new issue
Block a user