Replace page reloads with dynamic calendar refresh functionality
All checks were successful
Build and Push Docker Image / docker (push) Successful in 29s
All checks were successful
Build and Push Docker Image / docker (push) Successful in 29s
- Add refresh_calendar_data function to replace window.location.reload() - Implement dynamic event re-fetching without full page refresh - Add last_updated timestamp to UserInfo to force component re-renders - Fix WASM compatibility by using js_sys::Date::now() instead of SystemTime - Remove debug logging from refresh operations - Maintain same user experience with improved performance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,7 @@ web-sys = { version = "0.3", features = [
|
||||
"CssStyleDeclaration",
|
||||
] }
|
||||
wasm-bindgen = "0.2"
|
||||
js-sys = "0.3"
|
||||
|
||||
# HTTP client for CalDAV requests
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
|
||||
@@ -155,6 +155,108 @@ pub fn App() -> Html {
|
||||
|
||||
let available_colors = use_state(|| get_theme_event_colors());
|
||||
|
||||
// Function to refresh calendar data without full page reload
|
||||
let refresh_calendar_data = {
|
||||
let user_info = user_info.clone();
|
||||
let auth_token = auth_token.clone();
|
||||
let external_calendars = external_calendars.clone();
|
||||
let external_calendar_events = external_calendar_events.clone();
|
||||
|
||||
Callback::from(move |_| {
|
||||
let user_info = user_info.clone();
|
||||
let auth_token = auth_token.clone();
|
||||
let external_calendars = external_calendars.clone();
|
||||
let external_calendar_events = external_calendar_events.clone();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
// Refresh main calendar data if authenticated
|
||||
if let Some(token) = (*auth_token).clone() {
|
||||
let calendar_service = CalendarService::new();
|
||||
|
||||
let password = if let Ok(credentials_str) =
|
||||
LocalStorage::get::<String>("caldav_credentials")
|
||||
{
|
||||
if let Ok(credentials) =
|
||||
serde_json::from_str::<serde_json::Value>(&credentials_str)
|
||||
{
|
||||
credentials["password"].as_str().unwrap_or("").to_string()
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
if !password.is_empty() {
|
||||
match calendar_service.fetch_user_info(&token, &password).await {
|
||||
Ok(mut info) => {
|
||||
// Apply saved colors
|
||||
if let Ok(saved_colors_json) =
|
||||
LocalStorage::get::<String>("calendar_colors")
|
||||
{
|
||||
if let Ok(saved_info) =
|
||||
serde_json::from_str::<UserInfo>(&saved_colors_json)
|
||||
{
|
||||
for saved_cal in &saved_info.calendars {
|
||||
for cal in &mut info.calendars {
|
||||
if cal.path == saved_cal.path {
|
||||
cal.color = saved_cal.color.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add timestamp to force re-render
|
||||
info.last_updated = (js_sys::Date::now() / 1000.0) as u64;
|
||||
user_info.set(Some(info));
|
||||
}
|
||||
Err(err) => {
|
||||
web_sys::console::log_1(
|
||||
&format!("Failed to refresh main calendar data: {}", err).into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh external calendars data
|
||||
match CalendarService::get_external_calendars().await {
|
||||
Ok(calendars) => {
|
||||
external_calendars.set(calendars.clone());
|
||||
|
||||
// Load events for visible external calendars
|
||||
let mut all_external_events = Vec::new();
|
||||
for calendar in calendars {
|
||||
if calendar.is_visible {
|
||||
match CalendarService::fetch_external_calendar_events(calendar.id).await {
|
||||
Ok(mut events) => {
|
||||
// Set calendar_path for color matching
|
||||
for event in &mut events {
|
||||
event.calendar_path = Some(format!("external_{}", calendar.id));
|
||||
}
|
||||
all_external_events.extend(events);
|
||||
}
|
||||
Err(e) => {
|
||||
web_sys::console::log_1(
|
||||
&format!("Failed to fetch events for external calendar {}: {}", calendar.id, e).into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
external_calendar_events.set(all_external_events);
|
||||
}
|
||||
Err(e) => {
|
||||
web_sys::console::log_1(
|
||||
&format!("Failed to refresh external calendars: {}", e).into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
let on_login = {
|
||||
let auth_token = auth_token.clone();
|
||||
Callback::from(move |token: String| {
|
||||
@@ -531,6 +633,7 @@ pub fn App() -> Html {
|
||||
let on_event_create = {
|
||||
let create_event_modal_open = create_event_modal_open.clone();
|
||||
let auth_token = auth_token.clone();
|
||||
let refresh_calendar_data = refresh_calendar_data.clone();
|
||||
Callback::from(move |event_data: EventCreationData| {
|
||||
// Check if this is an update operation (has original_uid) or a create operation
|
||||
if let Some(original_uid) = event_data.original_uid.clone() {
|
||||
@@ -541,6 +644,7 @@ pub fn App() -> Html {
|
||||
// Handle the update operation using the existing backend update logic
|
||||
if let Some(token) = (*auth_token).clone() {
|
||||
let event_data_for_update = event_data.clone();
|
||||
let refresh_callback = refresh_calendar_data.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let calendar_service = CalendarService::new();
|
||||
|
||||
@@ -641,10 +745,8 @@ pub fn App() -> Html {
|
||||
match update_result {
|
||||
Ok(_) => {
|
||||
web_sys::console::log_1(&"Event updated successfully via modal".into());
|
||||
// Trigger a page reload to refresh events from all calendars
|
||||
if let Some(window) = web_sys::window() {
|
||||
let _ = window.location().reload();
|
||||
}
|
||||
// Refresh calendar data without page reload
|
||||
refresh_callback.emit(());
|
||||
}
|
||||
Err(err) => {
|
||||
web_sys::console::error_1(
|
||||
@@ -680,6 +782,7 @@ pub fn App() -> Html {
|
||||
create_event_modal_open.set(false);
|
||||
|
||||
if let Some(_token) = (*auth_token).clone() {
|
||||
let refresh_callback = refresh_calendar_data.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let _calendar_service = CalendarService::new();
|
||||
|
||||
@@ -726,9 +829,8 @@ pub fn App() -> Html {
|
||||
match create_result {
|
||||
Ok(_) => {
|
||||
web_sys::console::log_1(&"Event created successfully".into());
|
||||
// Trigger a page reload to refresh events from all calendars
|
||||
// TODO: This could be improved to do a more targeted refresh
|
||||
web_sys::window().unwrap().location().reload().unwrap();
|
||||
// Refresh calendar data without page reload
|
||||
refresh_callback.emit(());
|
||||
}
|
||||
Err(err) => {
|
||||
web_sys::console::error_1(
|
||||
@@ -747,6 +849,7 @@ pub fn App() -> Html {
|
||||
|
||||
let on_event_update = {
|
||||
let auth_token = auth_token.clone();
|
||||
let refresh_calendar_data = refresh_calendar_data.clone();
|
||||
Callback::from(
|
||||
move |(
|
||||
original_event,
|
||||
@@ -781,6 +884,7 @@ pub fn App() -> Html {
|
||||
if let Some(token) = (*auth_token).clone() {
|
||||
let original_event = original_event.clone();
|
||||
let backend_uid = backend_uid.clone();
|
||||
let refresh_callback = refresh_calendar_data.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let calendar_service = CalendarService::new();
|
||||
|
||||
@@ -965,14 +1069,8 @@ pub fn App() -> Html {
|
||||
match result {
|
||||
Ok(_) => {
|
||||
web_sys::console::log_1(&"Event updated successfully".into());
|
||||
// Add small delay before reload to let any pending requests complete
|
||||
wasm_bindgen_futures::spawn_local(async {
|
||||
gloo_timers::future::sleep(std::time::Duration::from_millis(
|
||||
100,
|
||||
))
|
||||
.await;
|
||||
web_sys::window().unwrap().location().reload().unwrap();
|
||||
});
|
||||
// Refresh calendar data without page reload
|
||||
refresh_callback.emit(());
|
||||
}
|
||||
Err(err) => {
|
||||
web_sys::console::error_1(
|
||||
@@ -1392,10 +1490,10 @@ pub fn App() -> Html {
|
||||
let auth_token = auth_token.clone();
|
||||
let event_context_menu_event = event_context_menu_event.clone();
|
||||
let event_context_menu_open = event_context_menu_open.clone();
|
||||
let refresh_calendars = refresh_calendars.clone();
|
||||
let refresh_calendar_data = refresh_calendar_data.clone();
|
||||
move |delete_action: DeleteAction| {
|
||||
if let (Some(token), Some(event)) = ((*auth_token).clone(), (*event_context_menu_event).clone()) {
|
||||
let _refresh_calendars = refresh_calendars.clone();
|
||||
let refresh_calendar_data = refresh_calendar_data.clone();
|
||||
let event_context_menu_open = event_context_menu_open.clone();
|
||||
|
||||
// Log the delete action for now - we'll implement different behaviors later
|
||||
@@ -1405,6 +1503,7 @@ pub fn App() -> Html {
|
||||
DeleteAction::DeleteSeries => web_sys::console::log_1(&"Delete entire series".into()),
|
||||
}
|
||||
|
||||
let refresh_callback = refresh_calendar_data.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let calendar_service = CalendarService::new();
|
||||
|
||||
@@ -1452,8 +1551,8 @@ pub fn App() -> Html {
|
||||
|
||||
// Close the context menu
|
||||
event_context_menu_open.set(false);
|
||||
// Force a page reload to refresh the calendar events
|
||||
web_sys::window().unwrap().location().reload().unwrap();
|
||||
// Refresh calendar data without page reload
|
||||
refresh_callback.emit(());
|
||||
}
|
||||
Err(err) => {
|
||||
web_sys::console::log_1(&format!("Failed to delete event: {}", err).into());
|
||||
|
||||
@@ -37,6 +37,12 @@ pub struct UserInfo {
|
||||
pub username: String,
|
||||
pub server_url: String,
|
||||
pub calendars: Vec<CalendarInfo>,
|
||||
#[serde(default = "default_timestamp")]
|
||||
pub last_updated: u64,
|
||||
}
|
||||
|
||||
fn default_timestamp() -> u64 {
|
||||
0
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
|
||||
Reference in New Issue
Block a user