160 lines
7.1 KiB
Markdown
160 lines
7.1 KiB
Markdown
# KROW Worker
|
|
|
|
A Flutter app for shift workers: find hospitality shifts, clock in on site, get
|
|
timecards filed automatically, and keep compliance documents in order.
|
|
|
|
Built from the workflow in the KROW worker-app prototype — the HTML was used as
|
|
the reference for screens and flow, not as a pixel spec.
|
|
|
|
## Running it
|
|
|
|
```bash
|
|
flutter pub get
|
|
flutter run
|
|
```
|
|
|
|
Targets Android, iOS and web. To try it in a browser:
|
|
|
|
```bash
|
|
flutter run -d chrome
|
|
```
|
|
|
|
**Demo sign-in:** any 10-digit mobile number, then the code `123456`.
|
|
|
|
## What works
|
|
|
|
Everything below is wired to real state, not static screens. Shifts, timecards
|
|
and compliance live in memory for the session; onboarding, sign-in,
|
|
availability, skills and preferences persist via `shared_preferences`.
|
|
|
|
**Getting in** — splash routes by how far you got last time · 3-screen
|
|
onboarding with skip · phone entry with validation · OTP with a resend
|
|
countdown, a wrong-code path and a 3-try budget · 3-step permission run whose
|
|
grants are recorded and reflected in Settings.
|
|
|
|
**Today** — greeting, period earnings and hours logged, a compliance nudge while
|
|
anything is outstanding, your next shift, quick tiles and matched open shifts.
|
|
|
|
**Shifts** — Booked / Open / History. The week strip filters booked shifts by
|
|
day and dots the days that have work. Open supports search and filters, and
|
|
Apply books the shift immediately. History carries completed, cancelled and
|
|
no-show shifts with a stat rail.
|
|
|
|
**Shift detail** — full schedule and pay breakdown, plus a requirements check
|
|
that compares what the business asks for against what you actually have on
|
|
file. Actions change with status: apply, cancel (with confirmation), or jump to
|
|
the clock.
|
|
|
|
**Clock** — the button unlocks 30 minutes before the shift, and only once you
|
|
are at the venue. Clocking in starts a live stopwatch against a progress ring;
|
|
clocking out completes the shift, deducts the unpaid break and files a timecard.
|
|
|
|
**Timecards** — every filed card with its scheduled vs clocked window, variance
|
|
in minutes, and pay. Review one to approve it or raise a dispute with a note.
|
|
The tab badge counts what is still waiting on you.
|
|
|
|
**Pay** — gross pre-tax earnings across week / month / year / all, a trend chart
|
|
split paid vs pending, per-payment detail, and a semi-monthly payroll schedule
|
|
that computes the current and next period from today's date.
|
|
|
|
**Profile & compliance** — live stats and a trust index derived from the shifts
|
|
you have actually worked. The compliance hub tracks documents, certificates, tax
|
|
forms and attire; uploading sends an item back for review, removing it drops it
|
|
to missing, and expiry dates are picked from a calendar. Plus emergency
|
|
contacts, experience and skills, availability, benefits, direct deposit,
|
|
settings, support, FAQs and privacy.
|
|
|
|
## Motion
|
|
|
|
Motion is used to explain what changed, not to decorate. The rules:
|
|
|
|
- **Going deeper pushes.** Detail screens slide in from the right while the
|
|
screen behind eases back and dims, so the stack reads as a stack. Going
|
|
sideways — sign-up steps, replacing a screen — cross-fades instead.
|
|
- **Selection travels.** The bottom nav indicator and the segmented controls
|
|
slide between positions and squash slightly at speed. Labels light up as the
|
|
indicator arrives over them, driven by the same animated value, so nothing
|
|
changes ahead of the thing causing it.
|
|
- **Numbers grow.** Progress bars and chart bars tween to new values, so an
|
|
uploaded document or a switched pay range is something you watch happen.
|
|
- **State changes animate together.** Availability blocks, week-strip days and
|
|
the clock dial move every part of themselves in one gesture rather than
|
|
flipping several properties at once.
|
|
- **Consequential actions are felt.** Clocking in and out give a medium impact;
|
|
selecting a tab, segment, or applying for a shift gives a selection click.
|
|
|
|
**Headers stay put.** On the five tabs the blue header is pinned: content
|
|
scrolls beneath it rather than pushing it off the top. A tall header held at
|
|
full size would cost a quarter of a phone screen for the whole session, so it
|
|
collapses as you scroll and cross-fades to a compact bar that keeps what still
|
|
matters — your name and the period figure on Today, the gross total on Pay.
|
|
|
|
Where a header holds a control, the collapsed state keeps it. Pay stops
|
|
shrinking while the range switcher is still on screen; collapsing that away
|
|
would mean scrolling back to the top just to change what you are looking at.
|
|
Shifts keeps its whole header fixed for the same reason — the Booked / Open /
|
|
History switch has to stay reachable.
|
|
|
|
Scrolling uses bouncing physics on every platform (`KrowScrollBehavior`). Under
|
|
a pinned header a rubber-band edge tells you that you have reached the end of
|
|
the content rather than the end of the screen; clamping just stops dead. The
|
|
overscroll glow is turned off, since the bounce already says it.
|
|
|
|
Two deliberate exceptions:
|
|
|
|
- **Tab content does not slide.** Switching bottom tabs fades and lifts the
|
|
content instead. An `AnimatedSwitcher` would hold two copies of the shell in
|
|
the tree, and the branch navigators are keyed by `GlobalKey`, so duplicating
|
|
them throws. `_TabTransition` animates one subtree in place, which keeps each
|
|
tab's scroll position.
|
|
- **No `Hero` between list and detail.** The tab branches all stay alive in an
|
|
`IndexedStack`, so the same shift can be on screen in two branches at once
|
|
and duplicate hero tags would throw.
|
|
|
|
## Layout
|
|
|
|
```
|
|
lib/
|
|
core/ theme, router, formatters
|
|
models/ shift, timecard, availability, compliance, worker
|
|
state/ Riverpod controllers + seed data
|
|
screens/ one file per area of the app
|
|
widgets/ shift card, week strip, shared pieces
|
|
```
|
|
|
|
## Packages
|
|
|
|
| Package | Why |
|
|
| --- | --- |
|
|
| `flutter_riverpod` | State: shifts, timecards, availability, compliance, profile, session |
|
|
| `go_router` | Routing, including the 5-tab shell where each tab keeps its own stack |
|
|
| `google_fonts` | Poppins, the brand typeface |
|
|
| `lucide_icons_flutter` | Icon set matching the prototype's line icons |
|
|
| `intl` | Currency, date and time formatting |
|
|
| `shared_preferences` | Persisting session, availability and preferences |
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
flutter test
|
|
```
|
|
|
|
Covers pay calculation (break deduction, clocked vs scheduled hours, zero-pay
|
|
states), timecard variance, and the formatters — plus the custom nav and
|
|
segmented control: that the indicator actually travels rather than jumping,
|
|
that taps report the right index, and that each tab reaches the semantics tree
|
|
with its selected state (the dot alone is not readable).
|
|
|
|
## Wiring it to a backend
|
|
|
|
The seams are deliberate. `lib/state/seed.dart` is the only source of demo data;
|
|
swap each controller's `build()` for an API call and the screens are unchanged.
|
|
Two places currently stand in for device APIs:
|
|
|
|
- **Geofence** — `ClockScreen` has an "at the venue" switch in place of GPS.
|
|
Replace with `geolocator` and a 150 m radius check against the venue.
|
|
- **File upload** — the compliance sheet fakes a filename. Replace with
|
|
`image_picker` / `file_picker` and a real upload.
|
|
|
|
Notifications and SMS verification are also stubbed: the OTP is always `123456`.
|