login refactored
This commit is contained in:
@@ -9,6 +9,9 @@ use crate::state::pages::canvas_state::CanvasState;
|
||||
use crate::ui::handlers::context::DialogPurpose;
|
||||
use common::proto::multieko2::auth::LoginResponse;
|
||||
use anyhow::{Context, Result};
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::{info, error};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoginResult {
|
||||
@@ -139,3 +142,87 @@ pub async fn back_to_main(
|
||||
"Returned to main menu".to_string()
|
||||
}
|
||||
|
||||
/// Validates input, shows loading, and spawns the login task.
|
||||
pub fn initiate_login(
|
||||
login_state: &LoginState,
|
||||
app_state: &mut AppState,
|
||||
sender: mpsc::Sender<LoginResult>,
|
||||
) -> String {
|
||||
let username = login_state.username.clone();
|
||||
let password = login_state.password.clone();
|
||||
|
||||
// 1. Client-side validation
|
||||
if username.trim().is_empty() {
|
||||
app_state.show_dialog(
|
||||
"Login Failed",
|
||||
"Username/Email cannot be empty.",
|
||||
vec!["OK".to_string()],
|
||||
DialogPurpose::LoginFailed,
|
||||
);
|
||||
"Username cannot be empty.".to_string()
|
||||
} else {
|
||||
// 2. Show Loading Dialog
|
||||
app_state.show_loading_dialog("Logging In", "Please wait...");
|
||||
|
||||
// 3. Spawn the login task
|
||||
spawn(async move {
|
||||
let login_outcome = match AuthClient::new().await {
|
||||
Ok(mut auth_client) => {
|
||||
match auth_client.login(username.clone(), password).await
|
||||
.with_context(|| format!("Spawned login task failed for identifier: {}", username))
|
||||
{
|
||||
Ok(response) => LoginResult::Success(response),
|
||||
Err(e) => LoginResult::Failure(format!("{}", e)),
|
||||
}
|
||||
}
|
||||
Err(e) => LoginResult::ConnectionError(format!("Failed to create AuthClient: {}", e)),
|
||||
};
|
||||
// Send result back to the main UI thread
|
||||
if let Err(e) = sender.send(login_outcome).await {
|
||||
error!("Failed to send login result: {}", e);
|
||||
}
|
||||
});
|
||||
|
||||
// 4. Return immediately
|
||||
"Login initiated.".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the result received from the login task.
|
||||
/// Returns true if a redraw is needed.
|
||||
pub fn handle_login_result(
|
||||
result: LoginResult,
|
||||
app_state: &mut AppState,
|
||||
auth_state: &mut AuthState,
|
||||
login_state: &mut LoginState,
|
||||
) -> bool {
|
||||
match result {
|
||||
LoginResult::Success(response) => {
|
||||
auth_state.auth_token = Some(response.access_token.clone());
|
||||
auth_state.user_id = Some(response.user_id.clone());
|
||||
auth_state.role = Some(response.role.clone());
|
||||
auth_state.decoded_username = Some(response.username.clone());
|
||||
|
||||
let success_message = format!(
|
||||
"Login Successful!\n\nUsername: {}\nUser ID: {}\nRole: {}",
|
||||
response.username, response.user_id, response.role
|
||||
);
|
||||
app_state.update_dialog_content(
|
||||
&success_message,
|
||||
vec!["Menu".to_string(), "Exit".to_string()],
|
||||
DialogPurpose::LoginSuccess,
|
||||
);
|
||||
info!(message = %success_message, "Login successful");
|
||||
}
|
||||
LoginResult::Failure(err_msg) | LoginResult::ConnectionError(err_msg) => {
|
||||
app_state.update_dialog_content(&err_msg, vec!["OK".to_string()], DialogPurpose::LoginFailed);
|
||||
login_state.error_message = Some(err_msg.clone());
|
||||
error!(error = %err_msg, "Login failed/connection error");
|
||||
}
|
||||
}
|
||||
login_state.username.clear();
|
||||
login_state.password.clear();
|
||||
login_state.set_has_unsaved_changes(false);
|
||||
login_state.current_cursor_pos = 0;
|
||||
true // Request redraw as dialog content changed
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user