use std::str::FromStr; use filamento::{chat::Chat, error::{CommandError, DatabaseError}, user::User}; use jid::{BareJID, JID}; use leptos::{html::Input, prelude::*}; use leptos_fetch::QueryClient; use reactive_stores::{ArcStore, Store}; use thiserror::Error; use crate::{chat::MacawChat, client::Client, open_chats::OpenChatsPanel, user::MacawUser}; #[derive(Clone, Debug, Error)] pub enum NewChatError { #[error("Missing JID")] MissingJID, #[error("Invalid JID: {0}")] InvalidJID(#[from] jid::ParseError), #[error("Database: {0}")] Db(#[from] CommandError), } // TODO: remove async fn get_chat(jid: BareJID) -> ArcStore { let client: Client = use_context().expect("no client in context"); ArcStore::new(client.get_chat(jid).await.unwrap()) } async fn get_user(jid: BareJID) -> ArcStore { let client: Client = use_context().expect("no client in context"); ArcStore::new(client.get_user(jid).await.unwrap()) } #[component] pub fn NewChatWidget(set_open_new_chat: WriteSignal) -> impl IntoView { let jid = RwSignal::new("".to_string()); // TODO: compartmentalise into error component, form component... let (error, set_error) = signal(None::); let error_message = move || { error.with(|error| { if let Some(error) = error { view! {
{error.to_string()}
}.into_any() } else { view! {}.into_any() } }) }; let (new_chat_pending, set_new_chat_pending) = signal(false); let open_chats: Store = use_context().expect("no open chats panel store in context"); let client = use_context::().expect("client not in context"); let query_client: QueryClient = expect_context(); let open_chat = Action::new_local(move |_| { let client = client.clone(); async move { set_new_chat_pending.set(true); if jid.read_untracked().is_empty() { set_error.set(Some(NewChatError::MissingJID)); set_new_chat_pending.set(false); return; } let jid = match JID::from_str(&jid.read_untracked()) { // TODO: ability to direct address a resource? Ok(j) => j.to_bare(), Err(e) => { set_error.set(Some(e.into())); set_new_chat_pending.set(false); return; } }; let chat_jid = jid; let (chat, user) = match client.get_chat_and_user(chat_jid).await { Ok(c) => c, Err(e) => { set_error.set(Some(e.into())); set_new_chat_pending.set(false); return; }, }; let chat = { // let user = MacawUser::got_user(user); let jid = chat.correspondent.clone(); let chat_store = query_client.subscribe_value_local(get_chat, move || jid.clone()); if let Some(chat_store) = chat_store.get() { chat_store.set(chat); let user = { let jid = user.jid.clone(); let user_store = query_client.subscribe_value_local(get_user, move || jid.clone()); if let Some(user_store) = user_store.get() { user_store.set(user); MacawUser { user: user_store } } else { let jid = user.jid.clone(); let user_store = ArcStore::new(user); query_client.set_query_local(get_user, jid, user_store.clone()); MacawUser { user: user_store, } } }; MacawChat { chat: chat_store, user } } else { let jid = chat.correspondent.clone(); let chat_store = ArcStore::new(chat); query_client.set_query_local(get_chat, jid, chat_store.clone()); let user = { let jid = user.jid.clone(); let user_store = query_client.subscribe_value_local(get_user, move || jid.clone()); if let Some(user_store) = user_store.get() { user_store.set(user); MacawUser { user: user_store } } else { let jid = user.jid.clone(); let user_store = ArcStore::new(user); query_client.set_query_local(get_user, jid, user_store.clone()); MacawUser { user: user_store, } } }; MacawChat { chat: chat_store, user, } } }; open_chats.update(|open_chats| open_chats.open(chat.clone())); set_open_new_chat.set(false); } }); let jid_input = NodeRef::::new(); let _focus = Effect::new(move |_| { if let Some(input) = jid_input.get() { let _ = input.focus(); input.set_text_content(Some("")); // input.style("height: 0"); // let height = input.scroll_height(); // input.style(format!("height: {}px", height)); } }); view! {
{error_message}
} }