use std::cmp::Ordering;
use crate::class_list;
use crate::date_picker::DateMenuOption;
use crate::date_picker::DatePicker;
use crate::date_picker::SELECTED_ELEM_CLASSES;
use crate::util::callback::ArcOneCallback;
use chrono::NaiveDate;
use leptos::prelude::ClassAttribute;
use leptos::prelude::Effect;
use leptos::prelude::ElementChild;
use leptos::prelude::Get;
use leptos::prelude::RwSignal;
use leptos::prelude::Set;
use leptos::{IntoView, component, prelude::MaybeProp, view};
#[component]
pub fn DateRangePicker(
#[prop(optional, into)] id: MaybeProp<String>,
#[prop(optional, into)]
name: MaybeProp<String>,
#[prop(optional, into)] class: MaybeProp<String>,
#[prop(default = "yyyy-mm-dd".into(), into)] placeholder: MaybeProp<String>,
#[prop(default = RwSignal::new(None), into)]
start_date: RwSignal<Option<NaiveDate>>,
#[prop(default = RwSignal::new(None), into)]
end_date: RwSignal<Option<NaiveDate>>,
#[prop(optional, into)]
min_date: MaybeProp<NaiveDate>,
#[prop(optional, into)]
max_date: MaybeProp<NaiveDate>,
#[prop(optional, into)]
highlighter: MaybeProp<ArcOneCallback<DateMenuOption, String>>,
#[prop(optional)] required: bool,
) -> impl IntoView {
Effect::watch(
move || (start_date.get(), end_date.get()),
move |new, _old, _| {
if let (Some(start_date_value), Some(end_date_value)) = new
&& end_date_value < start_date_value
{
start_date.set(Some(*end_date_value));
end_date.set(Some(*start_date_value))
}
},
true,
);
let range_highlighter = move |date: DateMenuOption| {
if let Some(start) = start_date.get()
&& let Some(end) = end_date.get()
{
if date.matches_date(start) {
return "rounded-l-lg ".to_string() + SELECTED_ELEM_CLASSES;
}
if date.matches_date(end) {
return "rounded-r-lg ".to_string() + SELECTED_ELEM_CLASSES;
}
if date.compare_against(end) == Ordering::Less
&& date.compare_against(start) == Ordering::Greater
{
return "bg-oa-gray-mid".to_string();
} else {
return "rounded-lg".to_string();
}
} else {
if let Some(start) = start_date.get()
&& date.matches_date(start)
{
return "rounded-lg ".to_string() + SELECTED_ELEM_CLASSES;
}
if let Some(end) = end_date.get()
&& date.matches_date(end)
{
return "rounded-lg ".to_string() + SELECTED_ELEM_CLASSES;
}
}
"rounded-lg".to_string()
};
let combined_highlighter = ArcOneCallback::new(move |date: DateMenuOption| {
let mut all_classes = vec![range_highlighter(date)];
if let Some(provided_highlighter) = highlighter.get() {
all_classes.push(provided_highlighter(date));
}
if let DateMenuOption::Day(date) = date
&& date.is_other_month()
{
all_classes.push("text-gray-500".to_string());
}
all_classes.join(" ")
});
let id_left = MaybeProp::derive(move || id.get().map(|id| format!("{id}-left")));
let id_right = MaybeProp::derive(move || id.get().map(|id| format!("{id}-right")));
let name_start = MaybeProp::derive(move || name.get().map(|name| format!("{name}_start")));
let name_end = MaybeProp::derive(move || name.get().map(|name| format!("{name}_end")));
view! {
<div class=class_list!["inline-flex", class]>
<DatePicker placeholder id=id_left name=name_start value=start_date min_date max_date
highlighter=combined_highlighter.clone() required />
<span class="mx-2 content-center">"Until"</span>
<DatePicker placeholder id=id_right name=name_end value=end_date min_date max_date
highlighter=combined_highlighter required />
</div>
}
}