feat: sort dates list before displaying the list
This commit is contained in:
1 parent
f15d151694
commit
7d7c96e642
4 files changed
+150
-99
No files matched your search
+48
-12
@@ -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
@@ -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() /> }
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
|
|||||||
Reference in new issue
Block a user