feat: implement automatic date status determination
This commit is contained in:
1 parent
09de9fcf91
commit
67d0f766f8
3 files changed
+87
-24
No files matched your search
@@ -1,3 +1,4 @@
|
|||||||
|
use chrono::{DateTime, FixedOffset};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -8,17 +9,17 @@ pub struct DateInfo {
|
|||||||
pub(crate) date: DateRange,
|
pub(crate) date: DateRange,
|
||||||
#[serde(rename = "desc")]
|
#[serde(rename = "desc")]
|
||||||
pub(crate) description: String,
|
pub(crate) description: String,
|
||||||
#[serde(rename = "stat")]
|
|
||||||
pub(crate) status: DateStatus,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum DateRange {
|
pub enum DateRange {
|
||||||
Single(String),
|
Single(DateTime<FixedOffset>),
|
||||||
Range(String, String),
|
Range(DateTime<FixedOffset>, DateTime<FixedOffset>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum DateStatus {
|
pub enum DateStatus {
|
||||||
|
Blank,
|
||||||
Upcoming,
|
Upcoming,
|
||||||
Open,
|
Open,
|
||||||
Deadline,
|
Deadline,
|
||||||
|
|||||||
+45
-5
@@ -1,18 +1,57 @@
|
|||||||
|
use chrono::Local;
|
||||||
use crate::common::{DateInfo, DateRange, DateStatus};
|
use crate::common::{DateInfo, DateRange, DateStatus};
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
|
||||||
fn render_dates(dates: DateRange) -> impl IntoView {
|
fn render_dates(dates: DateRange) -> impl IntoView {
|
||||||
let date_text = match dates {
|
let date_text = match dates {
|
||||||
DateRange::Single(date) => date,
|
DateRange::Single(date) => format!("{}", date.format("%A %B %d, %I:%M%p")),
|
||||||
DateRange::Range(start_date, end_date) =>
|
DateRange::Range(start_date, end_date) =>
|
||||||
format!("{} - {}", start_date, end_date),
|
format!("{} - {}",
|
||||||
|
start_date.format("%D %I:%M%p"),
|
||||||
|
end_date.format("%D %I:%M%p")
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
view! { <span>{move || date_text.clone()}</span> }
|
view! { <span>{move || date_text.clone()}</span> }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_status(status: DateStatus) -> impl IntoView {
|
fn get_date_status(date: &DateRange) -> DateStatus {
|
||||||
let status_text = match status {
|
// We need a threshold - maybe within 5 days, the status is deadline,
|
||||||
|
// further away is open, upcoming is when the range has not started yet,
|
||||||
|
// and closed is past the date.
|
||||||
|
|
||||||
|
match date {
|
||||||
|
DateRange::Single(_) => DateStatus::Blank,
|
||||||
|
DateRange::Range(start_date, end_date) => {
|
||||||
|
let local = Local::now();
|
||||||
|
// Check the amount of time from now to the start date. Values that are negative
|
||||||
|
// indicate that the start date has already passed.
|
||||||
|
if dbg!(start_date.signed_duration_since(local).num_days()) > 0 {
|
||||||
|
DateStatus::Upcoming
|
||||||
|
} else {
|
||||||
|
// Check the amount of time from now to the end date. The value will be positive if
|
||||||
|
// the end date is in the future. We will be specific to the minute.
|
||||||
|
let duration_until = dbg!(end_date).signed_duration_since(local);
|
||||||
|
let num_days = dbg!(duration_until.num_days());
|
||||||
|
let num_mins = dbg!(duration_until.num_minutes());
|
||||||
|
|
||||||
|
if num_mins <= 0 {
|
||||||
|
DateStatus::Closed
|
||||||
|
} else if num_days <= 5 {
|
||||||
|
DateStatus::Deadline
|
||||||
|
} else {
|
||||||
|
DateStatus::Open
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_status(date: DateRange) -> impl IntoView {
|
||||||
|
let status = get_date_status(&date);
|
||||||
|
|
||||||
|
let status_text = match dbg!(status.clone()) {
|
||||||
|
DateStatus::Blank => "",
|
||||||
DateStatus::Upcoming => "Upcoming",
|
DateStatus::Upcoming => "Upcoming",
|
||||||
DateStatus::Open => "Open",
|
DateStatus::Open => "Open",
|
||||||
DateStatus::Deadline => "Deadline",
|
DateStatus::Deadline => "Deadline",
|
||||||
@@ -20,6 +59,7 @@ fn render_status(status: DateStatus) -> impl IntoView {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let background_class = match status {
|
let background_class = match status {
|
||||||
|
DateStatus::Blank => "hidden border-none",
|
||||||
DateStatus::Upcoming => "bg-yellow-100 text-yellow-800 border-yellow-100",
|
DateStatus::Upcoming => "bg-yellow-100 text-yellow-800 border-yellow-100",
|
||||||
DateStatus::Open => "bg-green-100 text-green-800 border-green-100",
|
DateStatus::Open => "bg-green-100 text-green-800 border-green-100",
|
||||||
DateStatus::Deadline | DateStatus::Closed => "bg-red-100 text-red-800 border-red-100",
|
DateStatus::Deadline | DateStatus::Closed => "bg-red-100 text-red-800 border-red-100",
|
||||||
@@ -72,7 +112,7 @@ fn Date(
|
|||||||
</h3>
|
</h3>
|
||||||
<p class="text-sm text-gray-600">{info.get().description}</p>
|
<p class="text-sm text-gray-600">{info.get().description}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-shrink-0 ml-2">{move || render_status(info.get().status)}</div>
|
<div class="flex-shrink-0 ml-2">{move || render_status(info.get().date)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+37
-15
@@ -1,4 +1,5 @@
|
|||||||
use crate::common::{DateInfo, DateRange, DateStatus};
|
use chrono::DateTime;
|
||||||
|
use crate::common::{DateInfo, DateRange};
|
||||||
use crate::components::{DashboardButton, DateList};
|
use crate::components::{DashboardButton, DateList};
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
|
||||||
@@ -37,32 +38,53 @@ pub fn TestPage() -> impl IntoView {
|
|||||||
<div class="flex flex-col p-3 gap-3">
|
<div class="flex flex-col p-3 gap-3">
|
||||||
<DateList dates=vec![
|
<DateList dates=vec![
|
||||||
DateInfo {
|
DateInfo {
|
||||||
title: "Title".to_string(),
|
title: "Open Example".to_string(),
|
||||||
date: DateRange::Range(
|
date: DateRange::Range(
|
||||||
"February 2nd, 2026".to_string(),
|
DateTime::parse_from_rfc3339("2026-01-15T07:15:00-05:00")
|
||||||
"February 10th, 2026".to_string(),
|
.unwrap_or_default(),
|
||||||
|
DateTime::parse_from_rfc3339("2026-01-30T14:05:00-05:00")
|
||||||
|
.unwrap_or_default()
|
||||||
),
|
),
|
||||||
description: "This is a test".to_string(),
|
description: "This is a test".to_string(),
|
||||||
status: DateStatus::Upcoming,
|
|
||||||
},
|
},
|
||||||
DateInfo {
|
DateInfo {
|
||||||
title: "Scholarships Due".to_string(),
|
title: "Closed Example".to_string(),
|
||||||
date: DateRange::Single("November 4th, 2025".to_string()),
|
date: DateRange::Range(
|
||||||
description: "This is a test".to_string(),
|
DateTime::parse_from_rfc3339("2026-01-01T07:15:00-05:00")
|
||||||
status: DateStatus::Open,
|
.unwrap_or_default(),
|
||||||
|
DateTime::parse_from_rfc3339("2026-01-14T14:05:00-05:00")
|
||||||
|
.unwrap_or_default()
|
||||||
|
),
|
||||||
|
description: "".to_string(),
|
||||||
},
|
},
|
||||||
DateInfo {
|
DateInfo {
|
||||||
title: "Scholarships Due".to_string(),
|
title: "Deadline Example".to_string(),
|
||||||
date: DateRange::Single("November 4th, 2025".to_string()),
|
date: DateRange::Range(
|
||||||
|
DateTime::parse_from_rfc3339("2026-01-15T07:15:00-05:00")
|
||||||
|
.unwrap_or_default(),
|
||||||
|
DateTime::parse_from_rfc3339("2026-01-20T14:05:00-05:00")
|
||||||
|
.unwrap_or_default()
|
||||||
|
),
|
||||||
description: "This is a test".to_string(),
|
description: "This is a test".to_string(),
|
||||||
status: DateStatus::Deadline,
|
|
||||||
},
|
},
|
||||||
DateInfo {
|
DateInfo {
|
||||||
title: "Scholarships Due".to_string(),
|
title: "Upcoming Example".to_string(),
|
||||||
date: DateRange::Single("November 4th, 2025".to_string()),
|
date: DateRange::Range(
|
||||||
|
DateTime::parse_from_rfc3339("2026-01-30T07:15:00-05:00")
|
||||||
|
.unwrap_or_default(),
|
||||||
|
DateTime::parse_from_rfc3339("2026-02-20T14:05:00-05:00")
|
||||||
|
.unwrap_or_default()
|
||||||
|
),
|
||||||
description: "This is a test".to_string(),
|
description: "This is a test".to_string(),
|
||||||
status: DateStatus::Closed,
|
|
||||||
},
|
},
|
||||||
|
DateInfo {
|
||||||
|
title: "Single Date (Blank)".to_string(),
|
||||||
|
date: DateRange::Single(
|
||||||
|
DateTime::parse_from_rfc3339("2026-01-15T14:05:00-05:00")
|
||||||
|
.unwrap_or_default()
|
||||||
|
),
|
||||||
|
description: "".to_string(),
|
||||||
|
}
|
||||||
] />
|
] />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user