diff --git a/client/src/components/auth/register.rs b/client/src/components/auth/register.rs index f86b396..5cf2edd 100644 --- a/client/src/components/auth/register.rs +++ b/client/src/components/auth/register.rs @@ -46,7 +46,24 @@ pub fn render_register( ]) .split(inner_area); - + // --- FORM RENDERING (Using render_canvas) --- + crate::components::handlers::canvas::render_canvas( + f, + chunks[0], // Area for the canvas + state, // The state object (RegisterState) + &[ // Field labels + "Username", + "Email (Optional)", + "Password (Optional)", + "Confirm Password", + "Role (Optional)", + ], + &state.current_field(), // Pass current field index + &state.inputs().iter().map(|s| *s).collect::>(), // Pass inputs directly + theme, + is_edit_mode, + // No need to pass suggestion state here, render_canvas uses the trait + ); // --- ERROR MESSAGE --- if let Some(err) = &state.error_message { @@ -130,32 +147,4 @@ pub fn render_register( app_state.ui.dialog.dialog_active_button_index, ); } - - // --- AUTOCOMPLETE DROPDOWN RENDERING --- - if state.show_role_suggestions && !state.role_suggestions.is_empty() { - // Calculate dropdown area below the role input field - let dropdown_height = (state.role_suggestions.len() as u16).min(5) + 2; // Max 5 suggestions + border - let dropdown_area = Rect { - x: role_input_rect.x, - y: role_input_rect.y + 1, // Position below the input line - width: role_input_rect.width.max(20), // Ensure minimum width - height: dropdown_height, - }; - - // Ensure dropdown doesn't go off screen (simple vertical check) - let screen_height = f.size().height; - let clamped_dropdown_area = if dropdown_area.bottom() > screen_height { - Rect::new(dropdown_area.x, dropdown_area.y.saturating_sub(dropdown_height + 1), dropdown_area.width, dropdown_area.height) - } else { - dropdown_area - }; - - autocomplete::render_autocomplete_dropdown( - f, - clamped_dropdown_area, - theme, - &state.role_suggestions, - state.selected_suggestion_index, - ); - } } diff --git a/client/src/components/handlers/canvas.rs b/client/src/components/handlers/canvas.rs index 134a9fa..9488ad3 100644 --- a/client/src/components/handlers/canvas.rs +++ b/client/src/components/handlers/canvas.rs @@ -9,6 +9,7 @@ use ratatui::{ }; use crate::config::colors::themes::Theme; use crate::state::canvas_state::CanvasState; +use crate::components::common::autocomplete; pub fn render_canvas( f: &mut Frame, @@ -56,6 +57,8 @@ pub fn render_canvas( .constraints(vec![Constraint::Length(1); fields.len()]) .split(input_area); + let mut active_field_input_rect = None; + // Render labels for (i, field) in fields.iter().enumerate() { let label = Paragraph::new(Line::from(Span::styled( @@ -84,9 +87,38 @@ pub fn render_canvas( f.render_widget(input_display, input_rows[i]); if is_active { + active_field_input_rect = Some(input_rows[i]); let cursor_x = input_rows[i].x + form_state.current_cursor_pos() as u16; let cursor_y = input_rows[i].y; f.set_cursor_position((cursor_x, cursor_y)); } } + + // --- Render Autocomplete Dropdown (if applicable) --- + if let Some(suggestions) = form_state.get_suggestions() { + if !suggestions.is_empty() { + if let Some(input_rect) = active_field_input_rect { + let selected_index = form_state.get_selected_suggestion_index(); + + // Calculate dropdown area below the active input field + let dropdown_height = (suggestions.len() as u16).min(5) + 2; // Max 5 suggestions + border + let dropdown_area = Rect { + x: input_rect.x, + y: input_rect.y + 1, // Position below the input line + width: input_rect.width.max(20), // Ensure minimum width + height: dropdown_height, + }; + + // Ensure dropdown doesn't go off screen (simple vertical check) + let screen_height = f.size().height; + let clamped_dropdown_area = if dropdown_area.bottom() > screen_height { + Rect::new(dropdown_area.x, dropdown_area.y.saturating_sub(dropdown_height + 1), dropdown_area.width, dropdown_area.height) + } else { + dropdown_area + }; + + autocomplete::render_autocomplete_dropdown(f, clamped_dropdown_area, theme, suggestions, selected_index); + } + } + } } diff --git a/client/src/state/canvas_state.rs b/client/src/state/canvas_state.rs index 0a86d5a..c3ec0f1 100644 --- a/client/src/state/canvas_state.rs +++ b/client/src/state/canvas_state.rs @@ -13,4 +13,8 @@ pub trait CanvasState { fn set_current_field(&mut self, index: usize); fn set_current_cursor_pos(&mut self, pos: usize); fn set_has_unsaved_changes(&mut self, changed: bool); + + // --- Autocomplete Support --- + fn get_suggestions(&self) -> Option<&[String]>; + fn get_selected_suggestion_index(&self) -> Option; } diff --git a/client/src/state/pages/auth.rs b/client/src/state/pages/auth.rs index 88ed2aa..396653f 100644 --- a/client/src/state/pages/auth.rs +++ b/client/src/state/pages/auth.rs @@ -93,7 +93,6 @@ impl RegisterState { } } - impl CanvasState for AuthState { fn current_field(&self) -> usize { self.current_field @@ -163,6 +162,15 @@ impl CanvasState for AuthState { // Allow the generic handler to signal changes self.has_unsaved_changes = changed; } + + // --- Autocomplete Support (Not Used for AuthState) --- + fn get_suggestions(&self) -> Option<&[String]> { + None // AuthState doesn't provide suggestions + } + + fn get_selected_suggestion_index(&self) -> Option { + None // AuthState doesn't have selected suggestions + } } impl CanvasState for RegisterState { @@ -258,4 +266,22 @@ impl CanvasState for RegisterState { fn set_has_unsaved_changes(&mut self, changed: bool) { self.has_unsaved_changes = changed; } + + fn get_suggestions(&self) -> Option<&[String]> { + // Only show suggestions for the role field (index 4) when requested + if self.current_field == 4 && self.show_role_suggestions { + Some(&self.role_suggestions) + } else { + None + } + } + + fn get_selected_suggestion_index(&self) -> Option { + // Only return index if suggestions are shown for the role field + if self.current_field == 4 && self.show_role_suggestions { + self.selected_suggestion_index + } else { + None + } + } } diff --git a/client/src/state/pages/form.rs b/client/src/state/pages/form.rs index 4d98500..776df45 100644 --- a/client/src/state/pages/form.rs +++ b/client/src/state/pages/form.rs @@ -133,4 +133,13 @@ impl CanvasState for FormState { fn set_has_unsaved_changes(&mut self, changed: bool) { self.has_unsaved_changes = changed; } + + // --- Autocomplete Support (Not Used for FormState) --- + fn get_suggestions(&self) -> Option<&[String]> { + None // FormState doesn't provide suggestions + } + + fn get_selected_suggestion_index(&self) -> Option { + None // FormState doesn't have selected suggestions + } }