Skip to content

Commit 6a01320

Browse files
committed
feat(add): show target exit time on IN and refactor event creation
- display calculated target exit time (TGT) when adding an IN event - reuse existing time helpers for target formatting - unify IN/OUT event creation via shared CLI helper - remove duplicated upsert logic with a generic helper
1 parent 7f20987 commit 6a01320

File tree

4 files changed

+82
-87
lines changed

4 files changed

+82
-87
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rtimelogger"
3-
version = "0.8.4"
3+
version = "0.8.5"
44
edition = "2024"
55
authors = ["Umpire274 <umpire274@gmail.com>"]
66
description = "A simple cross-platform CLI tool to track working hours, lunch breaks, and calculate surplus time"
@@ -25,7 +25,7 @@ winresource = "0.1.28"
2525
OriginalFilename = "rtimelogger.exe"
2626
FileDescription = "rTimelogger - Time Tracking Utility"
2727
ProductName = "rTimelogger"
28-
ProductVersion = "0.8.4"
28+
ProductVersion = "0.8.5"
2929
LegalCopyright = "© 2025 Alessandro Maestri"
3030
Icon = "res/rtimelogger.ico"
3131

src/cli/commands/add.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub fn handle(cmd: &Commands, cfg: &crate::config::Config) -> AppResult<()> {
7070
// 7. Execute logic
7171
//
7272
AddLogic::apply(
73+
cfg,
7374
&mut pool,
7475
d,
7576
pos_final,

src/core/add.rs

Lines changed: 78 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
use crate::config::Config;
2+
use crate::core::logic::Core;
13
use crate::db::pool::DbPool;
24
use crate::db::queries::{insert_event, load_events_by_date, load_pair_by_index};
35
use crate::errors::{AppError, AppResult};
46
use crate::models::event::{Event, EventExtras};
57
use crate::models::event_type::EventType;
68
use crate::models::location::Location;
79
use crate::ui::messages::success;
8-
use chrono::{NaiveDate, NaiveTime};
10+
use chrono::{NaiveDate, NaiveTime, Timelike};
911
use rusqlite::params;
1012

1113
/// High-level business logic for the `add` command.
@@ -20,9 +22,42 @@ fn upsert_event(conn: &rusqlite::Connection, ev: &Event) -> AppResult<()> {
2022
Ok(())
2123
}
2224

25+
fn build_event_cli(
26+
date: NaiveDate,
27+
time: NaiveTime,
28+
kind: EventType,
29+
location: Location,
30+
event_extras: EventExtras,
31+
) -> Event {
32+
Event::new(0, date, time, kind, location, event_extras)
33+
}
34+
35+
fn extras_cli(lunch: Option<i32>, work_gap: bool) -> EventExtras {
36+
EventExtras {
37+
lunch,
38+
work_gap,
39+
source: Some("cli".to_string()),
40+
meta: None,
41+
..Default::default()
42+
}
43+
}
44+
45+
fn upsert_event_time(
46+
slot: &mut Option<Event>,
47+
date: NaiveDate,
48+
time: NaiveTime,
49+
kind: EventType,
50+
location: Location,
51+
extras: EventExtras,
52+
) {
53+
let e = slot.get_or_insert_with(|| build_event_cli(date, time, kind, location, extras));
54+
e.time = time;
55+
}
56+
2357
impl AddLogic {
2458
#[allow(clippy::too_many_arguments)]
2559
pub fn apply(
60+
cfg: &Config,
2661
pool: &mut DbPool,
2762
date: NaiveDate,
2863
position: Location,
@@ -66,48 +101,29 @@ impl AddLogic {
66101
}
67102
}
68103

104+
// IN time
69105
// IN time
70106
if let Some(start_time) = start {
71-
if let Some(ref mut e) = ev_in {
72-
e.time = start_time;
73-
} else {
74-
ev_in = Some(Event::new(
75-
0,
76-
date,
77-
start_time,
78-
EventType::In,
79-
pos_final,
80-
EventExtras {
81-
lunch, // if user passed --lunch in edit mode, keep it on IN creation
82-
work_gap: false,
83-
source: Some("cli".to_string()),
84-
meta: None,
85-
..Default::default()
86-
},
87-
));
88-
}
107+
upsert_event_time(
108+
&mut ev_in,
109+
date,
110+
start_time,
111+
EventType::In,
112+
pos_final,
113+
extras_cli(lunch, false),
114+
);
89115
}
90116

91117
// OUT time
92118
if let Some(end_time) = end {
93-
if let Some(ref mut e) = ev_out {
94-
e.time = end_time;
95-
} else {
96-
ev_out = Some(Event::new(
97-
0,
98-
date,
99-
end_time,
100-
EventType::Out,
101-
pos_final,
102-
EventExtras {
103-
lunch: Some(0),
104-
work_gap: false,
105-
source: Some("cli".to_string()),
106-
meta: None,
107-
..Default::default()
108-
},
109-
));
110-
}
119+
upsert_event_time(
120+
&mut ev_out,
121+
date,
122+
end_time,
123+
EventType::Out,
124+
pos_final,
125+
extras_cli(Some(0), false), // se vuoi preservare la tua semantica OUT default
126+
);
111127
}
112128

113129
// LUNCH (applies to OUT; coherent with your current model)
@@ -188,19 +204,12 @@ impl AddLogic {
188204
let holiday_time = NaiveTime::from_hms_opt(0, 0, 0)
189205
.ok_or_else(|| AppError::Other("Invalid holiday time sentinel.".into()))?;
190206

191-
let ev_holiday = Event::new(
192-
0,
207+
let ev_holiday = build_event_cli(
193208
date,
194209
holiday_time,
195-
EventType::In, // sentinel kind
210+
EventType::In,
196211
pos_final,
197-
EventExtras {
198-
lunch: Some(0),
199-
work_gap: false,
200-
source: Some("cli".to_string()),
201-
meta: None,
202-
..Default::default()
203-
},
212+
extras_cli(lunch, false),
204213
);
205214

206215
insert_event(&pool.conn, &ev_holiday)?;
@@ -254,25 +263,31 @@ impl AddLogic {
254263
if let Some(start_time) = start
255264
&& end.is_none()
256265
{
257-
let ev_in = Event::new(
258-
0,
266+
let ev_in = build_event_cli(
259267
date,
260268
start_time,
261269
EventType::In,
262270
pos_final,
263-
EventExtras {
264-
lunch: Some(lunch_val),
265-
work_gap: false,
266-
source: Some("cli".to_string()),
267-
meta: None,
268-
..Default::default()
269-
},
271+
extras_cli(lunch, false),
270272
);
271273

272274
insert_event(&pool.conn, &ev_in)?;
273275
crate::db::queries::recalc_pairs_for_date(&mut pool.conn, &date)?;
274276

275-
success(format!("Added IN at {} on {}.", start_time, date_str));
277+
// --- Compute TGT (same logic as list: uses summary.expected) ---
278+
let events_after = load_events_by_date(pool, &date)?;
279+
let summary = Core::build_daily_summary(&events_after, cfg);
280+
281+
let tgt_time = start_time + chrono::Duration::minutes(summary.expected);
282+
283+
// Usa helper esistente: minuti da mezzanotte -> "HH:MM"
284+
let tgt_mins = (tgt_time.hour() as i64) * 60 + (tgt_time.minute() as i64);
285+
let tgt_str = crate::utils::time::format_minutes(tgt_mins);
286+
287+
success(format!(
288+
"✅ Added IN at {} on {}. TGT => {}",
289+
start_time, date_str, tgt_str
290+
));
276291
return Ok(());
277292
}
278293

@@ -302,19 +317,12 @@ impl AddLogic {
302317
last_in.location
303318
};
304319

305-
let ev_out = Event::new(
306-
0,
320+
let ev_out = build_event_cli(
307321
date,
308322
end_time,
309323
EventType::Out,
310324
out_position,
311-
EventExtras {
312-
lunch: Some(lunch_val),
313-
work_gap: wg,
314-
source: Some("cli".to_string()),
315-
meta: None,
316-
..Default::default()
317-
},
325+
extras_cli(lunch, false),
318326
);
319327

320328
insert_event(&pool.conn, &ev_out)?;
@@ -333,34 +341,20 @@ impl AddLogic {
333341
return Err(AppError::InvalidArgs("END must be later than IN.".into()));
334342
}
335343

336-
let ev_in = Event::new(
337-
0,
344+
let ev_in = build_event_cli(
338345
date,
339346
start_time,
340347
EventType::In,
341348
pos_final,
342-
EventExtras {
343-
lunch: Some(lunch_val),
344-
work_gap: false,
345-
source: Some("cli".to_string()),
346-
meta: None,
347-
..Default::default()
348-
},
349+
extras_cli(lunch, false),
349350
);
350351

351-
let ev_out = Event::new(
352-
0,
352+
let ev_out = build_event_cli(
353353
date,
354354
end_time,
355355
EventType::Out,
356356
pos_final,
357-
EventExtras {
358-
lunch: Some(0),
359-
work_gap: wg,
360-
source: Some("cli".to_string()),
361-
meta: None,
362-
..Default::default()
363-
},
357+
extras_cli(lunch, false),
364358
);
365359

366360
insert_event(&pool.conn, &ev_in)?;

0 commit comments

Comments
 (0)