Remove the original create_event_modal.rs and rename create_event_modal_v2.rs to complete the modal migration started earlier. This eliminates duplicate code and consolidates to a single, clean event modal implementation. Changes: - Remove original create_event_modal.rs (2,300+ lines) - Rename create_event_modal_v2.rs → create_event_modal.rs - Update component/function names: CreateEventModalV2 → CreateEventModal - Fix all imports in app.rs and calendar.rs - Add missing to_create_event_params() method to EventCreationData - Resolve EditAction type conflicts between modules - Clean up duplicate types and unused imports - Maintain backwards compatibility with EventCreationData export Result: -2440 lines, +160 lines - massive code cleanup with zero functionality loss. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
730 lines
35 KiB
Rust
730 lines
35 KiB
Rust
use super::types::*;
|
|
// Types are already imported from super::types::*
|
|
use chrono::{Datelike, NaiveDate};
|
|
use wasm_bindgen::JsCast;
|
|
use web_sys::{HtmlInputElement, HtmlSelectElement, HtmlTextAreaElement};
|
|
use yew::prelude::*;
|
|
|
|
#[function_component(BasicDetailsTab)]
|
|
pub fn basic_details_tab(props: &TabProps) -> Html {
|
|
let data = &props.data;
|
|
|
|
// Event handlers
|
|
let on_title_input = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: InputEvent| {
|
|
if let Some(target) = e.target() {
|
|
if let Ok(input) = target.dyn_into::<HtmlInputElement>() {
|
|
let mut event_data = (*data).clone();
|
|
event_data.title = input.value();
|
|
if !event_data.changed_fields.contains(&"title".to_string()) {
|
|
event_data.changed_fields.push("title".to_string());
|
|
}
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_description_input = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: InputEvent| {
|
|
if let Some(target) = e.target() {
|
|
if let Ok(textarea) = target.dyn_into::<HtmlTextAreaElement>() {
|
|
let mut event_data = (*data).clone();
|
|
event_data.description = textarea.value();
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_calendar_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(target) = e.target() {
|
|
if let Ok(select) = target.dyn_into::<HtmlSelectElement>() {
|
|
let mut event_data = (*data).clone();
|
|
let value = select.value();
|
|
let new_calendar = if value.is_empty() { None } else { Some(value) };
|
|
if event_data.selected_calendar != new_calendar {
|
|
event_data.selected_calendar = new_calendar;
|
|
if !event_data.changed_fields.contains(&"selected_calendar".to_string()) {
|
|
event_data.changed_fields.push("selected_calendar".to_string());
|
|
}
|
|
}
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_all_day_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(target) = e.target() {
|
|
if let Ok(input) = target.dyn_into::<HtmlInputElement>() {
|
|
let mut event_data = (*data).clone();
|
|
event_data.all_day = input.checked();
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_recurrence_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(target) = e.target() {
|
|
if let Ok(select) = target.dyn_into::<HtmlSelectElement>() {
|
|
let mut event_data = (*data).clone();
|
|
event_data.recurrence = match select.value().as_str() {
|
|
"daily" => RecurrenceType::Daily,
|
|
"weekly" => RecurrenceType::Weekly,
|
|
"monthly" => RecurrenceType::Monthly,
|
|
"yearly" => RecurrenceType::Yearly,
|
|
_ => RecurrenceType::None,
|
|
};
|
|
// Reset recurrence-related fields when changing type
|
|
event_data.recurrence_days = vec![false; 7];
|
|
event_data.recurrence_interval = 1;
|
|
event_data.recurrence_until = None;
|
|
event_data.recurrence_count = None;
|
|
event_data.monthly_by_day = None;
|
|
event_data.monthly_by_monthday = None;
|
|
event_data.yearly_by_month = vec![false; 12];
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_reminder_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(target) = e.target() {
|
|
if let Ok(select) = target.dyn_into::<HtmlSelectElement>() {
|
|
let mut event_data = (*data).clone();
|
|
event_data.reminder = match select.value().as_str() {
|
|
"15min" => ReminderType::Minutes15,
|
|
"30min" => ReminderType::Minutes30,
|
|
"1hour" => ReminderType::Hour1,
|
|
"1day" => ReminderType::Day1,
|
|
"2days" => ReminderType::Days2,
|
|
"1week" => ReminderType::Week1,
|
|
_ => ReminderType::None,
|
|
};
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_recurrence_interval_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
if let Ok(interval) = input.value().parse::<u32>() {
|
|
let mut event_data = (*data).clone();
|
|
event_data.recurrence_interval = interval.max(1);
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_recurrence_until_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
let mut event_data = (*data).clone();
|
|
if input.value().is_empty() {
|
|
event_data.recurrence_until = None;
|
|
} else if let Ok(date) = NaiveDate::parse_from_str(&input.value(), "%Y-%m-%d") {
|
|
event_data.recurrence_until = Some(date);
|
|
}
|
|
data.set(event_data);
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_recurrence_count_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
let mut event_data = (*data).clone();
|
|
if input.value().is_empty() {
|
|
event_data.recurrence_count = None;
|
|
} else if let Ok(count) = input.value().parse::<u32>() {
|
|
event_data.recurrence_count = Some(count.max(1));
|
|
}
|
|
data.set(event_data);
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_monthly_by_monthday_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
let mut event_data = (*data).clone();
|
|
if input.value().is_empty() {
|
|
event_data.monthly_by_monthday = None;
|
|
} else if let Ok(day) = input.value().parse::<u8>() {
|
|
if day >= 1 && day <= 31 {
|
|
event_data.monthly_by_monthday = Some(day);
|
|
event_data.monthly_by_day = None; // Clear the other option
|
|
}
|
|
}
|
|
data.set(event_data);
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_monthly_by_day_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(select) = e.target_dyn_into::<HtmlSelectElement>() {
|
|
let mut event_data = (*data).clone();
|
|
if select.value().is_empty() || select.value() == "none" {
|
|
event_data.monthly_by_day = None;
|
|
} else {
|
|
event_data.monthly_by_day = Some(select.value());
|
|
event_data.monthly_by_monthday = None; // Clear the other option
|
|
}
|
|
data.set(event_data);
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_weekday_change = {
|
|
let data = data.clone();
|
|
move |day_index: usize| {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
let mut event_data = (*data).clone();
|
|
if day_index < event_data.recurrence_days.len() {
|
|
event_data.recurrence_days[day_index] = input.checked();
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
}
|
|
};
|
|
|
|
let on_yearly_month_change = {
|
|
let data = data.clone();
|
|
move |month_index: usize| {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
let mut event_data = (*data).clone();
|
|
if month_index < event_data.yearly_by_month.len() {
|
|
event_data.yearly_by_month[month_index] = input.checked();
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
}
|
|
};
|
|
|
|
let on_start_date_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
if let Ok(date) = NaiveDate::parse_from_str(&input.value(), "%Y-%m-%d") {
|
|
let mut event_data = (*data).clone();
|
|
event_data.start_date = date;
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_start_time_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
if let Ok(time) = chrono::NaiveTime::parse_from_str(&input.value(), "%H:%M") {
|
|
let mut event_data = (*data).clone();
|
|
event_data.start_time = time;
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_end_date_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
if let Ok(date) = NaiveDate::parse_from_str(&input.value(), "%Y-%m-%d") {
|
|
let mut event_data = (*data).clone();
|
|
event_data.end_date = date;
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_end_time_change = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: Event| {
|
|
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
|
|
if let Ok(time) = chrono::NaiveTime::parse_from_str(&input.value(), "%H:%M") {
|
|
let mut event_data = (*data).clone();
|
|
event_data.end_time = time;
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_location_input = {
|
|
let data = data.clone();
|
|
Callback::from(move |e: InputEvent| {
|
|
if let Some(target) = e.target() {
|
|
if let Ok(input) = target.dyn_into::<HtmlInputElement>() {
|
|
let mut event_data = (*data).clone();
|
|
event_data.location = input.value();
|
|
data.set(event_data);
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
html! {
|
|
<div class="tab-panel">
|
|
<div class="form-group">
|
|
<label for="event-title">{"Event Title *"}</label>
|
|
<input
|
|
type="text"
|
|
id="event-title"
|
|
class="form-input"
|
|
value={data.title.clone()}
|
|
oninput={on_title_input}
|
|
placeholder="Add a title"
|
|
required=true
|
|
/>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="event-description">{"Description"}</label>
|
|
<textarea
|
|
id="event-description"
|
|
class="form-input"
|
|
value={data.description.clone()}
|
|
oninput={on_description_input}
|
|
placeholder="Add a description"
|
|
rows="3"
|
|
></textarea>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="event-calendar">{"Calendar"}</label>
|
|
<select
|
|
id="event-calendar"
|
|
class="form-input"
|
|
onchange={on_calendar_change}
|
|
>
|
|
<option value="">{"Select Calendar"}</option>
|
|
{
|
|
props.available_calendars.iter().map(|calendar| {
|
|
html! {
|
|
<option
|
|
key={calendar.path.clone()}
|
|
value={calendar.path.clone()}
|
|
selected={data.selected_calendar.as_ref() == Some(&calendar.path)}
|
|
>
|
|
{&calendar.display_name}
|
|
</option>
|
|
}
|
|
}).collect::<Html>()
|
|
}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="checkbox-label">
|
|
<input
|
|
type="checkbox"
|
|
checked={data.all_day}
|
|
onchange={on_all_day_change}
|
|
/>
|
|
{" All Day"}
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="event-recurrence-basic">{"Repeat"}</label>
|
|
<select
|
|
id="event-recurrence-basic"
|
|
class="form-input"
|
|
onchange={on_recurrence_change}
|
|
>
|
|
<option value="none" selected={matches!(data.recurrence, RecurrenceType::None)}>{"Does not repeat"}</option>
|
|
<option value="daily" selected={matches!(data.recurrence, RecurrenceType::Daily)}>{"Daily"}</option>
|
|
<option value="weekly" selected={matches!(data.recurrence, RecurrenceType::Weekly)}>{"Weekly"}</option>
|
|
<option value="monthly" selected={matches!(data.recurrence, RecurrenceType::Monthly)}>{"Monthly"}</option>
|
|
<option value="yearly" selected={matches!(data.recurrence, RecurrenceType::Yearly)}>{"Yearly"}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="event-reminder-basic">{"Reminder"}</label>
|
|
<select
|
|
id="event-reminder-basic"
|
|
class="form-input"
|
|
onchange={on_reminder_change}
|
|
>
|
|
<option value="none" selected={matches!(data.reminder, ReminderType::None)}>{"None"}</option>
|
|
<option value="15min" selected={matches!(data.reminder, ReminderType::Minutes15)}>{"15 minutes before"}</option>
|
|
<option value="30min" selected={matches!(data.reminder, ReminderType::Minutes30)}>{"30 minutes before"}</option>
|
|
<option value="1hour" selected={matches!(data.reminder, ReminderType::Hour1)}>{"1 hour before"}</option>
|
|
<option value="1day" selected={matches!(data.reminder, ReminderType::Day1)}>{"1 day before"}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
// RECURRENCE OPTIONS GO RIGHT HERE - directly below repeat/reminder!
|
|
if matches!(data.recurrence, RecurrenceType::Weekly) {
|
|
<div class="form-group">
|
|
<label>{"Repeat on"}</label>
|
|
<div class="weekday-selection">
|
|
{
|
|
["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(i, day)| {
|
|
let day_checked = data.recurrence_days.get(i).cloned().unwrap_or(false);
|
|
let on_change = on_weekday_change(i);
|
|
html! {
|
|
<label key={i} class="weekday-checkbox">
|
|
<input
|
|
type="checkbox"
|
|
checked={day_checked}
|
|
onchange={on_change}
|
|
/>
|
|
<span class="weekday-label">{day}</span>
|
|
</label>
|
|
}
|
|
})
|
|
.collect::<Html>()
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
if !matches!(data.recurrence, RecurrenceType::None) {
|
|
<div class="recurrence-options">
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="recurrence-interval">{"Every"}</label>
|
|
<div class="interval-input">
|
|
<input
|
|
id="recurrence-interval"
|
|
type="number"
|
|
class="form-input"
|
|
value={data.recurrence_interval.to_string()}
|
|
min="1"
|
|
max="999"
|
|
onchange={on_recurrence_interval_change}
|
|
/>
|
|
<span class="interval-unit">
|
|
{match data.recurrence {
|
|
RecurrenceType::Daily => if data.recurrence_interval == 1 { "day" } else { "days" },
|
|
RecurrenceType::Weekly => if data.recurrence_interval == 1 { "week" } else { "weeks" },
|
|
RecurrenceType::Monthly => if data.recurrence_interval == 1 { "month" } else { "months" },
|
|
RecurrenceType::Yearly => if data.recurrence_interval == 1 { "year" } else { "years" },
|
|
RecurrenceType::None => "",
|
|
}}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>{"Ends"}</label>
|
|
<div class="end-options">
|
|
<div class="end-option">
|
|
<label class="radio-label">
|
|
<input
|
|
type="radio"
|
|
name="recurrence-end"
|
|
value="never"
|
|
checked={data.recurrence_until.is_none() && data.recurrence_count.is_none()}
|
|
onchange={{
|
|
let data = data.clone();
|
|
Callback::from(move |_| {
|
|
let mut new_data = (*data).clone();
|
|
new_data.recurrence_until = None;
|
|
new_data.recurrence_count = None;
|
|
data.set(new_data);
|
|
})
|
|
}}
|
|
/>
|
|
{"Never"}
|
|
</label>
|
|
</div>
|
|
|
|
<div class="end-option">
|
|
<label class="radio-label">
|
|
<input
|
|
type="radio"
|
|
name="recurrence-end"
|
|
value="until"
|
|
checked={data.recurrence_until.is_some()}
|
|
onchange={{
|
|
let data = data.clone();
|
|
Callback::from(move |_| {
|
|
let mut new_data = (*data).clone();
|
|
new_data.recurrence_count = None;
|
|
new_data.recurrence_until = Some(new_data.start_date);
|
|
data.set(new_data);
|
|
})
|
|
}}
|
|
/>
|
|
{"Until"}
|
|
</label>
|
|
<input
|
|
type="date"
|
|
class="form-input"
|
|
value={data.recurrence_until.map(|d| d.format("%Y-%m-%d").to_string()).unwrap_or_default()}
|
|
onchange={on_recurrence_until_change}
|
|
/>
|
|
</div>
|
|
|
|
<div class="end-option">
|
|
<label class="radio-label">
|
|
<input
|
|
type="radio"
|
|
name="recurrence-end"
|
|
value="count"
|
|
checked={data.recurrence_count.is_some()}
|
|
onchange={{
|
|
let data = data.clone();
|
|
Callback::from(move |_| {
|
|
let mut new_data = (*data).clone();
|
|
new_data.recurrence_until = None;
|
|
new_data.recurrence_count = Some(10); // Default count
|
|
data.set(new_data);
|
|
})
|
|
}}
|
|
/>
|
|
{"After"}
|
|
</label>
|
|
<input
|
|
type="number"
|
|
class="form-input count-input"
|
|
value={data.recurrence_count.map(|c| c.to_string()).unwrap_or_default()}
|
|
min="1"
|
|
max="999"
|
|
placeholder="1"
|
|
onchange={on_recurrence_count_change}
|
|
/>
|
|
<span class="count-unit">{"occurrences"}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
// Monthly specific options
|
|
if matches!(data.recurrence, RecurrenceType::Monthly) {
|
|
<div class="form-group">
|
|
<label>{"Repeat by"}</label>
|
|
<div class="monthly-options">
|
|
<div class="monthly-option">
|
|
<label class="radio-label">
|
|
<input
|
|
type="radio"
|
|
name="monthly-type"
|
|
checked={data.monthly_by_monthday.is_some()}
|
|
onchange={{
|
|
let data = data.clone();
|
|
Callback::from(move |_| {
|
|
let mut new_data = (*data).clone();
|
|
new_data.monthly_by_day = None;
|
|
new_data.monthly_by_monthday = Some(new_data.start_date.day() as u8);
|
|
data.set(new_data);
|
|
})
|
|
}}
|
|
/>
|
|
{"Day of month:"}
|
|
</label>
|
|
<input
|
|
type="number"
|
|
class="form-input day-input"
|
|
value={data.monthly_by_monthday.map(|d| d.to_string()).unwrap_or_else(|| data.start_date.day().to_string())}
|
|
min="1"
|
|
max="31"
|
|
onchange={on_monthly_by_monthday_change}
|
|
/>
|
|
</div>
|
|
|
|
<div class="monthly-option">
|
|
<label class="radio-label">
|
|
<input
|
|
type="radio"
|
|
name="monthly-type"
|
|
checked={data.monthly_by_day.is_some()}
|
|
onchange={{
|
|
let data = data.clone();
|
|
Callback::from(move |_| {
|
|
let mut new_data = (*data).clone();
|
|
new_data.monthly_by_monthday = None;
|
|
new_data.monthly_by_day = Some("1MO".to_string()); // Default to first Monday
|
|
data.set(new_data);
|
|
})
|
|
}}
|
|
/>
|
|
{"Day of week:"}
|
|
</label>
|
|
<select
|
|
class="form-input"
|
|
value={data.monthly_by_day.clone().unwrap_or_default()}
|
|
onchange={on_monthly_by_day_change}
|
|
>
|
|
<option value="none">{"Select..."}</option>
|
|
<option value="1MO">{"First Monday"}</option>
|
|
<option value="1TU">{"First Tuesday"}</option>
|
|
<option value="1WE">{"First Wednesday"}</option>
|
|
<option value="1TH">{"First Thursday"}</option>
|
|
<option value="1FR">{"First Friday"}</option>
|
|
<option value="1SA">{"First Saturday"}</option>
|
|
<option value="1SU">{"First Sunday"}</option>
|
|
<option value="2MO">{"Second Monday"}</option>
|
|
<option value="2TU">{"Second Tuesday"}</option>
|
|
<option value="2WE">{"Second Wednesday"}</option>
|
|
<option value="2TH">{"Second Thursday"}</option>
|
|
<option value="2FR">{"Second Friday"}</option>
|
|
<option value="2SA">{"Second Saturday"}</option>
|
|
<option value="2SU">{"Second Sunday"}</option>
|
|
<option value="3MO">{"Third Monday"}</option>
|
|
<option value="3TU">{"Third Tuesday"}</option>
|
|
<option value="3WE">{"Third Wednesday"}</option>
|
|
<option value="3TH">{"Third Thursday"}</option>
|
|
<option value="3FR">{"Third Friday"}</option>
|
|
<option value="3SA">{"Third Saturday"}</option>
|
|
<option value="3SU">{"Third Sunday"}</option>
|
|
<option value="4MO">{"Fourth Monday"}</option>
|
|
<option value="4TU">{"Fourth Tuesday"}</option>
|
|
<option value="4WE">{"Fourth Wednesday"}</option>
|
|
<option value="4TH">{"Fourth Thursday"}</option>
|
|
<option value="4FR">{"Fourth Friday"}</option>
|
|
<option value="4SA">{"Fourth Saturday"}</option>
|
|
<option value="4SU">{"Fourth Sunday"}</option>
|
|
<option value="-1MO">{"Last Monday"}</option>
|
|
<option value="-1TU">{"Last Tuesday"}</option>
|
|
<option value="-1WE">{"Last Wednesday"}</option>
|
|
<option value="-1TH">{"Last Thursday"}</option>
|
|
<option value="-1FR">{"Last Friday"}</option>
|
|
<option value="-1SA">{"Last Saturday"}</option>
|
|
<option value="-1SU">{"Last Sunday"}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
// Yearly specific options
|
|
if matches!(data.recurrence, RecurrenceType::Yearly) {
|
|
<div class="form-group">
|
|
<label>{"Repeat in months"}</label>
|
|
<div class="yearly-months">
|
|
{
|
|
["Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(i, month)| {
|
|
let month_checked = data.yearly_by_month.get(i).cloned().unwrap_or(false);
|
|
let on_change = on_yearly_month_change(i);
|
|
html! {
|
|
<label key={i} class="month-checkbox">
|
|
<input
|
|
type="checkbox"
|
|
checked={month_checked}
|
|
onchange={on_change}
|
|
/>
|
|
<span class="month-label">{month}</span>
|
|
</label>
|
|
}
|
|
})
|
|
.collect::<Html>()
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
// Date and time fields go here AFTER recurrence options
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="start-date">{"Start Date *"}</label>
|
|
<input
|
|
type="date"
|
|
id="start-date"
|
|
class="form-input"
|
|
value={data.start_date.format("%Y-%m-%d").to_string()}
|
|
onchange={on_start_date_change}
|
|
required=true
|
|
/>
|
|
</div>
|
|
|
|
if !data.all_day {
|
|
<div class="form-group">
|
|
<label for="start-time">{"Start Time"}</label>
|
|
<input
|
|
type="time"
|
|
id="start-time"
|
|
class="form-input"
|
|
value={data.start_time.format("%H:%M").to_string()}
|
|
onchange={on_start_time_change}
|
|
/>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="end-date">{"End Date *"}</label>
|
|
<input
|
|
type="date"
|
|
id="end-date"
|
|
class="form-input"
|
|
value={data.end_date.format("%Y-%m-%d").to_string()}
|
|
onchange={on_end_date_change}
|
|
required=true
|
|
/>
|
|
</div>
|
|
|
|
if !data.all_day {
|
|
<div class="form-group">
|
|
<label for="end-time">{"End Time"}</label>
|
|
<input
|
|
type="time"
|
|
id="end-time"
|
|
class="form-input"
|
|
value={data.end_time.format("%H:%M").to_string()}
|
|
onchange={on_end_time_change}
|
|
/>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="event-location">{"Location"}</label>
|
|
<input
|
|
type="text"
|
|
id="event-location"
|
|
class="form-input"
|
|
value={data.location.clone()}
|
|
oninput={on_location_input}
|
|
placeholder="Enter event location"
|
|
/>
|
|
</div>
|
|
</div>
|
|
}
|
|
} |