From b51e76e366073d3d927ee807276f260465eadc13 Mon Sep 17 00:00:00 2001 From: filipriec Date: Thu, 10 Apr 2025 18:50:54 +0200 Subject: [PATCH] register on the way --- client/src/components/auth.rs | 1 + client/src/components/auth/register.rs | 153 +++++++++++++++++++++++++ client/src/modes/canvas/edit.rs | 2 +- client/src/state/pages/auth.rs | 115 +++++++++++++++++++ client/src/state/state.rs | 5 +- client/src/ui/handlers/render.rs | 5 +- 6 files changed, 276 insertions(+), 5 deletions(-) diff --git a/client/src/components/auth.rs b/client/src/components/auth.rs index 428841c..6e7c225 100644 --- a/client/src/components/auth.rs +++ b/client/src/components/auth.rs @@ -3,3 +3,4 @@ pub mod login; pub mod register; pub use login::*; +pub use register::*; diff --git a/client/src/components/auth/register.rs b/client/src/components/auth/register.rs index e69de29..6cd19f5 100644 --- a/client/src/components/auth/register.rs +++ b/client/src/components/auth/register.rs @@ -0,0 +1,153 @@ +// src/components/auth/register.rs + +use crate::{ + config::colors::themes::Theme, + state::pages::auth::RegisterState, // Use RegisterState + components::common::dialog, + state::state::AppState, +}; +use ratatui::{ + layout::{Alignment, Constraint, Direction, Layout, Rect, Margin}, + style::{Style, Modifier, Color}, + widgets::{Block, BorderType, Borders, Paragraph}, + Frame, +}; + +pub fn render_register( + f: &mut Frame, + area: Rect, + theme: &Theme, + state: &RegisterState, // Use RegisterState + app_state: &AppState, + is_edit_mode: bool, +) { + let block = Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Plain) + .border_style(Style::default().fg(theme.border)) + .title(" Register ") // Update title + .style(Style::default().bg(theme.bg)); + + f.render_widget(block, area); + + let inner_area = area.inner(Margin { + horizontal: 1, + vertical: 1, + }); + + // Adjust constraints for 4 fields + error + buttons + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(6), // Form (4 fields + padding) + Constraint::Length(1), // Error message + Constraint::Length(3), // Buttons + ]) + .split(inner_area); + + // --- FORM RENDERING --- + crate::components::handlers::canvas::render_canvas( + f, + chunks[0], + state, // Pass RegisterState + &[ // Update field labels + "Username", + "Email (Optional)", + "Password (Optional)", + "Confirm Password", + ], + &state.current_field, + &[ // Update values from RegisterState + &state.username, + &state.email, + &state.password, + &state.password_confirmation, + ], + theme, + is_edit_mode, + ); + + // --- ERROR MESSAGE --- + if let Some(err) = &state.error_message { + f.render_widget( + Paragraph::new(err.as_str()) + .style(Style::default().fg(Color::Red)) + .alignment(Alignment::Center), + chunks[1], + ); + } + + // --- BUTTONS --- + let button_chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Percentage(50), Constraint::Percentage(50)]) + .split(chunks[2]); + + // Register Button + let register_button_index = 0; + let register_active = if app_state.ui.focus_outside_canvas { + app_state.general.selected_item == register_button_index + } else { + false + }; + let mut register_style = Style::default().fg(theme.fg); + let mut register_border = Style::default().fg(theme.border); + if register_active { + register_style = register_style.fg(theme.highlight).add_modifier(Modifier::BOLD); + register_border = register_border.fg(theme.accent); + } + + f.render_widget( + Paragraph::new("Register") // Update button text + .style(register_style) + .alignment(Alignment::Center) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Plain) + .border_style(register_border), + ), + button_chunks[0], + ); + + // Return Button (logic remains similar) + let return_button_index = 1; + let return_active = if app_state.ui.focus_outside_canvas { + app_state.general.selected_item == return_button_index + } else { + false + }; + let mut return_style = Style::default().fg(theme.fg); + let mut return_border = Style::default().fg(theme.border); + if return_active { + return_style = return_style.fg(theme.highlight).add_modifier(Modifier::BOLD); + return_border = return_border.fg(theme.accent); + } + + f.render_widget( + Paragraph::new("Return") + .style(return_style) + .alignment(Alignment::Center) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Plain) + .border_style(return_border), + ), + button_chunks[1], + ); + + // --- DIALOG --- (Keep dialog logic) + if app_state.ui.dialog.dialog_show { + dialog::render_dialog( + f, + f.area(), + theme, + &app_state.ui.dialog.dialog_title, + &app_state.ui.dialog.dialog_message, + &app_state.ui.dialog.dialog_buttons, + app_state.ui.dialog.dialog_active_button_index, + ); + } +} + diff --git a/client/src/modes/canvas/edit.rs b/client/src/modes/canvas/edit.rs index 2bc7c9d..292a371 100644 --- a/client/src/modes/canvas/edit.rs +++ b/client/src/modes/canvas/edit.rs @@ -55,7 +55,7 @@ pub async fn handle_edit_event( ).await .map(|outcome| match outcome { EventOutcome::Ok(msg) => msg, - EventOutcome::Exit(msg) => format!("Exit requested: {}", msg), // Or handle differently + EventOutcome::Exit(msg) => format!("Exit requested: {}", msg), EventOutcome::DataSaved(save_outcome, msg) => format!("Data saved ({:?}): {}", save_outcome, msg), EventOutcome::ButtonSelected { context, index } => { "Unexpected action in edit mode".to_string() diff --git a/client/src/state/pages/auth.rs b/client/src/state/pages/auth.rs index 94f5126..8ea976c 100644 --- a/client/src/state/pages/auth.rs +++ b/client/src/state/pages/auth.rs @@ -15,6 +15,18 @@ pub struct AuthState { pub has_unsaved_changes: bool, } +#[derive(Default, Clone)] // Add Clone derive +pub struct RegisterState { + pub username: String, + pub email: String, + pub password: String, + pub password_confirmation: String, + pub error_message: Option, + pub current_field: usize, + pub current_cursor_pos: usize, + pub has_unsaved_changes: bool, +} + impl AuthState { pub fn new() -> Self { Self { @@ -32,6 +44,21 @@ impl AuthState { } } +impl RegisterState { + pub fn new() -> Self { + Self { + username: String::new(), + email: String::new(), + password: String::new(), + password_confirmation: String::new(), + error_message: None, + current_field: 0, + current_cursor_pos: 0, + has_unsaved_changes: false, + } + } +} + impl CanvasState for AuthState { fn current_field(&self) -> usize { self.current_field @@ -102,3 +129,91 @@ impl CanvasState for AuthState { self.has_unsaved_changes = changed; } } + +impl CanvasState for RegisterState { + fn current_field(&self) -> usize { + self.current_field + } + + fn current_cursor_pos(&self) -> usize { + let len = match self.current_field { + 0 => self.username.len(), + 1 => self.email.len(), + 2 => self.password.len(), + 3 => self.password_confirmation.len(), + _ => 0, + }; + self.current_cursor_pos.min(len) + } + + fn has_unsaved_changes(&self) -> bool { + self.has_unsaved_changes + } + + fn inputs(&self) -> Vec<&String> { + vec![ + &self.username, + &self.email, + &self.password, + &self.password_confirmation, + ] + } + + fn get_current_input(&self) -> &str { + match self.current_field { + 0 => &self.username, + 1 => &self.email, + 2 => &self.password, + 3 => &self.password_confirmation, + _ => "", + } + } + + fn get_current_input_mut(&mut self) -> &mut String { + match self.current_field { + 0 => &mut self.username, + 1 => &mut self.email, + 2 => &mut self.password, + 3 => &mut self.password_confirmation, + _ => panic!("Invalid current_field index in RegisterState"), + } + } + + fn fields(&self) -> Vec<&str> { + vec![ + "Username", + "Email (Optional)", + "Password (Optional)", + "Confirm Password", + ] + } + + fn set_current_field(&mut self, index: usize) { + if index < 4 { // RegisterState has 4 fields + self.current_field = index; + let len = match self.current_field { + 0 => self.username.len(), + 1 => self.email.len(), + 2 => self.password.len(), + 3 => self.password_confirmation.len(), + _ => 0, + }; + self.current_cursor_pos = self.current_cursor_pos.min(len); + } + } + + fn set_current_cursor_pos(&mut self, pos: usize) { + let len = match self.current_field { + 0 => self.username.len(), + 1 => self.email.len(), + 2 => self.password.len(), + 3 => self.password_confirmation.len(), + _ => 0, + }; + self.current_cursor_pos = pos.min(len); + } + + fn set_has_unsaved_changes(&mut self, changed: bool) { + self.has_unsaved_changes = changed; + } +} diff --git a/client/src/state/state.rs b/client/src/state/state.rs index 98f9620..57596ca 100644 --- a/client/src/state/state.rs +++ b/client/src/state/state.rs @@ -4,6 +4,7 @@ use std::env; use common::proto::multieko2::table_definition::ProfileTreeResponse; use crate::components::IntroState; use crate::modes::handlers::mode_manager::AppMode; +use crate::state::pages::auth::{AuthState, RegisterState}; use crate::ui::handlers::context::DialogPurpose; pub struct DialogState { @@ -21,9 +22,10 @@ pub struct UiState { pub show_admin: bool, pub show_form: bool, pub show_login: bool, + pub show_register: bool, pub intro_state: IntroState, pub focus_outside_canvas: bool, - pub dialog: DialogState, // Add dialog state here + pub dialog: DialogState, } pub struct GeneralState { @@ -144,6 +146,7 @@ impl Default for UiState { show_admin: false, show_form: false, show_login: false, + show_register: false, intro_state: IntroState::new(), focus_outside_canvas: false, dialog: DialogState::default(), diff --git a/client/src/ui/handlers/render.rs b/client/src/ui/handlers/render.rs index 7198759..8690e92 100644 --- a/client/src/ui/handlers/render.rs +++ b/client/src/ui/handlers/render.rs @@ -7,7 +7,7 @@ use crate::components::{ handlers::sidebar::{self, calculate_sidebar_layout}, form::form::render_form, admin::{admin_panel::AdminPanelState}, - auth::login::render_login, + auth::{login::render_login, register::render_register}, }; use crate::config::colors::themes::Theme; use ratatui::layout::{Constraint, Direction, Layout}; @@ -29,7 +29,6 @@ pub fn render_ui( command_mode: bool, command_message: &str, app_state: &AppState, - // intro_state parameter removed ) { render_background(f, f.area(), theme); @@ -52,7 +51,7 @@ pub fn render_ui( main_content_area, theme, auth_state, - app_state, // Add AppState reference here + app_state, auth_state.current_field < 2 ); } else if app_state.ui.show_admin {