#[cfg(test)] use crate::session::SessionIdentity; #[cfg(all(target_family = "wasm", target_os = "unknown"))] pub const AUTH_BROADCAST_CHANNEL: &str = "polymodel-auth"; #[cfg(all(target_family = "wasm", target_os = "unknown"))] pub const SIGN_OUT_MESSAGE: &str = "sign-out"; #[derive(Clone, Debug, PartialEq, Eq)] pub struct Toast { pub id: u64, pub message: String, } #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct ToastState { next_id: u64, items: Vec, } impl ToastState { pub fn push(&mut self, message: impl Into) -> u64 { let id = self.next_id; self.next_id += 1; self.items.push(Toast { id, message: message.into(), }); id } pub fn dismiss(&mut self, id: u64) { self.items.retain(|toast| toast.id != id); } pub fn items(&self) -> &[Toast] { &self.items } } #[cfg(test)] pub fn handle_remote_sign_out(session: &mut SessionIdentity, toasts: &mut ToastState) { *session = SessionIdentity::Anonymous; toasts.push("Signed out in another tab."); } pub fn logout_url() -> &'static str { "/oauth/logout" } #[cfg(all(target_family = "wasm", target_os = "unknown"))] pub fn broadcast_sign_out() { if let Ok(channel) = web_sys::BroadcastChannel::new(AUTH_BROADCAST_CHANNEL) { let _ = channel.post_message(&wasm_bindgen::JsValue::from_str(SIGN_OUT_MESSAGE)); } } #[cfg(not(all(target_family = "wasm", target_os = "unknown")))] pub fn broadcast_sign_out() {} #[cfg(test)] mod tests { use super::*; use jacquard::types::string::Handle; use jacquard_common::types::did::Did; #[test] fn remote_sign_out_clears_session_and_adds_toast() { let mut session = SessionIdentity::Authenticated(crate::session::AuthenticatedIdentity { did: Did::new_owned("did:plc:alice").unwrap(), handle: Handle::new_owned("alice.test").unwrap(), display_name: None, }); let mut toasts = ToastState::default(); handle_remote_sign_out(&mut session, &mut toasts); assert_eq!(session, SessionIdentity::Anonymous); assert_eq!(toasts.items()[0].message, "Signed out in another tab."); } #[test] fn toast_state_dismisses_by_id() { let mut toasts = ToastState::default(); let first = toasts.push("one"); let _second = toasts.push("two"); toasts.dismiss(first); assert_eq!(toasts.items().len(), 1); assert_eq!(toasts.items()[0].message, "two"); } }