register on the way

This commit is contained in:
filipriec
2025-04-10 18:50:54 +02:00
parent 4e01740a61
commit b51e76e366
6 changed files with 276 additions and 5 deletions

View File

@@ -3,3 +3,4 @@ pub mod login;
pub mod register;
pub use login::*;
pub use register::*;

View File

@@ -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,
);
}
}

View File

@@ -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()

View File

@@ -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<String>,
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;
}
}

View File

@@ -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(),

View File

@@ -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 {