diff options
author | 2025-06-01 16:10:26 +0100 | |
---|---|---|
committer | 2025-06-01 17:27:40 +0100 | |
commit | 6ee4190a26f32bfa953302ee363ad3bb6c384ebb (patch) | |
tree | 2c3182c29d5780a0ad9c9770b5e546312bea49b4 /src/views/login_page.rs | |
parent | f76c80c1d23177ab00c81240ee3a75d3bcda0e3b (diff) | |
download | macaw-web-6ee4190a26f32bfa953302ee363ad3bb6c384ebb.tar.gz macaw-web-6ee4190a26f32bfa953302ee363ad3bb6c384ebb.tar.bz2 macaw-web-6ee4190a26f32bfa953302ee363ad3bb6c384ebb.zip |
refactor: reorganise code
Diffstat (limited to 'src/views/login_page.rs')
-rw-r--r-- | src/views/login_page.rs | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/src/views/login_page.rs b/src/views/login_page.rs new file mode 100644 index 0000000..2edd4b5 --- /dev/null +++ b/src/views/login_page.rs @@ -0,0 +1,189 @@ +use std::{str::FromStr, sync::Arc}; + +use filamento::{db::Db, error::{CommandError, ConnectionError}, files::{opfs::OPFSError, FilesMem, FilesOPFS}, UpdateMessage}; +use jid::JID; +use thiserror::Error; +use leptos::prelude::*; +use tokio::sync::mpsc::Receiver; +use tracing::debug; + +use crate::{client::Client, files::Files}; + +use super::AppState; + +#[derive(Clone, Debug, Error)] +pub enum LoginError { + #[error("Missing Password")] + MissingPassword, + #[error("Missing JID")] + MissingJID, + #[error("Invalid JID: {0}")] + InvalidJID(#[from] jid::ParseError), + #[error("Connection Error: {0}")] + ConnectionError(#[from] CommandError<ConnectionError>), + #[error("OPFS: {0}")] + OPFS(#[from] OPFSError), +} + +#[component] +pub fn LoginPage( + set_app: WriteSignal<AppState>, + set_client: WriteSignal<Option<(Client, Receiver<UpdateMessage>)>>, +) -> impl IntoView { + let jid = RwSignal::new("".to_string()); + let password = RwSignal::new("".to_string()); + let remember_me = RwSignal::new(false); + let connect_on_login = RwSignal::new(true); + + let (error, set_error) = signal(None::<LoginError>); + let error_message = move || { + error.with(|error| { + if let Some(error) = error { + view! { <div class="error">{error.to_string()}</div> }.into_any() + } else { + view! {}.into_any() + } + }) + }; + + let (login_pending, set_login_pending) = signal(false); + + let login = Action::new_local(move |_| { + async move { + set_login_pending.set(true); + + if jid.read_untracked().is_empty() { + set_error.set(Some(LoginError::MissingJID)); + set_login_pending.set(false); + return; + } + + if password.read_untracked().is_empty() { + set_error.set(Some(LoginError::MissingPassword)); + set_login_pending.set(false); + return; + } + + let jid = match JID::from_str(&jid.read_untracked()) { + Ok(j) => j, + Err(e) => { + set_error.set(Some(e.into())); + set_login_pending.set(false); + return; + } + }; + + let remember_me = remember_me.get_untracked(); + // initialise the client + let db = if remember_me { + debug!("creating db in opfs"); + Db::create_connect_and_migrate(jid.as_bare().to_string()) + .await + .unwrap() + } else { + debug!("creating db in memory"); + Db::create_connect_and_migrate_memory().await.unwrap() + }; + let files = if remember_me { + let opfs = FilesOPFS::new(jid.as_bare().to_string()).await; + match opfs { + Ok(f) => Files::Opfs(f), + Err(e) => { + set_error.set(Some(e.into())); + set_login_pending.set(false); + return; + } + } + } else { + Files::Mem(FilesMem::new()) + }; + let (client, updates) = filamento::Client::new( + jid.clone(), + password.read_untracked().clone(), + db, + files.clone(), + ); + let resource = ArcRwSignal::new(None::<String>); + let client = Client { + client, + resource: resource.clone(), + jid: Arc::new(jid.to_bare()), + file_store: files, + }; + + if *connect_on_login.read_untracked() { + match client.connect().await { + Ok(r) => { + resource.set(Some(r)) + } + Err(e) => { + set_error.set(Some(e.into())); + set_login_pending.set(false); + return; + } + } + } + + // debug!("before setting app state"); + set_client.set(Some((client, updates))); + set_app.set(AppState::LoggedIn); + } + }); + + view! { + <div class="center fill"> + <div id="login-form" class="panel"> + <div id="hero"> + <img src="/assets/macaw-icon.png" /> + <h1>Macaw Instant Messenger</h1> + </div> + {error_message} + <form on:submit=move |ev| { + ev.prevent_default(); + login.dispatch(()); + }> + <label for="jid">JID</label> + <input + disabled=login_pending + placeholder="caw@macaw.chat" + type="text" + bind:value=jid + name="jid" + id="jid" + autofocus="true" + /> + <label for="password">Password</label> + <input + disabled=login_pending + placeholder="••••••••" + type="password" + bind:value=password + name="password" + id="password" + /> + <div> + <label for="remember_me">Remember me</label> + <input + disabled=login_pending + type="checkbox" + bind:checked=remember_me + name="remember_me" + id="remember_me" + /> + </div> + <div> + <label for="connect_on_login">Connect on login</label> + <input + disabled=login_pending + type="checkbox" + bind:checked=connect_on_login + name="connect_on_login" + id="connect_on_login" + /> + </div> + <input disabled=login_pending class="button" type="submit" value="Log In" /> + </form> + </div> + </div> + } +} |