diff --git a/frontend/src/app.rs b/frontend/src/app.rs index 9ebf735..d6473a4 100644 --- a/frontend/src/app.rs +++ b/frontend/src/app.rs @@ -1,5 +1,4 @@ use crate::components::layout::protected::Protected; -use crate::components::toast::ToastContainer; use crate::components::torrent::table::TorrentTable; use crate::components::torrent::detail::TorrentDetail; use crate::components::auth::login::Login; @@ -9,6 +8,7 @@ use leptos::task::spawn_local; use leptos_router::components::{Router, Routes, Route}; use leptos_router::hooks::use_navigate; use leptos_shadcn_skeleton::Skeleton; +use leptos_shadcn_toast::SonnerProvider; #[component] pub fn App() -> impl IntoView { @@ -70,126 +70,126 @@ pub fn App() -> impl IntoView { }); view! { -
- - "404 Not Found"
}> - } - } /> - } - } /> - - +
+ + "404 Not Found"
}> + } + } /> + } + } /> + + + // Sidebar skeleton +
+ +
+ + + + + + +
+
+ // Main content skeleton +
+ // Header skeleton +
+ + +
+
+ // Table skeleton rows +
+ + + + + + +
+ // Status bar skeleton +
+ +
+
+ + }.into_any()> + + +
+
+ +
+ +
+
+
+ + }.into_any() + }/> + + - // Sidebar skeleton -
- -
- - - - - - -
-
- // Main content skeleton -
- // Header skeleton -
- - -
-
- // Table skeleton rows -
- - - - - - -
- // Status bar skeleton -
- -
-
- - }.into_any()> - - -
-
- -
- -
-
+ }); + + view! { + + + +
"Settings Page (Coming Soon)"
+
+
-
- }.into_any() - }/> - - - - -
"Settings Page (Coming Soon)"
-
-
- - } - }/> - - - - - + }/> + + + + } } diff --git a/frontend/src/components/mod.rs b/frontend/src/components/mod.rs index 41ef545..fccaf48 100644 --- a/frontend/src/components/mod.rs +++ b/frontend/src/components/mod.rs @@ -1,5 +1,4 @@ pub mod context_menu; pub mod layout; -pub mod toast; pub mod torrent; pub mod auth; diff --git a/frontend/src/components/toast.rs b/frontend/src/components/toast.rs deleted file mode 100644 index bc35e3d..0000000 --- a/frontend/src/components/toast.rs +++ /dev/null @@ -1,86 +0,0 @@ -use leptos::prelude::*; -use shared::NotificationLevel; -use leptos_shadcn_alert::{Alert, AlertVariant}; - -// ============================================================================ -// Toast Components - Using ShadCN Alert -// ============================================================================ - -fn level_to_variant(level: &NotificationLevel) -> AlertVariant { - match level { - NotificationLevel::Info => AlertVariant::Default, - NotificationLevel::Success => AlertVariant::Success, - NotificationLevel::Warning => AlertVariant::Warning, - NotificationLevel::Error => AlertVariant::Destructive, - } -} - -fn level_icon(level: &NotificationLevel) -> impl IntoView { - match level { - NotificationLevel::Info => view! { - - - - }.into_any(), - NotificationLevel::Success => view! { - - - - }.into_any(), - NotificationLevel::Warning => view! { - - - - }.into_any(), - NotificationLevel::Error => view! { - - - - }.into_any(), - } -} - -/// Individual toast item component -#[component] -fn ToastItem( - level: NotificationLevel, - message: String, -) -> impl IntoView { - let variant = level_to_variant(&level); - let icon = level_icon(&level); - - view! { - -
- {icon} -
{message}
-
-
- } -} - -/// Main toast container - renders all active notifications -#[component] -pub fn ToastContainer() -> impl IntoView { - let store = use_context::().expect("TorrentStore not provided"); - let notifications = store.notifications; - - view! { -
- - } - } - /> -
- } -} diff --git a/frontend/src/components/torrent/add_torrent.rs b/frontend/src/components/torrent/add_torrent.rs index 7d7178d..824a00d 100644 --- a/frontend/src/components/torrent/add_torrent.rs +++ b/frontend/src/components/torrent/add_torrent.rs @@ -11,7 +11,6 @@ pub fn AddTorrentDialog( on_close: Callback<()>, ) -> impl IntoView { let store = use_context::().expect("TorrentStore not provided"); - let notifications = store.notifications; let uri = signal(String::new()); let is_loading = signal(false); @@ -34,11 +33,7 @@ pub fn AddTorrentDialog( match api::torrent::add(&uri_val).await { Ok(_) => { log::info!("Torrent added successfully"); - crate::store::show_toast_with_signal( - notifications, - shared::NotificationLevel::Success, - "Torrent başarıyla eklendi" - ); + crate::store::toast_success("Torrent başarıyla eklendi"); on_close.run(()); } Err(e) => { diff --git a/frontend/src/components/torrent/table.rs b/frontend/src/components/torrent/table.rs index ee03db7..fe06599 100644 --- a/frontend/src/components/torrent/table.rs +++ b/frontend/src/components/torrent/table.rs @@ -1,6 +1,6 @@ use leptos::prelude::*; use leptos::task::spawn_local; -use crate::store::{get_action_messages, show_toast_with_signal}; +use crate::store::{get_action_messages, show_toast}; use crate::api; use shared::NotificationLevel; use crate::components::context_menu::TorrentContextMenu; @@ -116,7 +116,6 @@ pub fn TorrentTable() -> impl IntoView { let (success_msg_str, error_msg_str): (&'static str, &'static str) = get_action_messages(&action); let success_msg = success_msg_str.to_string(); let error_msg = error_msg_str.to_string(); - let notifications = store.notifications; spawn_local(async move { let result = match action.as_str() { "delete" => api::torrent::delete(&hash).await, @@ -126,8 +125,8 @@ pub fn TorrentTable() -> impl IntoView { _ => api::torrent::action(&hash, &action).await, }; match result { - Ok(_) => show_toast_with_signal(notifications, NotificationLevel::Success, success_msg), - Err(e) => show_toast_with_signal(notifications, NotificationLevel::Error, format!("{}: {:?}", error_msg, e)), + Ok(_) => show_toast(NotificationLevel::Success, success_msg), + Err(e) => show_toast(NotificationLevel::Error, format!("{}: {:?}", error_msg, e)), } }); }); diff --git a/frontend/src/store.rs b/frontend/src/store.rs index e0fa3f0..1313823 100644 --- a/frontend/src/store.rs +++ b/frontend/src/store.rs @@ -7,40 +7,18 @@ use std::collections::HashMap; use struct_patch::traits::Patch; use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64}; -#[derive(Clone, Debug, PartialEq)] -pub struct NotificationItem { - pub id: u64, - pub notification: SystemNotification, -} - -pub fn show_toast_with_signal( - notifications: RwSignal>, - level: NotificationLevel, - message: impl Into, -) { - let id = js_sys::Date::now() as u64; - let notification = SystemNotification { - level, - message: message.into(), - }; - let item = NotificationItem { id, notification }; - - notifications.update(|list| list.push(item)); - - leptos::prelude::set_timeout( - move || { - notifications.update(|list| list.retain(|i| i.id != id)); - }, - std::time::Duration::from_secs(5), - ); -} - pub fn show_toast(level: NotificationLevel, message: impl Into) { - if let Some(store) = use_context::() { - show_toast_with_signal(store.notifications, level, message); + let msg = message.into(); + match level { + NotificationLevel::Info => { leptos_shadcn_toast::toast::info(&msg).show(); }, + NotificationLevel::Success => { leptos_shadcn_toast::toast::success(&msg).show(); }, + NotificationLevel::Warning => { leptos_shadcn_toast::toast::warning(&msg).show(); }, + NotificationLevel::Error => { leptos_shadcn_toast::toast::error(&msg).show(); }, } } + + pub fn toast_success(message: impl Into) { show_toast(NotificationLevel::Success, message); } pub fn toast_error(message: impl Into) { show_toast(NotificationLevel::Error, message); } @@ -67,7 +45,6 @@ pub struct TorrentStore { pub filter: RwSignal, pub search_query: RwSignal, pub global_stats: RwSignal, - pub notifications: RwSignal>, pub user: RwSignal>, pub selected_torrent: RwSignal>, } @@ -77,16 +54,14 @@ pub fn provide_torrent_store() { let filter = RwSignal::new(FilterStatus::All); let search_query = RwSignal::new(String::new()); let global_stats = RwSignal::new(GlobalStats::default()); - let notifications = RwSignal::new(Vec::::new()); let user = RwSignal::new(Option::::None); let selected_torrent = RwSignal::new(Option::::None); let show_browser_notification = crate::utils::notification::use_app_notification(); - let store = TorrentStore { torrents, filter, search_query, global_stats, notifications, user, selected_torrent }; + let store = TorrentStore { torrents, filter, search_query, global_stats, user, selected_torrent }; provide_context(store); - let notifications_for_sse = notifications; let global_stats_for_sse = global_stats; let torrents_for_sse = torrents; let show_browser_notification = show_browser_notification.clone(); @@ -112,7 +87,7 @@ pub fn provide_torrent_store() { got_first_message = true; backoff_ms = 1000; if was_connected && disconnect_notified { - show_toast_with_signal(notifications_for_sse, NotificationLevel::Success, "Sunucu bağlantısı yeniden kuruldu"); + show_toast(NotificationLevel::Success, "Sunucu bağlantısı yeniden kuruldu"); disconnect_notified = false; } was_connected = true; @@ -149,7 +124,7 @@ pub fn provide_torrent_store() { } AppEvent::Stats(stats) => { global_stats_for_sse.set(stats); } AppEvent::Notification(n) => { - show_toast_with_signal(notifications_for_sse, n.level.clone(), n.message.clone()); + show_toast(n.level.clone(), n.message.clone()); if n.message.contains("tamamlandı") || n.level == shared::NotificationLevel::Error { show_browser_notification("VibeTorrent", &n.message); } @@ -164,14 +139,14 @@ pub fn provide_torrent_store() { } } if was_connected && !disconnect_notified { - show_toast_with_signal(notifications_for_sse, NotificationLevel::Warning, "Sunucu bağlantısı kesildi, yeniden bağlanılıyor..."); + show_toast(NotificationLevel::Warning, "Sunucu bağlantısı kesildi, yeniden bağlanılıyor..."); disconnect_notified = true; } } } Err(_) => { if was_connected && !disconnect_notified { - show_toast_with_signal(notifications_for_sse, NotificationLevel::Warning, "Sunucu bağlantısı kurulamıyor..."); + show_toast(NotificationLevel::Warning, "Sunucu bağlantısı kurulamıyor..."); disconnect_notified = true; } }