The review screen now tracks whether there are edits not yet exported
and asks for confirmation before discarding them: clicking back, or
closing the app window entirely (intercepted via onCloseRequested,
which needed a core:window:allow-destroy capability that wasn't
granted by core:default). The confirmation dialog (ConfirmDialog.svelte)
is generic, built on a shared ModalFrame extracted from ExportModal so
the two don't duplicate the backdrop/box styling.
Also adds undo: a per-row button (icon-only, left of the note, shown
when that day has edits) reverts just that day instantly, and a
per-employee "undo all" (icon in a red box, last among the header's
tools) reverts every day for the current employee after a confirmation
dialog, since that one can't be undone itself.
ActionButton moves out of review/ next to IconButton/PillButton, since
ConfirmDialog (outside the review feature) now uses it too.
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Employee names are now cached locally (employees.toml, keyed by reader
index then employee id) instead of being re-fetched from the time
clock on every month: load_employees only asks the device for ids not
already in the cache. When a month has employees the cache doesn't
know yet, a new screen (NewEmployees.svelte) lets the user name them
before continuing to the review screen; the chosen names are local to
Oxibadge only, never written back to the device. The same cache can be
managed afterwards from a drawer reachable from the time clock card in
Settings ("Gestisci dipendenti"), reusing the rename-in-row pattern
from the original mockup.
Settings.readers is a list again (was flattened to a single `reader`
object) so multiple time clocks can be supported later; only the first
one is used today.
Also:
- buildEmployees() now derives the employee list from the month's
records instead of from every cached name ever seen, so the review
screen no longer shows employees unrelated to the selected month.
- Renaming an employee from the review screen's pencil button now
actually persists to the cache (the callback existed but was never
wired up).
- Translated to English a number of Rust/TS/Svelte comments that had
been written in Italian; only the i18n locale files should contain
Italian.
- Minor dedup: extracted PillButton.svelte (was duplicated inline in
ReaderCard), promoted the repeated .mono CSS rule to app.css, moved
initials() out of the review feature into $lib/text.ts.
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Add a settings screen (gear button on the month-confirmation screen)
to configure the expected shift times, the rounding step, the
interface language, and the time clock address — replacing the old
onboarding-only connection flow. Settings persist to the same
preferences.toml as the reader address, under a single load_settings/
save_settings command pair.
The review screen's "fix shifts" action now redistributes stacked
punches by nearest configured shift time instead of blind position,
and a stacked cell manually cleared down to one entry no longer
leaves a dangling empty input.
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Add the month-review screen shown after records/employees load: an
editable per-employee timesheet table with issue/rounding detection,
bulk fixes (reorder stacked punches, add lunch break, round to step),
and an export flow (single employee or all) wired to a new Rust
export_timesheet command. Split into focused components under
review/ instead of one large file, with shared i18n keys and a new
export_timesheet IPC command.
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
load_records/load_employees failures were only logged to the console
and silently reset the UI to the month picker. Errors now flow through
a shared store (src/lib/error.ts) into an ErrorBanner, reused by both
Onboarding and ConfirmMonth, with the raw message passed straight
through from Rust (no stable-code classification layer — these are
mostly plain I/O errors, not worth categorizing).
i18n stays grouped per screen as before, with error-related strings
split into their own top-level "errors" group.
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Adds the screen after onboarding: pick a month/year (ConfirmMonth), show
loading screens while the device is queried, then download that month's
records and resolve each distinct employee's name, printing both to
stdout (debug pretty-print) before landing on the placeholder "done"
screen.
- r701: RecordIterator's boxed stream is now Send, required for it to
cross into a Tauri command's future.
- oxibadge: load_records/load_employees commands, sharing the existing
3-retry connect_with_retries helper. load_records uses skip_while/
take_while on the device's newest-first stream to grab only the
target month without walking its whole history, then a single
collect + in-place Vec::reverse() back to chronological order.
- Shared LoadingScreen/Intro components extracted so future screens
reuse the same look without duplicating markup/CSS.
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Adds the first real screen: a setup form for the device's host/port,
tested against the real device (3 retries) and persisted to
preferences.toml before showing a placeholder "done" screen.
- Rust: test_connection/save_preferences/load_preferences commands;
preferences stored as [[reader]] in TOML so more readers can be
added later without a format change.
- Svelte: split the monolithic page into reusable components
(Screen, Column, Field, Button, ErrorBanner, Hint) under
src/lib/components, sharing design tokens from app.css.
- Automatic it/en i18n via svelte-i18n, locale detected from
navigator.language.
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Scaffolds the oxibadge crate/frontend as a new workspace member, stripped
down to a bare hello-world, and
extends the CI pipeline
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>