use dioxus::prelude::*;
use crate::notifications::push_rules::persist_room_notification_level;
use crate::state::app_state::{AppState, RightPanelView};
use crate::state::room_state::NotificationLevel;
#[component]
pub fn NotificationPanel() -> Element {
let mut state = use_context::<Signal<AppState>>();
let mut saving = use_signal(|| false);
let mut save_error = use_signal(|| Option::<String>::None);
let state_read = state.read();
let current_level = state_read
.active_room()
.map(|r| r.notification_level.clone())
.unwrap_or(NotificationLevel::Default);
let close_panel = move |_| {
state.write().right_panel = RightPanelView::Closed;
};
let back_to_info = move |_| {
state.write().right_panel = RightPanelView::RoomInfo;
};
let mut set_level = move |level: NotificationLevel| {
let (client, room_id, previous_level) = {
let state_read = state.read();
(
state_read.client.clone(),
state_read.active_room_id.clone(),
state_read
.active_room()
.map(|room| room.notification_level.clone())
.unwrap_or(NotificationLevel::Default),
)
};
let Some(client) = client else {
save_error.set(Some("Not logged in".to_string()));
return;
};
let Some(room_id) = room_id else {
return;
};
if let Some(room) = state.write().rooms.get_mut(&room_id) {
room.notification_level = level.clone();
}
saving.set(true);
save_error.set(None);
spawn(async move {
match persist_room_notification_level(&client, &room_id, level.clone()).await {
Ok(()) => {}
Err(e) => {
if let Some(room) = state.write().rooms.get_mut(&room_id) {
room.notification_level = previous_level;
}
save_error.set(Some(e));
}
}
saving.set(false);
});
};
rsx! {
div {
class: "notification-panel",
header {
class: "notification-panel__header",
button {
class: "notification-panel__back-btn",
title: "Back to room info",
onclick: back_to_info,
"←"
}
h3 {
class: "notification-panel__title",
"Notifications"
}
button {
class: "notification-panel__close-btn",
title: "Close panel",
onclick: close_panel,
"✕"
}
}
div {
class: "notification-panel__description",
p {
"Choose how you want to be notified about activity in this room."
}
if *saving.read() {
p { "Saving..." }
}
if let Some(err) = save_error.read().as_ref() {
p { "{err}" }
}
}
div {
class: "notification-panel__options",
NotificationOption {
label: "Default",
description: "Use your global notification settings.",
is_selected: matches!(current_level, NotificationLevel::Default),
disabled: *saving.read(),
on_select: move |_| set_level(NotificationLevel::Default),
}
NotificationOption {
label: "All Messages",
description: "Get notified for every message in this room.",
is_selected: matches!(current_level, NotificationLevel::AllMessages),
disabled: *saving.read(),
on_select: move |_| set_level(NotificationLevel::AllMessages),
}
NotificationOption {
label: "Mentions & Keywords",
description: "Only get notified when you are mentioned or a keyword is used.",
is_selected: matches!(current_level, NotificationLevel::MentionsAndKeywords),
disabled: *saving.read(),
on_select: move |_| set_level(NotificationLevel::MentionsAndKeywords),
}
NotificationOption {
label: "Mute",
description: "You will not receive any notifications from this room.",
is_selected: matches!(current_level, NotificationLevel::Mute),
disabled: *saving.read(),
on_select: move |_| set_level(NotificationLevel::Mute),
}
}
}
}
}
#[component]
fn NotificationOption(
label: &'static str,
description: &'static str,
is_selected: bool,
disabled: bool,
on_select: EventHandler<MouseEvent>,
) -> Element {
let class = if is_selected {
"notification-option notification-option--selected"
} else {
"notification-option"
};
rsx! {
button {
class: "{class}",
disabled: disabled,
onclick: move |evt| on_select.call(evt),
div {
class: "notification-option__radio",
if is_selected {
span { class: "notification-option__radio-dot" }
}
}
div {
class: "notification-option__text",
span {
class: "notification-option__label",
"{label}"
}
span {
class: "notification-option__description",
"{description}"
}
}
}
}
}