07 — Component Library (CRM Module)
- 1. LeadStatusChip (status badge)
- 2. LeadSourceIcon
- 3. LeadListTile (S1 row)
- 4. FollowUpCard (S2 timeline item)
- 5. ConvertDialog (S4)
- 6. StatusBadge (admission, S5/S6)
- 7. AdmissionListTile (S5 row)
- 8. WorkflowTimeline (S6)
- 9. DocumentCard (S6)
- 10. InterviewCard (S6)
- 11. FunnelStatCard (S5 header)
- 12. CampaignCard (S10 row)
- 13. FilterChipRow (S1/S5)
- 14. FollowUpComposer (S2 sheet)
- Composition rules
Module-specific widgets on top of the shared component library (00-shared/03_Component_Library.md). Shared atoms (
AppButton,AppCard,AppTextField,AppChips,AppBadge,AppAvatar,AppTimeline,AppDialog,AppBottomSheet,AppSkeleton,AppEmptyState,AppFAB,AppDatePicker,AppSegmentedButton) are reused as-is; only CRM-specific compositions are specified here. All colors from 00-shared/02_Design_Tokens.md (proposed until designer sign-off).
1. LeadStatusChip (status badge)
| Prop | Values |
|---|---|
| status | new|contacted|qualified|converted|closed (lead.schema.ts:7-13) |
| Status | Color (semantic) | Icon | Label key |
|---|---|---|---|
| new | color.secondaryContainer | inbox | crm.status.new |
| contacted | color.primaryContainer | call | crm.status.contacted |
| qualified | color.tertiaryContainer | verified | crm.status.qualified |
| converted | success container | check_circle | crm.status.converted |
| closed | surface-variant | block | crm.status.closed |
- Icon + text, never color-only (00-shared/09).
- Disabled variant renders grayed + reduced opacity for non-actionable chips.
2. LeadSourceIcon
| source | icon | label key |
|---|---|---|
| website | language | crm.source.website |
| referral | group | crm.source.referral |
| walk_in | storefront | crm.source.walk_in |
| phone | phone | crm.source.phone |
| campaign | campaign | crm.source.campaign |
| other | more_horiz | crm.source.other |
Sizes: 16 dp inline (list rows), 20 dp in detail header.
3. LeadListTile (S1 row)
Composition: AppAvatar(40, initials) · column(name, subtitle) · trailing
(LeadStatusChip + LeadSourceIcon). Subtitle auto-composed:
email · next follow-up {date} / overdue variant {date} overdue in color.error.
Subtitle logic in a pure function followUpSummary(lead) — unit-tested.
4. FollowUpCard (S2 timeline item)
note (body), meta row: scheduledAt (formatted, DateTime.toDisplayDate),
"completed" check when completedAt set, "by {createdBy}". Data:
lead.schema.ts:24-39. Variants: upcoming (default), due today (primary border),
overdue (error border), completed (muted + check).
5. ConvertDialog (S4)
AppDialog wrapper with pre-condition list + destructive-primary confirm. Props:
lead, canConvert (client rule check per crm.service.ts:118-149), onConvert.
Fixed copy from 06 §S4.
6. StatusBadge (admission, S5/S6)
| status | color | label key |
|---|---|---|
| draft / submitted | secondaryContainer | crm.adm.status.draft|submitted |
| documents_pending | tertiaryContainer | crm.adm.status.documents_pending |
| interview_scheduled | primaryContainer | crm.adm.status.interview_scheduled |
| under_review | secondaryContainer | crm.adm.status.under_review |
| approved | success container | crm.adm.status.approved |
| rejected | error container | crm.adm.status.rejected |
| waitlisted | surface-variant | crm.adm.status.waitlisted |
| converted | success container + check | crm.adm.status.converted |
Statuses: admission.schema.ts:7-17.
7. AdmissionListTile (S5 row)
AppAvatar(40) · name · email · submitted {date} · trailing StatusBadge.
Optional document hint line: "docs: 2/3" (count from documents array;
required-set knowledge (planned)).
8. WorkflowTimeline (S6)
Read-only vertical AppTimeline over workflow[] (admission.schema.ts:52-67):
each node "statusA → statusB", approver name, comment (italic), at timestamp.
Rendered newest-first. Never editable.
9. DocumentCard (S6)
Icon by type (tc → description, marksheet → table_chart, certificate → workspaces,
photo → photo, other → attach_file — admission.schema.ts:27-33), filename,
meta "by {uploadedBy} · {uploadedAt}". Tap → open file (fileId via storage layer;
no download endpoint in this module — (planned)).
10. InterviewCard (S6)
scheduledAt (prominent), mode chip (online/offline), panel chips (names), feedback
body. Empty variant: "No interview scheduled" + Schedule action. Data:
admission.schema.ts:69-81.
11. FunnelStatCard (S5 header)
Title (label key), big number, sub-label. Variants: total, per-status count, and
conversionRate ("N%") from GET /crm/admissions/stats (admission.service.ts:227-237).
Loading → AppSkeleton box; error → "—" with retry icon.
12. CampaignCard (S10 row)
name (title), type icon + label, StatusBadge (campaign enum — campaign.schema.ts:7-12),
date range, metrics line leadsGenerated · converted (campaign.schema.ts:45-52);
metrics absent → "—". Tap → read-only info sheet (no detail endpoint).
13. FilterChipRow (S1/S5)
Horizontal SingleChildScrollView of AppChips (filter chips): first = "All",
selected chip emphasized. Wraps the shared status-filter interaction used by both
lists; emits onChanged(value|null).
14. FollowUpComposer (S2 sheet)
AppTextField multiline (note*), AppDatePicker datetime (scheduledAt*),
optional completedAt toggle (create-follow-up.dto.ts:4-17). Submit Add follow-up.
Composition rules
- Module widgets never fetch data; they render models passed by cubits (00-shared/06 §2).
- All labels via i18n keys (
crm.*namespace) — server text only for business 4xx fallback (00-shared/11 §9). - Goldens required for:
LeadStatusChip(6 statuses × light/dark),StatusBadge(9),WorkflowTimeline,LeadListTile,FunnelStatCard.