summaryrefslogtreecommitdiffstats
path: root/src/views/login_page.rs
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@bunny.garden>2025-06-01 16:10:26 +0100
committerLibravatar cel 🌸 <cel@bunny.garden>2025-06-01 17:27:40 +0100
commit6ee4190a26f32bfa953302ee363ad3bb6c384ebb (patch)
tree2c3182c29d5780a0ad9c9770b5e546312bea49b4 /src/views/login_page.rs
parentf76c80c1d23177ab00c81240ee3a75d3bcda0e3b (diff)
downloadmacaw-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.rs189
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>
+ }
+}