// src/state/pages/form.rs use std::collections::HashMap; // NEW use crate::config::colors::themes::Theme; use ratatui::layout::Rect; use ratatui::Frame; use crate::state::app::highlight::HighlightState; use crate::state::pages::canvas_state::CanvasState; pub struct FormState { pub id: i64, // NEW fields for dynamic table context pub profile_name: String, pub table_name: String, pub total_count: u64, pub current_position: u64, // 1-based index, 0 or total_count + 1 for new entry pub fields: Vec, // Already dynamic, which is good pub values: Vec, pub current_field: usize, pub has_unsaved_changes: bool, pub current_cursor_pos: usize, } impl FormState { // MODIFIED constructor pub fn new( profile_name: String, table_name: String, fields: Vec, ) -> Self { let values = vec![String::new(); fields.len()]; FormState { id: 0, // Default to 0, indicating a new or unloaded record profile_name, table_name, total_count: 0, // Will be fetched after initialization current_position: 0, // Will be set after count is fetched (e.g., 1 or total_count + 1) fields, values, current_field: 0, has_unsaved_changes: false, current_cursor_pos: 0, } } pub fn render( &self, f: &mut Frame, area: Rect, theme: &Theme, is_edit_mode: bool, highlight_state: &HighlightState, // total_count and current_position are now part of self ) { let fields_str_slice: Vec<&str> = self.fields.iter().map(|s| s.as_str()).collect(); let values_str_slice: Vec<&String> = self.values.iter().collect(); crate::components::form::form::render_form( f, area, self, // Pass self as CanvasState &fields_str_slice, &self.current_field, &values_str_slice, theme, is_edit_mode, highlight_state, self.total_count, // MODIFIED: Use self.total_count self.current_position, // MODIFIED: Use self.current_position ); } // MODIFIED: Reset now also considers table context for counts pub fn reset_to_empty(&mut self) { self.id = 0; self.values.iter_mut().for_each(|v| v.clear()); self.current_field = 0; self.current_cursor_pos = 0; self.has_unsaved_changes = false; // current_position should be set to total_count + 1 for a new entry // This might be better handled by the logic that calls reset_to_empty // For now, let's ensure it's consistent with a "new" state. if self.total_count > 0 { self.current_position = self.total_count + 1; } else { self.current_position = 1; // If table is empty, new record is at position 1 } } pub fn get_current_input(&self) -> &str { self.values .get(self.current_field) .map(|s| s.as_str()) .unwrap_or("") } pub fn get_current_input_mut(&mut self) -> &mut String { self.values .get_mut(self.current_field) .expect("Invalid current_field index") } // MODIFIED: Update from a generic HashMap response pub fn update_from_response( &mut self, response_data: &HashMap, ) { self.values = self.fields .iter() .map(|field_name| { response_data.get(field_name).cloned().unwrap_or_default() }) .collect(); if let Some(id_str) = response_data.get("id") { match id_str.parse::() { Ok(parsed_id) => self.id = parsed_id, Err(e) => { tracing::error!( "Failed to parse 'id' field '{}' for table {}.{}: {}", id_str, self.profile_name, self.table_name, e ); self.id = 0; // Default to 0 if parsing fails } } } else { // If no ID is present, it might be a new record structure or an error // For now, assume it means the record doesn't have an ID from the server yet self.id = 0; } self.has_unsaved_changes = false; // current_field and current_cursor_pos might need resetting or adjusting // depending on the desired behavior after loading data. // For now, let's reset current_field to 0. self.current_field = 0; self.current_cursor_pos = 0; } } impl CanvasState for FormState { fn current_field(&self) -> usize { self.current_field } fn current_cursor_pos(&self) -> usize { self.current_cursor_pos } fn has_unsaved_changes(&self) -> bool { self.has_unsaved_changes } fn inputs(&self) -> Vec<&String> { self.values.iter().collect() } fn get_current_input(&self) -> &str { // Re-use the struct's own method FormState::get_current_input(self) } fn get_current_input_mut(&mut self) -> &mut String { // Re-use the struct's own method FormState::get_current_input_mut(self) } fn fields(&self) -> Vec<&str> { self.fields.iter().map(|s| s.as_str()).collect() } fn set_current_field(&mut self, index: usize) { if index < self.fields.len() { self.current_field = index; } } fn set_current_cursor_pos(&mut self, pos: usize) { self.current_cursor_pos = pos; } fn set_has_unsaved_changes(&mut self, changed: bool) { self.has_unsaved_changes = changed; } fn get_suggestions(&self) -> Option<&[String]> { None } fn get_selected_suggestion_index(&self) -> Option { None } }