// src/pages/register/logic.rs use crate::services::auth::AuthClient; use crate::state::app::state::AppState; use crate::ui::handlers::context::DialogPurpose; use crate::buffer::state::{AppView, BufferState}; use common::proto::komp_ac::auth::AuthResponse; use crate::pages::register::RegisterFormState; use anyhow::Context; use tokio::spawn; use tokio::sync::mpsc; use tracing::{info, error}; #[derive(Debug)] pub enum RegisterResult { Success(AuthResponse), Failure(String), ConnectionError(String), } /// Clears the registration form fields. pub async fn revert( register_state: &mut RegisterFormState, app_state: &mut AppState, ) -> String { register_state.username_mut().clear(); register_state.email_mut().clear(); register_state.password_mut().clear(); register_state.password_confirmation_mut().clear(); register_state.role_mut().clear(); register_state.set_error_message(None); register_state.set_has_unsaved_changes(false); register_state.set_current_field(0); // Reset focus to first field register_state.set_current_cursor_pos(0); app_state.hide_dialog(); "Registration form cleared".to_string() } /// Clears the form and returns to the intro screen. pub async fn back_to_login( register_state: &mut RegisterFormState, app_state: &mut AppState, buffer_state: &mut BufferState, ) -> String { // Clear fields first let _ = revert(register_state, app_state).await; // Ensure dialog is hidden app_state.hide_dialog(); // Navigation logic buffer_state.close_active_buffer(); buffer_state.update_history(AppView::Login); // Reset focus state app_state.ui.focus_outside_canvas = false; app_state.focused_button_index = 0; "Returned to main menu".to_string() } /// Validates input, shows loading, and spawns the registration task. pub fn initiate_registration( register_state: &mut RegisterFormState, app_state: &mut AppState, mut auth_client: AuthClient, sender: mpsc::Sender, ) -> String { register_state.sync_from_editor(); let username = register_state.username().to_string(); let email = register_state.email().to_string(); let password = register_state.password().to_string(); let password_confirmation = register_state.password_confirmation().to_string(); let role = register_state.role().to_string(); // 1. Client-side validation if username.trim().is_empty() { app_state.show_dialog( "Registration Failed", "Username cannot be empty.", vec!["OK".to_string()], DialogPurpose::RegisterFailed, ); "Username cannot be empty.".to_string() } else if !password.is_empty() && password != password_confirmation { app_state.show_dialog( "Registration Failed", "Passwords do not match.", vec!["OK".to_string()], DialogPurpose::RegisterFailed, ); "Passwords do not match.".to_string() } else { // 2. Show Loading Dialog app_state.show_loading_dialog("Registering", "Please wait..."); // 3. Spawn the registration task spawn(async move { let password_opt = if password.is_empty() { None } else { Some(password) }; let password_conf_opt = if password_confirmation.is_empty() { None } else { Some(password_confirmation) }; let role_opt = if role.is_empty() { None } else { Some(role) }; let register_outcome = match auth_client .register(username.clone(), email, password_opt, password_conf_opt, role_opt) .await .with_context(|| format!("Spawned register task failed for username: {}", username)) { Ok(response) => RegisterResult::Success(response), Err(e) => RegisterResult::Failure(format!("{}", e)), }; // Send result back to the main UI thread if let Err(e) = sender.send(register_outcome).await { error!("Failed to send registration result: {}", e); } }); // 4. Return immediately "Registration initiated.".to_string() } } /// Handles the result received from the registration task. /// Returns true if a redraw is needed. pub fn handle_registration_result( result: RegisterResult, app_state: &mut AppState, register_state: &mut RegisterFormState, ) -> bool { match result { RegisterResult::Success(response) => { let success_message = format!( "Registration Successful!\n\nUser ID: {}\nUsername: {}\nEmail: {}\nRole: {}", response.id, response.username, response.email, response.role ); app_state.update_dialog_content( &success_message, vec!["OK".to_string()], DialogPurpose::RegisterSuccess, ); info!(message = %success_message, "Registration successful"); } RegisterResult::Failure(err_msg) | RegisterResult::ConnectionError(err_msg) => { app_state.update_dialog_content( &err_msg, vec!["OK".to_string()], DialogPurpose::RegisterFailed, ); register_state.set_error_message(Some(err_msg.clone())); error!(error = %err_msg, "Registration failed/connection error"); } } register_state.set_has_unsaved_changes(false); // Clear flag after processing true // Request redraw as dialog content changed }