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 (Staff Module)

Per-screen state on top of the shared architecture (00-shared/06_State_Management.md). Stack: flutter_bloc Cubits, get_it DI, repository layer with dio.

1. Cubits

CubitScreenEventsState
StaffListCubitS1Load, Refresh, LoadMore, Retry, ChangeStatusFilter, ChangeTypeFilter, Search(q){loadState, items, page, hasNext, isLoadingMore, statusFilter, typeFilter, query, meta}
StaffDetailCubitS2Load(id), Retry{loadState, staff?, department?, designation?, user?}
StaffFormCubitS3/S4LoadRefs, Load(initial), Submit(delta), Clear{loadState, submitState, fields, users, departments, designations, fieldErrors}
DepartmentListCubitS6Load, Refresh, LoadMore, Retrypaginated + membersCountByDept (proposed)
DepartmentFormCubitS8Load(initial), Submit(delta)form state
DesignationListCubitS9Load, Refresh, LoadMore, Retrypaginated
DesignationFormCubitS11Load(initial), Submit(delta)form state
DeactivateCubitS5Confirm(id), Dismiss{idle, submitting, success, error}

Deactivate lives in its own cubit (not the list cubit) so the dialog state is independent and testable.

2. Async state machine (all cubits)

Initial → Loading → Success | Error(ApiException) (00-shared/06 §3.1); UI maps: Loading → AppSkeleton, Error → AppErrorState(code, retry), Success+empty → AppEmptyState, Success → content. Form cubits add submitState with fieldErrors mapped from ApiException.details (400 → error.details[], http-exception.filter.ts:103-107).

3. Pagination (mixin PaginatedListMixin<T>)

  • Contract: page/limit(20)/sort/q (00-shared/06 §3.2).
  • loadMore fires when meta.hasNext (pagination-query.dto.ts:52) and isLoadingMore == false; appends, dedupes by _id.
  • Refresh bypasses cache and resets to page 1.
  • Cache key: sl:{tenant}:staff:list:{page} per module cache rules (00-shared/06 §3.3).

4. Caching & staleness

DataTTL (proposed)Notes
Staff list pages5 minvolatile (status changes)
Department list24 hreference catalog (00-shared/06 §3.3)
Designation list24 hreference catalog
Staff detailno client cacherefetch per visit; server caches
Users (picker)24 hcross-module reference

Stale-while-revalidate: render cache instantly, refresh in background (00-shared/06 §3.3).

5. Optimistic updates

None. All mutations (create/update/deactivate) wait for the server envelope — status changes and deletes have downstream audit events (event-queue-map.ts:34-36) and no rollback path (00-shared/06 §3.5).

6. Cross-screen sync

  • StaffDetailCubit refreshes after a successful edit; StaffListCubit refreshes after create/delete (or removes the row locally on DELETE success — (proposed)).
  • Catalog changes (department/designation) invalidate the 24 h catalog cache so pickers show fresh options (00-shared/06 §3.3).
  • No WebSocket topics exist for staff (00-shared/07 §8 lists none) — no realtime updates; lists refresh on pull or refetch.

7. Error handling (module specifics)

CodeBehavior
400field errors onto fieldErrors; focus first invalid field
401interceptor refresh once; fail → re-login (00-shared/06 §3.6)
403hide actions (no staff.create → no FAB) + 403 screen if routed
404detail → not-found empty-state; deactivate → snackbar "Already deactivated"
409inline duplicate message on the field (00-shared/06 §5)
429backoff copy; no auto-retry
5xxgeneric + requestId (00-shared/06 §5)

8. Testing hooks

  • Cubits are pure Dart with mocked repositories (00-shared/06 §6); each list cubit has widget-test pairs for skeleton/error/empty/success permutations; deactivate cubit tested for 404 and success paths.
  • Repository mappers (envelope → model) unit-tested for all status/type enum values and missing refs.