feat(oxibadge): add timesheet review and export screen
Check, format and test / build (push) Successful in 10m16s

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>
This commit is contained in:
2026-10-07 15:56:25 +02:00
parent b4cd8e1796
commit acd3efeac6
19 changed files with 2664 additions and 36 deletions
+37 -8
View File
@@ -3,6 +3,7 @@ mod preferences;
use chrono::{Local, TimeZone};
use preferences::Reader;
use r701::{Record, R701};
use serde::Deserialize;
use std::collections::HashMap;
use tauri::AppHandle;
use tokio_stream::StreamExt;
@@ -75,14 +76,10 @@ async fn load_records(app: AppHandle, year: i32, month: u32) -> Result<Vec<Recor
records.reverse();
dbg!(&records);
Ok(records)
}
/// Resolves the name of every distinct employee in `records`, printing both
/// the records and the resulting employee map to stdout before returning
/// the map.
/// Resolves the name of every distinct employee in `records`.
#[tauri::command]
async fn load_employees(
app: AppHandle,
@@ -108,11 +105,42 @@ async fn load_employees(
}
}
dbg!(&employees);
Ok(employees)
}
/// One employee's corrected timesheet for a month, as sent by the review
/// screen's export button. `days[d][c]` is the list of times (usually 0
/// or 1, more if stacked) punched in slot `c` (entry/exit of the 1st/2nd
/// shift) on day `d + 1`.
///
/// For now `export_timesheet` only `dbg!`-prints this, so none of the
/// fields are read outside of the derived `Debug` impl (which the
/// dead-code lint deliberately ignores).
#[derive(Debug, Deserialize)]
#[allow(dead_code)]
struct EmployeeTimesheet {
id: u32,
name: String,
days: Vec<Vec<Vec<String>>>,
}
#[derive(Debug, Deserialize)]
struct ExportPayload {
scope: String,
year: i32,
month: u32,
employees: Vec<EmployeeTimesheet>,
}
/// Placeholder export: just prints each employee's corrected timesheet.
#[tauri::command]
fn export_timesheet(payload: ExportPayload) {
dbg!(&payload.scope, payload.year, payload.month);
for employee in &payload.employees {
dbg!(employee);
}
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
@@ -121,7 +149,8 @@ pub fn run() {
save_preferences,
test_connection,
load_records,
load_employees
load_employees,
export_timesheet
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
+2 -2
View File
@@ -13,8 +13,8 @@
"windows": [
{
"title": "Oxibadge",
"width": 800,
"height": 600
"width": 1200,
"height": 700
}
],
"security": {