- Add comprehensive Windows timezone support for global external calendars - Map Windows timezone names (e.g. "Mountain Standard Time") to IANA zones (e.g. "America/Denver") - Support 60+ timezone mappings across North America, Europe, Asia, Asia Pacific, Africa, South America - Add chrono-tz dependency for proper timezone handling - Fix external calendar event colors by setting calendar_path for color lookup - Add visual distinction for external calendar events with dashed borders and calendar emoji - Update timezone parsing to extract TZID parameters from iCalendar DTSTART/DTEND properties - Pass external calendar data through component hierarchy for color matching 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
168 lines
6.3 KiB
Rust
168 lines
6.3 KiB
Rust
use crate::components::{Login, ViewMode};
|
|
use crate::models::ical::VEvent;
|
|
use crate::services::calendar_service::{UserInfo, ExternalCalendar};
|
|
use yew::prelude::*;
|
|
use yew_router::prelude::*;
|
|
|
|
#[derive(Clone, Routable, PartialEq)]
|
|
pub enum Route {
|
|
#[at("/")]
|
|
Home,
|
|
#[at("/login")]
|
|
Login,
|
|
#[at("/calendar")]
|
|
Calendar,
|
|
}
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
pub struct RouteHandlerProps {
|
|
pub auth_token: Option<String>,
|
|
pub user_info: Option<UserInfo>,
|
|
pub on_login: Callback<String>,
|
|
#[prop_or_default]
|
|
pub external_calendar_events: Vec<VEvent>,
|
|
#[prop_or_default]
|
|
pub external_calendars: Vec<ExternalCalendar>,
|
|
#[prop_or_default]
|
|
pub on_event_context_menu: Option<Callback<(web_sys::MouseEvent, VEvent)>>,
|
|
#[prop_or_default]
|
|
pub on_calendar_context_menu: Option<Callback<(web_sys::MouseEvent, chrono::NaiveDate)>>,
|
|
#[prop_or_default]
|
|
pub view: ViewMode,
|
|
#[prop_or_default]
|
|
pub on_create_event_request: Option<Callback<crate::components::EventCreationData>>,
|
|
#[prop_or_default]
|
|
pub on_event_update_request: Option<
|
|
Callback<(
|
|
VEvent,
|
|
chrono::NaiveDateTime,
|
|
chrono::NaiveDateTime,
|
|
bool,
|
|
Option<chrono::DateTime<chrono::Utc>>,
|
|
Option<String>,
|
|
Option<String>,
|
|
)>,
|
|
>,
|
|
#[prop_or_default]
|
|
pub context_menus_open: bool,
|
|
}
|
|
|
|
#[function_component(RouteHandler)]
|
|
pub fn route_handler(props: &RouteHandlerProps) -> Html {
|
|
let auth_token = props.auth_token.clone();
|
|
let user_info = props.user_info.clone();
|
|
let on_login = props.on_login.clone();
|
|
let external_calendar_events = props.external_calendar_events.clone();
|
|
let external_calendars = props.external_calendars.clone();
|
|
let on_event_context_menu = props.on_event_context_menu.clone();
|
|
let on_calendar_context_menu = props.on_calendar_context_menu.clone();
|
|
let view = props.view.clone();
|
|
let on_create_event_request = props.on_create_event_request.clone();
|
|
let on_event_update_request = props.on_event_update_request.clone();
|
|
let context_menus_open = props.context_menus_open;
|
|
|
|
html! {
|
|
<Switch<Route> render={move |route| {
|
|
let auth_token = auth_token.clone();
|
|
let user_info = user_info.clone();
|
|
let on_login = on_login.clone();
|
|
let external_calendar_events = external_calendar_events.clone();
|
|
let external_calendars = external_calendars.clone();
|
|
let on_event_context_menu = on_event_context_menu.clone();
|
|
let on_calendar_context_menu = on_calendar_context_menu.clone();
|
|
let view = view.clone();
|
|
let on_create_event_request = on_create_event_request.clone();
|
|
let on_event_update_request = on_event_update_request.clone();
|
|
let context_menus_open = context_menus_open;
|
|
|
|
match route {
|
|
Route::Home => {
|
|
if auth_token.is_some() {
|
|
html! { <Redirect<Route> to={Route::Calendar}/> }
|
|
} else {
|
|
html! { <Redirect<Route> to={Route::Login}/> }
|
|
}
|
|
}
|
|
Route::Login => {
|
|
if auth_token.is_some() {
|
|
html! { <Redirect<Route> to={Route::Calendar}/> }
|
|
} else {
|
|
html! { <Login {on_login} /> }
|
|
}
|
|
}
|
|
Route::Calendar => {
|
|
if auth_token.is_some() {
|
|
html! {
|
|
<CalendarView
|
|
user_info={user_info}
|
|
external_calendar_events={external_calendar_events}
|
|
external_calendars={external_calendars}
|
|
on_event_context_menu={on_event_context_menu}
|
|
on_calendar_context_menu={on_calendar_context_menu}
|
|
view={view}
|
|
on_create_event_request={on_create_event_request}
|
|
on_event_update_request={on_event_update_request}
|
|
context_menus_open={context_menus_open}
|
|
/>
|
|
}
|
|
} else {
|
|
html! { <Redirect<Route> to={Route::Login}/> }
|
|
}
|
|
}
|
|
}
|
|
}} />
|
|
}
|
|
}
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
pub struct CalendarViewProps {
|
|
pub user_info: Option<UserInfo>,
|
|
#[prop_or_default]
|
|
pub external_calendar_events: Vec<VEvent>,
|
|
#[prop_or_default]
|
|
pub external_calendars: Vec<ExternalCalendar>,
|
|
#[prop_or_default]
|
|
pub on_event_context_menu: Option<Callback<(web_sys::MouseEvent, VEvent)>>,
|
|
#[prop_or_default]
|
|
pub on_calendar_context_menu: Option<Callback<(web_sys::MouseEvent, chrono::NaiveDate)>>,
|
|
#[prop_or_default]
|
|
pub view: ViewMode,
|
|
#[prop_or_default]
|
|
pub on_create_event_request: Option<Callback<crate::components::EventCreationData>>,
|
|
#[prop_or_default]
|
|
pub on_event_update_request: Option<
|
|
Callback<(
|
|
VEvent,
|
|
chrono::NaiveDateTime,
|
|
chrono::NaiveDateTime,
|
|
bool,
|
|
Option<chrono::DateTime<chrono::Utc>>,
|
|
Option<String>,
|
|
Option<String>,
|
|
)>,
|
|
>,
|
|
#[prop_or_default]
|
|
pub context_menus_open: bool,
|
|
}
|
|
|
|
use crate::components::Calendar;
|
|
|
|
#[function_component(CalendarView)]
|
|
pub fn calendar_view(props: &CalendarViewProps) -> Html {
|
|
html! {
|
|
<div class="calendar-view">
|
|
<Calendar
|
|
user_info={props.user_info.clone()}
|
|
external_calendar_events={props.external_calendar_events.clone()}
|
|
external_calendars={props.external_calendars.clone()}
|
|
on_event_context_menu={props.on_event_context_menu.clone()}
|
|
on_calendar_context_menu={props.on_calendar_context_menu.clone()}
|
|
view={props.view.clone()}
|
|
on_create_event_request={props.on_create_event_request.clone()}
|
|
on_event_update_request={props.on_event_update_request.clone()}
|
|
context_menus_open={props.context_menus_open}
|
|
/>
|
|
</div>
|
|
}
|
|
}
|