07 — Component Library (Attendance Module)
- Status model (shared by all components)
- 1. AttendanceGrid
- 2. StatusChip
- 3. StatusChipPopover (bottom sheet)
- 4. BatchEditSheet
- 5. MarkedCountBar
- 6. StatusFilterChips
- 7. CalendarHeatmap
- 8. DaySummaryCard
- 9. SummaryDonut (S5/S6)
- 10. AbsenceAlertCard (S7,
(planned)dispatch — OQ-1) - 11. BiometricDeviceTile (S8)
- 12. UndoBar
- 13. ReportJobCard (S5/S6)
- Shared-component usage map
Module-specific components; all shared primitives (
AppCard,AppListTile,AppBottomSheet, …) come from 00-shared/03 and are referenced by name. Token references per 00-shared/02; status colors follow the standalone roles (success/warning/error, 02 §1.1).
Status model (shared by all components)
| Status | Token role | Icon (Material Symbols, filled) | Label (i18n key) |
|---|---|---|---|
present | success | check_circle | att.status.present |
absent | error | block | att.status.absent |
late | warning (tertiary) | schedule | att.status.late |
half_day | warning (tertiary) | right_half_circle | att.status.halfDay |
leave | neutral surfaceVariant | beach_access | att.status.leave |
holiday | neutral surfaceVariant | wb_sunny | att.status.holiday |
unmarked | outlineVariant | radio_button_unchecked | att.status.unmarked |
Statuses/enum from attendance.schema.ts:7-14. Never color-only: icon + label always
(00-shared/09 §9).
1. AttendanceGrid
- Purpose: the marking surface — virtualized roster rows with status chips.
- Props:
rows: List<AttendanceRow>(student + current doc),statuses: Map<studentId, Status>,onCycle(row)(tap-cycle),onOpenPopover(row),selection: SelectionState?,enabled(read-only mode),filter(from StatusFilterChips). - Structure: header row (sticky) +
ListView.builderrows (56 dp,itemExtentfixed — perf, see 15_Flutter_Implementation_Guide.md); optional empty state slot. - Semantics: table role (00-shared/09 §7), row summary "Aarav Sharma, absent".
- Golden tests: 3 sizes × light/dark; 60-row build < 8 ms frame budget.
2. StatusChip
- Purpose: single status affordance on a row; tap = cycle (Present→Absent→Late→Present).
- Props:
status,saved(dashed outline when unsaved/queued),dense(44 dp a11y toggle),onTap,loading,selected. - Behaviour:
Mo.m-fastcolor/icon morph; mini spinner when in-flight; long-press → popover (owner: row gesture arbitration). - A11y:
Semantics(toggled: status != unmarked), label = status name + "double-tap to change"; state announced via live region on change.
3. StatusChipPopover (bottom sheet)
- Purpose: full status picker + optional checkIn/checkOut/remarks for one row.
- Props:
row,existingDoc?(prefill,GET /attendance/:id),onSave(patch). - Contents: 6 status chips (grid 3×2),
AppTimePickercheck-in (default now), check-out optional,AppTextFieldremarks,AppButton"Save". - Semantics: sheet title "Mark Aarav Sharma — 20 Jul".
4. BatchEditSheet
- Purpose: apply one status to N selected rows (
POST /attendance/bulk,mark-attendance.dto.ts:51-54). - Props:
selection,conflicts(rows already marked differently),onApply(status). - Contents: preview list (5 rows + "+29 more"), current→target status chips, conflict
AppBanner(amber, "will be overwritten"), CTA "Apply to N" / "Overwrite N". - A11y: counter announced; banner is a live region.
5. MarkedCountBar
- Purpose: sticky live summary of the day ("23 marked · 17 unmarked").
- Props:
counts: Map<Status,int>,total. - Behaviour: animates on change (
AnimatedSwitcher,Mo.m-fast); compact on phone (horizontal scroll). Live region for a11y.
6. StatusFilterChips
- Purpose: client-side filter of grid rows.
- Props:
selected,counts(badge per status),onChanged. - Rules: "All" default; chips show counts as
AppBadge; filtering never refetches (roster in memory).
7. CalendarHeatmap
- Purpose: month grid of day cells colored by status mix; used in S4 (class) and S7 (student).
- Props:
days: Map<date, DayStats>,selectedDate,onDayTap,disabledBefore/future. - Cell: 40×40 min; color = dominant status (ties: worst status wins — absent > late > half_day > leave > present); empty = neutral.
- A11y: each cell label "20 Jul — 28 present, 2 absent"; cells are buttons ≥ 44 dp.
- Perf: cell =
CustomPaint-free plainContainer/InkWell; month builds viaGridView.builder(see 15).
8. DaySummaryCard
- Purpose: per-day counts + drill actions (S4 tap).
- Props:
date,counts,onOpenGrid(S2 read-only),onOpenStudent(S7). - Contents: status legend row with counts, source mix note (manual/biometric/import/api
from
attendance.schema.ts:16-21).
9. SummaryDonut (S5/S6)
- Purpose: per-status share of a range (
GET /attendance/summary→{total, summary:{present:n,...}},attendance.service.ts:103-113). - Props:
summary,total,onStatusTap(filter). - A11y:
Semanticssummary text "Total 812: 750 present, 34 absent, …" (00-shared/09:60); tabular fallback list whensummaryempty (total: 0).
10. AbsenceAlertCard (S7, (planned) dispatch — OQ-1)
- Purpose: surface absence pattern to parents: "3 absences this month".
- Props:
count,window(visible month),onViewDays. - Copy rules: count from worker semantics = total absent docs in window
(
attendance.worker.ts:70-74); never claim "consecutive". Banner tonewarning.
11. BiometricDeviceTile (S8)
- Purpose: device row: health + ingest state.
- Props:
device(name, model, location, status frombiometric-device.schema.ts:15-31),lastPunchAt,todayCount,onTap(detail). - States: status badge (
activesuccess /inactiveneutral /offlineerror); "no punches in 24 h" warn chip; pipelineAppBannerper 06 §S8. - A11y: label "Entrance gate — active — 412 punches today".
12. UndoBar
- Purpose: 4 s undo window after sweep/batch applies (00-shared/03 undo pattern).
- Props:
description,onUndo. - Behaviour: undo re-sends previous statuses via bulk (upsert-safe); expires after 4 s (00-shared/03 §F).
13. ReportJobCard (S5/S6)
- Purpose: async report job state (
report-job.schema.ts:13-18). - Props:
status(queued/processing/completed/failed),type(attendance_summary,report-job.schema.ts:8-9),result?,error?,onOpen. - Behaviour: queued/processing →
LinearProgressIndicator; failed →AppErrorStatecompact with servererrorstring; completed → open S6.
Shared-component usage map
| Needs | Shared component |
|---|---|
| Class picker rows | AppListTile + AppAvatar (initials from name) |
| Date/month pickers | AppDatePicker / AppTimePicker |
| Empty/error/loading | AppEmptyState, AppErrorState, AppSkeleton |
| Confirmations | AppDialog (batch overwrite confirm) |
| Selection bars, sheets | AppBottomSheet (S3), AppMenu (row context) |
| Status legend & stats | AppBadge, AppStatTile, AppCharts (S5/S6 bars) |
| KPI entry | AppBanner (pipeline warning, conflict) |