PR: #330: [Story-1281] Add-Matter matter-type picker + inline-create by @ankitmaheshwari-com
View PR →
Story-1281 · slice 2 · Matter Types · Spike-1274 · pramaan-docs ADR-115

Add-Matter matter-type picker + inline-create — closing #1281

Slice 1 (#329) wired the Matter Types settings catalog to the real /app/matter-types contract and left one piece open: the Add-Matter wizard could not pick or mint a matter type, and never sent matter_type_id on create. Functions S3 (#1279) landed MatterCreateRequest.matterTypeId and the server-side type resolution. This slice is the consumer side — the last piece of #1281.

What ships

PieceWhat & why
Picker componentadd-matter/matter-type-select.tsx (new) — a live combobox of firm matter types rendered mono-caps, mirroring participant-label-select.tsx: type to filter, "+ Add new type…" at the foot swaps the popover body to an inline create form. Copy-injected (i18n-agnostic), with a co-located story.
Inline createMinting a type calls the slice-1 path: useAppCreateMatterType (POST /app/matter-types) wired in live-matters-list-page.tsx via createWizardMatterType — dedupes by name, then invalidates appListMatterTypesQueryKey(). The minted type is firm-wide and immediately selected.
Step-2 fieldstep2-matter-body.tsx renders the picker as the first field, mono-caps label + required marker on the scratch path, with a helper line (scratch hint vs "set by the selected preset").
Gatingadd-matter-wizard.tsx holds matterTypeId state and folds it into the Step-2 Next gate: !isScratch || matterTypeId. Scratch requires a type; the preset path does not.
Send the idmatterTypeId flows AddMatterCreatePayload → wizardCreateInputFromPayload → WizardMatterInput → createMatterFromWizardAction → MatterCreateRequest.matterTypeId.
Data wiringlive-matters-list-page.tsx reads live types with useAppListMatterTypes() (no-arg = live only, distinct from the catalog's { includeArchived: true } entry) and passes options + the create handler down through AddMatterModal.
i18n10 new keys under the AddMatter namespace (placeholder, add-new, create/creating/cancel, error, scratch/preset hints, field label), full en + hi parity.

Preset auto-set — handled server-side

The contract does not expose matter_type_id on the matter-template View (verified against both the vendored mirror and functions main HEAD), so the wizard cannot pre-fill the combobox with the preset's type by name. It does not need to: functions _resolve_matter_type_id makes the preset's type win (template.matter_type_id || requested), and requires a type only on the scratch path (else pramaan.matter.matter_type_required). So the app sends null on the preset path and the backend derives the type; on the scratch path the wizard gates Next until one is chosen. The brief's "pre-select the preset's id" is the only unmet detail and is purely cosmetic — surfacing the preset's type name would need a new field on the template View (a follow-up functions ticket).

Verification

pnpm tsc         clean
pnpm lint        clean (0 errors; only pre-existing warnings)
pnpm build       green
vitest           add-matter + matter-create suites pass
                 (matters-internal-route flake is pre-existing — fails identically on clean HEAD)
contract         no openapi/ or src/gen changes — mirror byte-identical to functions HEAD; freshness guard untouched
i18n parity      en/hi AddMatter — 10 keys added to both
No gateway/hook recreation: reuses the slice-1 /app/matter-types hooks (useAppListMatterTypes / useAppCreateMatterType) and proxy. No LEGACY_MATTER_TYPE_ID_COMPAT sentinel existed on the app side, so nothing to retire here.

Files changed

15 file(s), +570 / -5 lines

Path Role + -
messages/en.jsonConfig+10-0
messages/hi.jsonConfig+10-0
src/app/[locale]/(workspace)/matters/actions.tsApp route+2-0
src/components/add-matter/__mocks__/matter-types.tsComponent+20-0
src/components/add-matter/add-matter-types.tsComponent+10-0
src/components/add-matter/add-matter-wizard.stories.tsxComponent+15-0
src/components/add-matter/add-matter-wizard.tsxComponent+34-4
src/components/add-matter/matter-type-select.stories.tsxComponent+68-0
src/components/add-matter/matter-type-select.tsxComponent+246-0
src/components/add-matter/step2-matter-body.tsxComponent+42-0
src/components/matters/live-matters-list-page.tsxComponent+47-1
src/components/matters/live-matters-wizard-payload.tsComponent+4-0
tests/unit/add-matter-wizard-label-gate.test.tsxTest+1-0
tests/unit/live-matters-wizard-payload.test.tsTest+44-0
tests/unit/wizard-matter-actions.test.tsTest+17-0