144 lines
5.3 KiB
Rust
144 lines
5.3 KiB
Rust
// src/tui/functions/common/register.rs
|
|
|
|
use crate::services::auth::AuthClient;
|
|
use crate::state::{
|
|
pages::auth::RegisterState,
|
|
app::state::AppState,
|
|
pages::canvas_state::CanvasState,
|
|
};
|
|
use crate::ui::handlers::context::DialogPurpose;
|
|
use crate::state::app::buffer::{AppView, BufferState};
|
|
use common::proto::multieko2::auth::AuthResponse;
|
|
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 RegisterState,
|
|
_app_state: &mut AppState, // Keep signature consistent if needed elsewhere
|
|
) -> String {
|
|
register_state.username.clear();
|
|
register_state.email.clear();
|
|
register_state.password.clear();
|
|
register_state.password_confirmation.clear();
|
|
register_state.role.clear();
|
|
register_state.error_message = None;
|
|
register_state.set_has_unsaved_changes(false);
|
|
register_state.current_field = 0; // Reset focus to first field
|
|
register_state.current_cursor_pos = 0;
|
|
"Registration form cleared".to_string()
|
|
}
|
|
|
|
/// Clears the form and returns to the intro screen.
|
|
pub async fn back_to_login(
|
|
register_state: &mut RegisterState,
|
|
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: &RegisterState,
|
|
app_state: &mut AppState,
|
|
mut auth_client: AuthClient,
|
|
sender: mpsc::Sender<RegisterResult>,
|
|
) -> String {
|
|
// Clone necessary data
|
|
let username = register_state.username.clone();
|
|
let email = register_state.email.clone();
|
|
let password = register_state.password.clone();
|
|
let password_confirmation = register_state.password_confirmation.clone();
|
|
let role = register_state.role.clone();
|
|
|
|
// 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 RegisterState,
|
|
) -> 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.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
|
|
}
|