Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

13 — State Management (Teachers Module)

Extends 00-shared/06. Bloc/Cubit, one cubit per screen; repository layer only place touching HTTP; typed ApiException(code, status, fieldDetails).


1. Cubits

CubitScreenStateNotes
TeachersListCubitS1TeachersListStatepaginated mixin + filters
TeacherDetailCubitS2–S4TeacherDetailStatetabs, year selection
TeacherFormCubitS5/S6TeacherFormStatecreate/update + dirty tracking
AssignmentEditorCubitS7AssignmentEditorStatepickers + duplicate guard
AssignmentsTabCubitS3AssignmentsTabStateyear-keyed matrix
ScheduleTabCubitS4ScheduleTabStateweek grid
MyTeachingCubitS9/S10 (planned)MyTeachingStatecomposed self-view

2. State classes

// S1
class TeachersListState {
  LoadState load;            // Initial | Loading | Success | Error
  List<Teacher> items;       // merged pages
  int page; bool hasNext;
  List<EmploymentStatus> statusFilter;
  String? departmentId, designationId, query;  // client-side filters (OQ-3)
}

// S2–S4
class TeacherDetailState {
  LoadState load;
  Teacher? teacher;
  int tabIndex;                       // 0 profile, 1 assignments, 2 schedule
  AcademicYear currentYear;           // default isCurrent
  List<SubjectAssignment>? assignments;
  List<TimetableEntry>? timetable;
  int yearRequestToken;               // drop stale year-switch responses
}

// S5/S6
class TeacherFormState {
  LoadState submit;                  // idle | submitting | success | error
  TeacherFormData data;              // field DTO mirror (F1/F2)
  Map<String, String> fieldErrors;   // from 400 details
  ConflictType? conflict;            // user | employeeNumber (409)
  bool dirty;
}

// S7
class AssignmentEditorState {
  LoadState submit;
  String? subjectId, classId, academicYearId;
  bool duplicateDetected;            // client-side (server gap, OQ-2)
}

3. Repository & cache keys

class TeacherRepository {
  Future<Page<Teacher>> list({page, limit});          // GET /teachers
  Future<Teacher> byId(String id);                    // GET /teachers/:id
  Future<Teacher> create(TeacherDraft dto);           // POST /teachers
  Future<Teacher> update(String id, TeacherPatch dto);// PATCH /teachers/:id
  Future<void> remove(String id);                     // DELETE /teachers/:id
  Future<List<SubjectAssignment>> assignmentsByTeacher(String teacherId, String yearId);
  Future<SubjectAssignment> createAssignment(CreateSubjectAssignmentDto dto);
  Future<void> removeAssignment(String id);
}
Cache keyTTLPolicy
sl:{tenant}:teachers:page:{n}5 minstale-while-revalidate (06 §3.3)
sl:{tenant}:teachers:refs:{depts|designations|subjects|classes|years}24 hreference data
sl:{tenant}:teachers:assignments:{teacherId}:{year}5 minvolatile matrix
detail teachers:{id}noneserver-fresh on every visit

RefreshIndicator always bypasses cache (06 §3.3).

4. Events

  • LoadTeachers, LoadMore, RefreshTeachers, ChangeStatusFilter(dept, designation), Search(q), ClearFilters
  • LoadTeacher(id), ChangeTab(i), ChangeYear(yearId), RefreshTab
  • SubmitCreate(draft), SubmitUpdate(patch), Discard
  • SelectSubject/Class/Year, AddAssignment, RemoveAssignment(id)
  • Naming per 00-shared/06 §4.

5. Realtime / cross-cubit

  • notification.new (WS, 00-shared/07 §8) for own tenant → teachers list marks refresh-needed badge (planned); no live row mutation (soft-delete is 404-driven).
  • Dashboard teachers.total refreshes on TeacherCreated/Deleted events when dashboard visible (via DashboardCubit refresh — dashboard.service.ts:32).

6. Optimistic policy (module)

ActionOptimistic?
List filters, search, year switchyes (local state)
Assignment add/removeno — server-confirmed (no server dedup; confirm before UI change)
Teacher create/updateno
Deactivateno (irreversible)
Pull-to-refreshcache-bypass reload

7. Error handling

  • 409 conflict → form-level state (ConflictType), never clears fields.
  • 400 → fieldErrors from error.details (00-shared/07 §3).
  • 404 → detail/list treat as removed: navigate back with snackbar.
  • 401 → AuthCubit refresh; fail → session expiry.
  • 5xx → AppErrorState with requestId; retry re-emits Load event.

8. Testing hooks

  • TeachersListCubit pure-Dart unit tests (mock TeacherRepository): pagination merge, filter application, duplicate detection, conflict mapping.
  • Widget tests: S1 3-state (loading/error/empty), S5 409-banner, S7 duplicate-block.
  • AppStateObserver transition logs dev-only (06 §6).