reminder_cli/
reminder.rs

1use chrono::{DateTime, Local};
2use cron::Schedule;
3use serde::{Deserialize, Serialize};
4use std::str::FromStr;
5use uuid::Uuid;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Reminder {
9    pub id: Uuid,
10    pub title: String,
11    pub description: Option<String>,
12    pub schedule: ReminderSchedule,
13    pub created_at: DateTime<Local>,
14    pub next_trigger: Option<DateTime<Local>>,
15    pub completed: bool,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub enum ReminderSchedule {
20    OneTime(DateTime<Local>),
21    Cron(String),
22}
23
24impl Reminder {
25    pub fn new_one_time(
26        title: String,
27        description: Option<String>,
28        time: DateTime<Local>,
29    ) -> Self {
30        Self {
31            id: Uuid::new_v4(),
32            title,
33            description,
34            schedule: ReminderSchedule::OneTime(time),
35            created_at: Local::now(),
36            next_trigger: Some(time),
37            completed: false,
38        }
39    }
40
41    pub fn new_cron(
42        title: String,
43        description: Option<String>,
44        cron_expr: String,
45    ) -> anyhow::Result<Self> {
46        let schedule = Schedule::from_str(&cron_expr)?;
47        let next = schedule.upcoming(Local).next();
48        
49        Ok(Self {
50            id: Uuid::new_v4(),
51            title,
52            description,
53            schedule: ReminderSchedule::Cron(cron_expr),
54            created_at: Local::now(),
55            next_trigger: next,
56            completed: false,
57        })
58    }
59
60    pub fn calculate_next_trigger(&mut self) {
61        match &self.schedule {
62            ReminderSchedule::OneTime(_) => {
63                self.completed = true;
64                self.next_trigger = None;
65            }
66            ReminderSchedule::Cron(expr) => {
67                if let Ok(schedule) = Schedule::from_str(expr) {
68                    self.next_trigger = schedule.upcoming(Local).next();
69                }
70            }
71        }
72    }
73
74    pub fn is_due(&self) -> bool {
75        if self.completed {
76            return false;
77        }
78        if let Some(next) = self.next_trigger {
79            return Local::now() >= next;
80        }
81        false
82    }
83}