Rebuild My Profile as a hero and five rooms

Featurekamo-internal
Shipped
September 3, 2026 at 6:53 PM UTC
Author
Kamo
Commit
c20bac5

**************** was one 1,999-line component rendering thirteen identical cards down a single column. One SectionCard helper gave all of them the same radius, the same shadow, the same icon chip and the same Edit / Save / Cancel trio, so "Account Information" — two dates nobody can edit — carried exactly the weight of "Password & MFA". The layout was telling the truth about a hierarchy the page did not have. The rebuild: • A hero that keeps MemberHeader's wallpaper resolution verbatim, scar comments included, and adds the identity it was only decorating: the name as the page's one piece of large type, the member's local time ticking in THEIR zone, MFA state, last sign-in, and a strength ring. • Five rooms behind a rail — Identity, Appearance, Work, Access, Regional — one open at a time, carried in the URL as &room=. A room whose every card is gated away for the viewer renders no rail item at all. • Click-to-edit fields and one room-level save bar, replacing 39 buttons. Saves fan out by endpoint under allSettled: a group that succeeds commits while a group that fails keeps its fields dirty with a reason. • Cmd+K over every field, so rooms hide things without hiding them. • Card-shaped staggered skeletons instead of one full-tab spinner. Two defects found while reading, fixed here: • The address never worked in EITHER direction. The loader hardcoded five empty strings and never read data.address, which SecurityService does send; and the client's {street, city, state, zip, country} is not the wire shape — Member.address is an EmbAddress of {address, addressDetails, locality, subdivision, postalCode, country}. So it rendered blank for everyone and saved keys the entity does not carry. Now uses the shape the rest of the platform already sends, with round-trip tests. • "Legal name:" and "Born " were English literals in MemberHeader, and the work-location and employment-status labels were English literals in the component. All keyed. Structure. The rules moved to app/lib/memberProfile, where vitest actually collects them — app/settings/** is not in the include allowlist, so a test written beside the page would have passed by never running. fields.ts is the keystone: every field declared once with its room, card, label, gate and endpoint. The palette, the strength ring, the save fan-out and rights gating all read it instead of reimplementing it, and 57 tests pin the gates down — including that no field is ever more visible than its card, and that editing is never wider than seeing. Quick Tips is dropped for this tab only, by omitting helpTips; SettingsView renders the rail from the active tab, so the other nine keep theirs. Impersonate moves from the settings header into the hero. Also deletes ProfileTab.tsx (2,650 lines), LoginSecurityTab.tsx (787) and MembershipPermissionsTab.tsx (2,136), which had no importers. Dictionary keys landed first in kamo-translation-dictionary 4bb91245. Verified: npm test (14 guards + 5,106 tests), tsc --noEmit, next build, and check-i18n-keys --require-messages against a fresh clone of the dictionary.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing