use ratatui::{
layout::{Constraint, Direction, Layout},
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, Clear, Paragraph},
Frame,
};
use crate::tui::app::App;
use crate::tui::layout::centered_rect_fixed;
#[derive(Debug, Clone, Default)]
pub struct ReconcileStartState {
pub date_input: String,
pub balance_input: String,
pub active_field: usize,
}
impl ReconcileStartState {
pub fn new() -> Self {
Self {
date_input: chrono::Local::now().format("%Y-%m-%d").to_string(),
balance_input: String::new(),
active_field: 0,
}
}
}
pub fn render(frame: &mut Frame, app: &App) {
let area = centered_rect_fixed(50, 12, frame.area());
frame.render_widget(Clear, area);
let block = Block::default()
.title(" Start Reconciliation ")
.title_style(
Style::default()
.fg(Color::Cyan)
.add_modifier(Modifier::BOLD),
)
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::Cyan));
let inner = block.inner(area);
frame.render_widget(block, area);
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(1), Constraint::Length(2), Constraint::Length(1), Constraint::Length(2), Constraint::Length(1), Constraint::Length(2), ])
.split(inner);
let state = &app.reconcile_start_state;
let date_style = if state.active_field == 0 {
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD)
} else {
Style::default().fg(Color::White)
};
let date_label = if state.active_field == 0 {
Span::styled("Statement Date: ", Style::default().fg(Color::Yellow))
} else {
Span::styled("Statement Date: ", Style::default().fg(Color::White))
};
let date_text = Paragraph::new(vec![
Line::from(date_label),
Line::from(Span::styled(&state.date_input, date_style)),
]);
frame.render_widget(date_text, chunks[1]);
let balance_style = if state.active_field == 1 {
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD)
} else {
Style::default().fg(Color::White)
};
let balance_label = if state.active_field == 1 {
Span::styled("Statement Balance: ", Style::default().fg(Color::Yellow))
} else {
Span::styled("Statement Balance: ", Style::default().fg(Color::White))
};
let balance_display = if state.balance_input.is_empty() {
"Enter balance...".to_string()
} else {
state.balance_input.clone()
};
let balance_text = Paragraph::new(vec![
Line::from(balance_label),
Line::from(Span::styled(balance_display, balance_style)),
]);
frame.render_widget(balance_text, chunks[3]);
let instructions = Paragraph::new(Line::from(vec![
Span::styled("[Tab]", Style::default().fg(Color::Green)),
Span::raw(" Switch field "),
Span::styled("[Enter]", Style::default().fg(Color::Green)),
Span::raw(" Start "),
Span::styled("[Esc]", Style::default().fg(Color::White)),
Span::raw(" Cancel"),
]));
frame.render_widget(instructions, chunks[5]);
}
pub fn handle_key(app: &mut App, key: crossterm::event::KeyCode) -> bool {
use crossterm::event::KeyCode;
let state = &mut app.reconcile_start_state;
match key {
KeyCode::Tab => {
state.active_field = (state.active_field + 1) % 2;
true
}
KeyCode::Up | KeyCode::Char('k') => {
if state.active_field > 0 {
state.active_field -= 1;
}
true
}
KeyCode::Down | KeyCode::Char('j') => {
if state.active_field < 1 {
state.active_field += 1;
}
true
}
KeyCode::Char(c) => {
if state.active_field == 0 {
state.date_input.push(c);
} else {
state.balance_input.push(c);
}
true
}
KeyCode::Backspace => {
if state.active_field == 0 {
state.date_input.pop();
} else {
state.balance_input.pop();
}
true
}
_ => false,
}
}