feat: sort dates list before displaying the list

This commit is contained in:
alphafetus committed 2026-01-15 13:57:59 -05:00
1 parent f15d151694
commit 7d7c96e642
4 files changed
+150 -99

No files matched your search

+48 -12
View File
@@ -1,14 +1,20 @@
use chrono::{DateTime, FixedOffset}; use chrono::{DateTime, FixedOffset, Local};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DateInfo { pub struct DateInfo {
#[serde()] pub id: String,
pub(crate) title: String, pub title: String,
#[serde(rename = "date")] pub date: DateRange,
pub(crate) date: DateRange, pub description: String,
#[serde(rename = "desc")] }
pub(crate) description: String,
impl DateInfo {
pub fn get_start_date(&self) -> DateTime<FixedOffset> {
match self.date {
DateRange::Single(date) | DateRange::Range(date, _) => date,
}
}
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -17,11 +23,41 @@ pub enum DateRange {
Range(DateTime<FixedOffset>, DateTime<FixedOffset>), Range(DateTime<FixedOffset>, DateTime<FixedOffset>),
} }
#[derive(Debug, Clone, Serialize, Deserialize)] impl DateRange {
pub fn get_status(&self) -> DateStatus {
match self {
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
}
}
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Ord)]
pub enum DateStatus { pub enum DateStatus {
Closed,
Deadline,
Open,
Upcoming,
Blank, Blank,
Upcoming,
Open,
Deadline,
Closed,
} }
+3 -35
View File
@@ -1,4 +1,3 @@
use chrono::Local;
use crate::common::{DateInfo, DateRange, DateStatus}; use crate::common::{DateInfo, DateRange, DateStatus};
use leptos::prelude::*; use leptos::prelude::*;
@@ -15,40 +14,8 @@ fn render_dates(dates: DateRange) -> impl IntoView {
view! { <span>{move || date_text.clone()}</span> } view! { <span>{move || date_text.clone()}</span> }
} }
fn get_date_status(date: &DateRange) -> DateStatus {
// 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 { fn render_status(date: DateRange) -> impl IntoView {
let status = get_date_status(&date); let status = date.get_status();
let status_text = match dbg!(status.clone()) { let status_text = match dbg!(status.clone()) {
DateStatus::Blank => "", DateStatus::Blank => "",
@@ -141,11 +108,12 @@ fn Date(
/// ``` /// ```
#[component] #[component]
pub fn DateList( pub fn DateList(
#[prop(into)] dates: Vec<DateInfo>, #[prop(into)] dates: Signal<Vec<DateInfo>>,
) -> impl IntoView { ) -> impl IntoView {
view! { view! {
{move || { {move || {
dates dates
.get()
.iter() .iter()
.map(|info| { .map(|info| {
view! { <Date info=info.clone() /> } view! { <Date info=info.clone() /> }
+4 -1
View File
@@ -1,4 +1,7 @@
mod comparisons; mod comparisons;
pub use comparisons::*;
mod scholarships; mod scholarships;
pub use scholarships::*;
mod dates;
pub use dates::*;
pub use self::{comparisons::*, scholarships::*};
+95 -51
View File
@@ -1,10 +1,100 @@
use chrono::DateTime; use chrono::DateTime;
use crate::common::{DateInfo, DateRange}; use crate::common::{DateInfo, DateRange};
use crate::components::{DashboardButton, DateList}; use crate::components::{ActionButton, DashboardButton, DateList};
use leptos::prelude::*; use leptos::prelude::*;
use crate::pages::api::{get_important_dates, CreateDates};
#[component] #[component]
pub fn TestPage() -> impl IntoView { pub fn TestPage() -> impl IntoView {
let reload_signal = RwSignal::new(0);
let dates_resource = Resource::new(
move || reload_signal.get(),
async move |_| {
get_important_dates().await
}
);
let dates_list = RwSignal::new(Vec::new());
Effect::new(move || {
if let Some(Ok(mut dates)) = dates_resource.get() {
dates.sort_by_key(|info| info.date.get_status());
dates_list.set(dates);
}
});
let create_dates = ServerAction::<CreateDates>::new();
let on_click = move |_| {
let dates_list = vec![
DateInfo {
id: uuid::Uuid::new_v4().to_string(),
title: "Open Example".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-30T14:05:00-05:00")
.unwrap_or_default()
),
description: "This is a test".to_string(),
},
DateInfo {
id: uuid::Uuid::new_v4().to_string(),
title: "Closed Example".to_string(),
date: DateRange::Range(
DateTime::parse_from_rfc3339("2026-01-01T07:15:00-05:00")
.unwrap_or_default(),
DateTime::parse_from_rfc3339("2026-01-14T14:05:00-05:00")
.unwrap_or_default()
),
description: "".to_string(),
},
DateInfo {
id: uuid::Uuid::new_v4().to_string(),
title: "Deadline Example".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(),
},
DateInfo {
id: uuid::Uuid::new_v4().to_string(),
title: "Upcoming Example".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(),
},
DateInfo {
id: uuid::Uuid::new_v4().to_string(),
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(),
}
];
create_dates.dispatch(CreateDates {
dates: dates_list
});
};
Effect::new(move || {
if let Some(Ok(_)) = create_dates.value().get() {
create_dates.clear();
reload_signal.update(|v| *v += 1);
}
});
view! { view! {
<div class="mx-auto px-6"> <div class="mx-auto px-6">
<div class="container mx-auto px-6 py-8 space-y-8"> <div class="container mx-auto px-6 py-8 space-y-8">
@@ -36,60 +126,14 @@ pub fn TestPage() -> impl IntoView {
</div> </div>
<div class="p-2"> <div class="p-2">
<div class="flex flex-col p-3 gap-3"> <div class="flex flex-col p-3 gap-3">
<DateList dates=vec![ <DateList dates=dates_list />
DateInfo {
title: "Open Example".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-30T14:05:00-05:00")
.unwrap_or_default()
),
description: "This is a test".to_string(),
},
DateInfo {
title: "Closed Example".to_string(),
date: DateRange::Range(
DateTime::parse_from_rfc3339("2026-01-01T07:15:00-05:00")
.unwrap_or_default(),
DateTime::parse_from_rfc3339("2026-01-14T14:05:00-05:00")
.unwrap_or_default()
),
description: "".to_string(),
},
DateInfo {
title: "Deadline Example".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(),
},
DateInfo {
title: "Upcoming Example".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(),
},
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>
</div> </div>
</section> </section>
<section>
<ActionButton on:click=on_click>"Create Dates List"</ActionButton>
</section>
</div> </div>
</div> </div>
</div> </div>