07 — Component Library (Communication Module)
- 1. AnnouncementCard
- 2. AudienceChip
- 3. AnnouncementStatusBadge
- 4. ReadReceiptBar
- 5. ReadReceiptRow
- 6. AudiencePicker (composer)
- 7. ComposerField (reused trio)
- 8. ThreadTile / MessageBubble (secondary surface)
- Composability map (screen → component)
Module-specific components. Reuse 00-shared/03 (App*) for everything generic; only announcement-specific composites live here. All components are stateless widgets driven by Cubit state (see 13_State_Management.md).
1. AnnouncementCard
| Property | Type | Notes |
|---|---|---|
| announcement | Announcement model | from GET /announcements payload (announcement.schema.ts:31-53) |
| isUnread | bool | derived: myUserId ∉ readBy[].userId |
| onTap | VoidCallback | → detail |
| trailing | widget? | optional AppMenu (authors: view receipts) |
Render: AppCard + AppListTile: unread dot (leading, 8 dp amber dot — semantics
"Unread"), title titleMedium, body excerpt bodySmall maxLines 2, row of
AudienceChip + AnnouncementStatusBadge, createdAt relative time.
Draft rows show AnnouncementStatusBadge(draft) and no unread dot (recipients never see
drafts — draft filter is published: false, announcement.schema.ts:45-46).
States: idle / loading (AppSkeleton variant) / error.
2. AudienceChip
| Property | Type | Notes |
|---|---|---|
| audience | AnnouncementAudience | { type, value } (announcement.schema.ts:15-21) |
Label mapping (verbatim enum, announcement.schema.ts:7-13):
| type | label |
|---|---|
all | "Everyone" |
role | value (e.g. "Teacher") |
grade | value (e.g. "Grade 10") |
section | value (e.g. "10-A") |
custom | "Selected people" (+count if known) |
AppChip with module palette (see 11_Design_System_Mapping.md).
3. AnnouncementStatusBadge
| Property | Type | Notes |
|---|---|---|
| published | bool | announcement.schema.ts:45-46 |
true→ "Published" +publishedAton detailfalse→ "Draft" (publishedAtabsent —:48-49)
AppBadge; published = success color, draft = neutral.
4. ReadReceiptBar
| Property | Type | Notes |
|---|---|---|
| readCount | int | readBy.length (announcement.service.ts:104-107) |
| targetCount | int | targetUserIds.length; 0 ⇒ render "Everyone", hide ratio (announcement.service.ts:144-146) |
Render: progress bar (readCount/targetCount) + "72 of 120 read". Used on
"AnnouncementCard(authors)" and receipts sheet.
5. ReadReceiptRow
| Property | Type | Notes |
|---|---|---|
| userId | string | receipt.userId (announcement.schema.ts:24-25) |
| readAt | DateTime | :27-28 |
| displayName | string | user lookup (forward-looking) — API returns ids only |
AppListTile: avatar, name, "Read 3 Aug 9:04". Unread variant shows "Not read yet".
6. AudiencePicker (composer)
| Property | Type | Notes |
|---|---|---|
| value | AnnouncementAudience | { type, value? } |
| onChanged | callback | |
| options | enum list | all|role|grade|section|custom (announcement.schema.ts:7-13) |
Render: 5 AppChoiceChips + conditional value input:
- role → dropdown of org roles (RBAC constants
(planned)— no perms exist today) - grade / section → picker fed by academics module data (values are names,
announcement.service.ts:121,128) - custom → user search + chips
- all → none; label "Everyone in your school"
7. ComposerField (reused trio)
AppTextField variants bound to DTO: title (single-line), body (multiline),
attachments chip list (create-announcement.dto.ts:29-49). Validation mirrors
class-validator rules (see 08_Form_Specifications.md §5).
8. ThreadTile / MessageBubble (secondary surface)
AppListTile (thread row) + outgoing/incoming bubble with sentAt, delivery tick
(WebSocket (planned) — IMPLEMENTATION_PLAN.md:119). Deferred detail to messaging
package.
Composability map (screen → component)
| Screen (05) | Components |
|---|---|
| Feed | AnnouncementCard, AudienceChip, AnnouncementStatusBadge, App* |
| Detail | AnnouncementStatusBadge, AudienceChip, AppSheet/Page |
| Compose | AudiencePicker, ComposerField, App* |
| Mine | AnnouncementCard, AnnouncementStatusBadge |
| Receipts | ReadReceiptBar, ReadReceiptRow |
| Threads | ThreadTile, MessageBubble |