Module-specific widgets. Shared primitives (AppCard, AppChips,
AppBadge, AppListTile, AppButton, AppBottomSheet, AppMenu,
AppSnackbar, AppEmptyState, AppSkeleton, DatePicker, TimePicker,
SegmentedButton) are owned by 00-shared/03 ; this file only defines
leave-specific compositions on top of them. Tokens: 00-shared/02 .
Prop Value
Input status: 'pending' | 'approved' | 'rejected' | 'cancelled'
Render small pill: dot + label (see 11_Design_System_Mapping for colors)
Statuses pending (tertiary, filled dot), approved (success), rejected (error), cancelled (neutral/outlined — unreachable today, leave-request.schema.ts:11, rendered defensively)
Semantics label: "Status: pending"; never color-only
Tests unit: renders each status; snapshot
[CL] Casual Leave 8 / 12
├─ used 4 · carried 0
└─ [progress 66%]
Prop Value
Input LeaveBalanceEntry (leave.service.ts:66-74)
Variants carry-forward line shown only when carryForward
Behavior progress = daysUsed / daysPerYear clamped 0–1; over-entitlement clamps bar at 1 with error color
a11y combined Semantics label "Casual Leave, 8 of 12 days remaining"
Data: LeaveRequest fields used — leaveTypeId (resolved to code via types
cache), startDate, endDate, daysRequested, reason, status,
decisionNote (leave-request.schema.ts:16-48).
Layout: leading AppAvatar-style code badge, title <code> <range> · <days>d, subtitle reason (2-line), trailing StatusChip.
Slots: onTap, optional trailingActions (admin approve/reject menu).
Variants: ApprovalTile (adds requester line + balance hint (proposed) +
Approve/Reject buttons).
Data: substitution.schema.ts:14-47 — classId, subjectId, date,
startTime, endTime, notes, status.
Layout: title <subject> · <class>, subtitle <date> <startTime>–<endTime>,
trailing status chip (only assigned reachable, leave.service.ts:261).
Resolve class/subject names via their modules' caches (forward-looking).
Opens from ApprovalTile menu or row action.
Segmented choice approve | reject (leave-decision.dto.ts:4-7); when
reject → AppTextField note (optional, :14-17).
Confirm → AppButton "Confirm approve/reject" → callback; caller executes
PATCH /leave/requests/:id/approve.
Shows 409 error inline (already decided / insufficient balance /
self-decision, leave.service.ts:175-189).
Data: leave-type.schema.ts:9-25 — code, name, daysPerYear,
carryForward, maxCarryForward, isDefault (default types badge "Default").
Sub-line: "Carries forward up to 60 days" only when carryForward.
Cell: date number, up to 3 mini avatars, +N overflow; states:
today (outlined), leave-day (tinted), selected (filled).
Tap → callback with date; parent shows day detail list.
Data source is GET /leave/calendar payload (approved requests,
leave.service.ts:282-296).
Every component is stateless; state lives in Cubits (13_State_Management.md).
No business logic in widgets (dates/counts computed in models/services).
All components accept theme from AppTheme only; no hardcoded colors
(tokens per 00-shared/02).
Placeholder resolution (type code ↔ name, teacher id ↔ name) via injected
lookup services, never in-widget.
Shared (00-shared/03) Leave-specific (this file)
AppCard, AppListTile, AppChips, AppBadge, AppButton, AppMenu, AppBottomSheet, AppSnackbar, AppEmptyState, AppSkeleton, DatePicker, TimePicker, SegmentedButton, RefreshIndicator StatusChip, BalanceCard, RequestTile/ApprovalTile, SubstitutionTile, ApprovalActionSheet, LeaveTypeCard, CalendarDayCell, MonthGrid