Compare commits

..

1 Commits

Author SHA1 Message Date
cuddle-please
b570d1d8e2 chore(release): 0.0.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-25 22:19:39 +00:00
3 changed files with 34 additions and 91 deletions

View File

@ -6,11 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.0.2] - 2025-03-26
### Added
- add current hours
## [0.0.1] - 2025-03-25 ## [0.0.1] - 2025-03-25
### Added ### Added

View File

@ -3,7 +3,7 @@ members = ["crates/*"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
version = "0.0.2" version = "0.0.1"
[workspace.dependencies] [workspace.dependencies]
clock = { path = "crates/clock" } clock = { path = "crates/clock" }

View File

@ -61,31 +61,28 @@ async fn main() -> anyhow::Result<()> {
match cli.command.expect("to have a command available") { match cli.command.expect("to have a command available") {
Commands::List { limit, project } => { Commands::List { limit, project } => {
let mut timetable = timetable.clone();
let days = &timetable let days = &timetable
.days .days
.iter_mut() .iter()
.map(|d| { .filter(|d| {
if let Some(project) = &project { if let Some(project) = &project {
d.entry = d Some(project) == d.project.as_ref()
.entry
.iter()
.filter(|d| d.project.as_ref() == Some(project))
.cloned()
.collect::<Vec<_>>();
d
} else { } else {
d true
} }
}) })
.filter(|d| !d.entry.is_empty())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let days = days.iter().rev().take(limit).collect::<Vec<_>>(); let days = days.iter().rev().take(limit).collect::<Vec<_>>();
for day in days { for day in days {
println!( println!(
"{}{}\n{}\n", "{}{}{}\n {}{}\n",
day.date.format("%Y-%m-%d"), day.clock_in.with_timezone(&Local {}).format("%Y-%m-%d"),
if let Some(project) = &day.project {
format!(" project: {}", project)
} else {
"".into()
},
if day.breaks.is_empty() { if day.breaks.is_empty() {
"".into() "".into()
} else { } else {
@ -94,64 +91,28 @@ async fn main() -> anyhow::Result<()> {
day.breaks.iter().fold(0, |acc, _| acc + 30) day.breaks.iter().fold(0, |acc, _| acc + 30)
) )
}, },
day.entry day.clock_in.with_timezone(&Local {}).format("%H:%M"),
.iter() if let Some(clockout) = &day.clock_out {
.map(|e| { format!(" - {}", clockout.with_timezone(&Local {}).format("%H:%M"))
format!( } else {
" - {} - {}{}", " - unclosed".into()
e.clock_in.with_timezone(&Local {}).format("%H:%M"), },
if let Some(clockout) = &e.clock_out {
clockout
.with_timezone(&Local {})
.format("%H:%M")
.to_string()
} else if day.date == now.date_naive() {
let working_hours = e.clock_in - now;
format!(
"unclosed, current hours: {}h{}m",
working_hours.num_hours().abs(),
working_hours.num_minutes().abs() % 60
)
} else {
"unclosed".into()
},
if let Some(project) = &e.project {
format!(": project: {}", project)
} else {
"".into()
}
)
})
.collect::<Vec<_>>()
.join("\n"),
) )
} }
} }
Commands::In { project } => { Commands::In { project } => {
match timetable.get_day(now) { timetable.days.push(Day {
Some(d) => { clock_in: now,
d.entry.push(ClockIn { clock_out: None,
clock_in: now, breaks: Vec::default(),
clock_out: None, project,
project, });
});
}
None => timetable.days.push(Day {
entry: vec![ClockIn {
clock_in: now,
clock_out: None,
project,
}],
breaks: Vec::default(),
date: now.date_naive(),
}),
};
} }
Commands::Out { project } => match timetable.get_day_entry(project, now) { Commands::Out { project } => match timetable.get_day(project, now) {
Some(day) => day.clock_out = Some(now), Some(day) => day.clock_out = Some(now),
None => todo!(), None => todo!(),
}, },
Commands::Break { project } => match timetable.get_day(now) { Commands::Break { project } => match timetable.get_day(project, now) {
Some(day) => day.breaks.push(Break {}), Some(day) => day.breaks.push(Break {}),
None => todo!(), None => todo!(),
}, },
@ -159,7 +120,6 @@ async fn main() -> anyhow::Result<()> {
let to_resolve = timetable let to_resolve = timetable
.days .days
.iter_mut() .iter_mut()
.flat_map(|d| &mut d.entry)
.filter(|d| d.clock_out.is_none()) .filter(|d| d.clock_out.is_none())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -244,18 +204,15 @@ fn parse_string_to_time(v: &str) -> anyhow::Result<chrono::NaiveTime> {
}) })
.context("failed to parse int to hour") .context("failed to parse int to hour")
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
struct ClockIn {
clock_in: chrono::DateTime<chrono::Utc>,
clock_out: Option<chrono::DateTime<chrono::Utc>>,
project: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
struct Day { struct Day {
date: chrono::NaiveDate, clock_in: chrono::DateTime<chrono::Utc>,
entry: Vec<ClockIn>, clock_out: Option<chrono::DateTime<chrono::Utc>>,
breaks: Vec<Break>, breaks: Vec<Break>,
project: Option<String>,
} }
#[derive(Default, Clone, Debug, Serialize, Deserialize)] #[derive(Default, Clone, Debug, Serialize, Deserialize)]
@ -267,21 +224,12 @@ struct TimeTable {
} }
impl TimeTable { impl TimeTable {
pub fn get_day(&mut self, now: chrono::DateTime<chrono::Utc>) -> Option<&mut Day> { pub fn get_day(
let item = self
.days
.iter_mut()
.find(|d| d.date.format("%Y-%m-%d").to_string() == now.format("%Y-%m-%d").to_string());
item
}
pub fn get_day_entry(
&mut self, &mut self,
project: Option<String>, project: Option<String>,
now: chrono::DateTime<chrono::Utc>, now: chrono::DateTime<chrono::Utc>,
) -> Option<&mut ClockIn> { ) -> Option<&mut Day> {
let item = self.days.iter_mut().flat_map(|d| &mut d.entry).find(|d| { let item = self.days.iter_mut().find(|d| {
if d.project != project { if d.project != project {
return false; return false;
} }