fix build
This commit is contained in:
@@ -111,13 +111,44 @@ Create `apps/dashboard/app/(authenticated)/<section>/<feature>/page.tsx`:
|
||||
| Form component | `<PascalFeature>Form` | `JobCardForm` |
|
||||
| Page component | `<PascalFeature>Page` (default export) | `JobCardsPage` |
|
||||
|
||||
### Relation Fields (Foreign Keys)
|
||||
### Relation Fields — Choosing the Right Component
|
||||
|
||||
**Two patterns exist. Pick the right one before building any relational field.**
|
||||
|
||||
#### Simple FK → `RhfAsyncSelectField`
|
||||
|
||||
Use for single-record foreign keys within the same domain or to a simple lookup/reference entity.
|
||||
|
||||
Examples: invoice → customer, bill → vendor, part → category, service → unit type, job card → vehicle, PO → department, any `*_type` or `*_terms` relation.
|
||||
|
||||
- Stored in form as `{ value: string, label: string } | null`
|
||||
- Use `toRelation(id, name)` to convert API data → form value
|
||||
- Use `toId(relation)` to convert form value → API payload
|
||||
- Schema uses `relationFieldSchema = z.object({ value: z.string(), label: z.string() }).nullable()`
|
||||
- Rendered with `<RhfAsyncSelectField>` (fetches options via React Query)
|
||||
|
||||
#### Cross-Domain Line Items → `RhfResourceField` (resource-selector skill)
|
||||
|
||||
Use when the relationship involves a **join table with extra fields** (quantity, rate, description) or the related items are from a **fully separate domain with its own CRUD page** and multiple records can be linked.
|
||||
|
||||
Examples: adding parts to a bill, linking services to an invoice, attaching expense items to a PO.
|
||||
|
||||
**→ Read the `resource-selector` SKILL before implementing these fields.**
|
||||
|
||||
Ready-to-use selector fields (import directly — do not re-implement):
|
||||
|
||||
| Component | Import path | For |
|
||||
|---|---|---|
|
||||
| `PartsSelectorField` | `@/modules/parts/parts-selector-field` | Parts line items |
|
||||
| `ServicesSelectorField` | `@/modules/services/services-selector-field` | Service line items |
|
||||
| `ExpenseItemsSelectorField` | `@/modules/expense-items/expense-items-selector-field` | Expense line items |
|
||||
|
||||
```tsx
|
||||
// Schema: use an array sub-schema with part_id / service_id / expense_id
|
||||
part_items: z.array(z.object({ part_id: z.number(), title: z.string(), quantity: z.number(), rate: z.number(), description: z.string().optional() })).optional()
|
||||
|
||||
// Form: render inside <FieldGroup>
|
||||
<PartsSelectorField<MyFormValues, "part_items"> name="part_items" />
|
||||
```
|
||||
|
||||
### Async Select Pattern
|
||||
|
||||
@@ -144,8 +175,11 @@ const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) =
|
||||
| `RhfTextareaField` | Multi-line text |
|
||||
| `RhfCheckboxField` | Boolean toggles |
|
||||
| `RhfSelectField` | Static option dropdowns |
|
||||
| `RhfAsyncSelectField` | Server-fetched single-select combobox |
|
||||
| `RhfAsyncSelectField` | Server-fetched single FK combobox (same-domain relation) |
|
||||
| `RhfAsyncMultiSelectField` | Server-fetched multi-select combobox |
|
||||
| `RhfResourceField` | Cross-domain multi-select with join table extra fields (parts, services, expenses) — see resource-selector skill |
|
||||
| `RhfDateField` | Date picker — see date-time-pickers skill |
|
||||
| `RhfTimeField` | Time picker — see date-time-pickers skill |
|
||||
|
||||
### Imports Cheat Sheet
|
||||
|
||||
|
||||
Reference in New Issue
Block a user