Account
Public handle settings, an editable field checked while typing, confirmed as final, then read-only.
Import from @workspace/ui-training/account/*.
AccountHandleViewModel
Prop
Type
AccountHandleAvailabilityViewModel
Where the availability check of the typed handle stands: idle while nothing is typed, checking, available, or unavailable with a reason (too_short, too_long, invalid_format, reserved, taken).
AccountHandleSettings
A controlled field: the app owns the draft, the availability and the write. The component renders the /authors/ prefix, the availability line (a CVA status variant: idle, checking, available, unavailable), the suggestion while the field is empty, and a confirmation dialog: onConfirm is only called once the user confirmed that the handle can no longer be changed. A locked handle (the locked mode) is shown read-only, without the submit, with a notice instead of the availability line.
| Prop | Role |
|---|---|
account | AccountHandleViewModel: the stored handle and its lock |
value, onValueChange | The draft; ignored once locked |
availability | AccountHandleAvailabilityViewModel; the submit is enabled only when available |
suggestion? | A handle offered while the field is empty, picked with Use it |
isSaving? | Disables the field and the submit while the write runs |
onConfirm | Called after the confirmation dialog |
import { AccountHandleSettings } from '@workspace/ui-training/account/account-handle-settings';
<AccountHandleSettings
account={{ handle: account.handle, locked: account.handleLocked }}
value={draft}
onValueChange={setDraft}
availability={availability}
suggestion={suggestion}
isSaving={setHandle.isPending}
onConfirm={() => setHandle.mutate(draft)}
/>AccountHandleSettingsSkeleton (same entry) is its placeholder while the account loads.
In apps/app, features/account/edit/handle maps the account and the availability query to these ViewModels, checks the format locally with the domain rules before asking the server, debounces the server check, and mounts the strings from the account namespace (profile.handle.*). The account page composes it as EditAccount.Handle, next to EditAccount.BasicForm: each block saves on its own, and the page owns their Suspense and skeletons.
Strings
AccountHandleStringsProvider and useAccountHandleStrings live in account/strings. unavailable(reason), suggestion(handle) and confirmTitle(handle) are factories.