travail sur add transaction

This commit is contained in:
thatscringebro
2026-03-11 16:05:56 -04:00
parent e58387a1bf
commit 461468ff1b
6 changed files with 192 additions and 7 deletions

View File

@@ -1,3 +1,4 @@
use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
use sqlite::Connection; use sqlite::Connection;
use crate::{data_layer, entities::*, enums::*}; use crate::{data_layer, entities::*, enums::*};
@@ -9,6 +10,8 @@ pub struct App {
pub trx_table: TrxTable, pub trx_table: TrxTable,
pub new_account: Account, pub new_account: Account,
pub new_transaction: Transaction, pub new_transaction: Transaction,
pub selected_transaction_input: TransactionInput,
pub current_input: String,
pub connection: Connection, pub connection: Connection,
} }
@@ -31,6 +34,8 @@ impl App {
trx_table: TrxTable::new(), trx_table: TrxTable::new(),
new_account: Account::new(0, String::new(), AccountType::Cash), new_account: Account::new(0, String::new(), AccountType::Cash),
new_transaction: Transaction::new_empty(), new_transaction: Transaction::new_empty(),
selected_transaction_input: TransactionInput::Type,
current_input: String::new(),
connection: con, connection: con,
}; };
} }
@@ -71,4 +76,89 @@ impl App {
self.trx_table.add_tr(tr); self.trx_table.add_tr(tr);
self.new_transaction = Transaction::new_empty(); self.new_transaction = Transaction::new_empty();
} }
pub fn next_tr_input(&mut self) {
match self.selected_transaction_input {
TransactionInput::Type => {
self.selected_transaction_input = TransactionInput::Amount;
self.new_transaction.set_type(
self.current_input
.parse::<i64>()
.expect("Failed to parse data"),
&self.connection,
);
}
TransactionInput::Amount => {
self.selected_transaction_input = TransactionInput::Date;
self.new_transaction.set_amount(
self.current_input
.parse::<f64>()
.expect("Failed to parse data"),
);
}
TransactionInput::Date => {
self.selected_transaction_input = TransactionInput::Description;
let date = NaiveDate::parse_from_str(&self.current_input, "%Y-%m-%d")
.expect("Faile to parse data");
let time = NaiveTime::from_hms_opt(5, 0, 0).unwrap(); // to account for my local datetime
self.new_transaction
.set_date(Local.from_utc_datetime(&NaiveDateTime::new(date, time)));
}
TransactionInput::Description => {
self.new_transaction.set_desc(self.current_input.clone())
}
}
self.set_current_input();
}
pub fn previous_tr_input(&mut self) {
match self.selected_transaction_input {
TransactionInput::Type => {
self.new_transaction.set_type(
self.current_input
.parse::<i64>()
.expect("Failed to parse data"),
&self.connection,
);
}
TransactionInput::Amount => {
self.selected_transaction_input = TransactionInput::Type;
self.new_transaction.set_amount(
self.current_input
.parse::<f64>()
.expect("Failed to parse data"),
);
}
TransactionInput::Date => {
self.selected_transaction_input = TransactionInput::Amount;
let date = NaiveDate::parse_from_str(&self.current_input, "%Y-%m-%d")
.expect("Faile to parse data");
let time = NaiveTime::from_hms_opt(5, 0, 0).unwrap(); // to account for my local datetime
self.new_transaction
.set_date(Local.from_utc_datetime(&NaiveDateTime::new(date, time)));
}
TransactionInput::Description => {
self.selected_transaction_input = TransactionInput::Date;
self.new_transaction.set_desc(self.current_input.clone());
}
}
self.set_current_input();
}
fn set_current_input(&mut self) {
match self.selected_transaction_input {
TransactionInput::Type => {
self.current_input = self.new_transaction.get_type().get_id().to_string()
}
TransactionInput::Amount => {
self.current_input = self.new_transaction.get_amount().to_string()
}
TransactionInput::Date => {
self.current_input = self
.new_transaction
.get_date()
.format("%Y-%m-%d")
.to_string()
}
TransactionInput::Description => self.current_input = self.new_transaction.get_desc(),
}
}
} }

View File

@@ -187,7 +187,7 @@ pub fn upsert_transaction(con: &Connection, tr: Transaction) -> Transaction {
} }
let mut statement = con.prepare(query).unwrap(); let mut statement = con.prepare(query).unwrap();
statement.bind((1, tr.get_account().get_id())).unwrap(); statement.bind((1, tr.get_account_id())).unwrap();
statement.bind((2, tr.get_type().get_id())).unwrap(); statement.bind((2, tr.get_type().get_id())).unwrap();
statement.bind((3, tr.get_amount())).unwrap(); statement.bind((3, tr.get_amount())).unwrap();
statement.bind((4, tr.get_date().timestamp())).unwrap(); statement.bind((4, tr.get_date().timestamp())).unwrap();
@@ -206,7 +206,7 @@ pub fn upsert_transaction(con: &Connection, tr: Transaction) -> Transaction {
return Transaction::new( return Transaction::new(
id, id,
tr.get_account().get_id(), tr.get_account_id(),
tr.get_amount(), tr.get_amount(),
tr.get_date_utc(), tr.get_date_utc(),
tr.get_desc(), tr.get_desc(),

View File

@@ -11,7 +11,6 @@ pub struct Transaction {
description: String, description: String,
type_id: i64, type_id: i64,
account: Account,
tr_type: TransactionType, tr_type: TransactionType,
} }
@@ -32,7 +31,6 @@ impl Transaction {
date: date, date: date,
description: desc, description: desc,
type_id: type_id, type_id: type_id,
account: data_layer::get_account(con, ac_id),
tr_type: data_layer::get_transaction_type(con, type_id), tr_type: data_layer::get_transaction_type(con, type_id),
} }
} }
@@ -45,7 +43,6 @@ impl Transaction {
date: DateTime::from_timestamp(0, 0).unwrap(), date: DateTime::from_timestamp(0, 0).unwrap(),
description: "".to_string(), description: "".to_string(),
type_id: 0, type_id: 0,
account: Account::new(0, "".to_string(), super::AccountType::Cash),
tr_type: TransactionType::new(0, "".to_string()), tr_type: TransactionType::new(0, "".to_string()),
} }
} }
@@ -57,6 +54,9 @@ impl Transaction {
pub fn get_amount(&self) -> f64 { pub fn get_amount(&self) -> f64 {
return self.amount; return self.amount;
} }
pub fn set_amount(&mut self, amnt: f64) {
self.amount = amnt;
}
pub fn get_date(&self) -> DateTime<Local> { pub fn get_date(&self) -> DateTime<Local> {
return Local.from_utc_datetime(&self.date.naive_local()); return Local.from_utc_datetime(&self.date.naive_local());
@@ -64,18 +64,31 @@ impl Transaction {
pub fn get_date_utc(&self) -> DateTime<Utc> { pub fn get_date_utc(&self) -> DateTime<Utc> {
return self.date; return self.date;
} }
pub fn set_date(&mut self, date: DateTime<Local>) {
self.date = date.to_utc();
}
pub fn get_desc(&self) -> String { pub fn get_desc(&self) -> String {
return self.description.clone(); return self.description.clone();
} }
pub fn set_desc(&mut self, desc: String) {
self.description = desc;
}
pub fn get_account(&self) -> Account { pub fn get_account_id(&self) -> i64 {
return self.account.clone(); return self.account_id;
}
pub fn set_account_id(&mut self, ac_id: i64) {
self.account_id = ac_id;
} }
pub fn get_type(&self) -> TransactionType { pub fn get_type(&self) -> TransactionType {
return self.tr_type.clone(); return self.tr_type.clone();
} }
pub fn set_type(&mut self, tr_id: i64, con: &Connection) {
self.type_id = tr_id;
self.tr_type = data_layer::get_transaction_type(con, tr_id);
}
} }
#[derive(Clone)] #[derive(Clone)]

View File

@@ -8,3 +8,11 @@ pub enum CurrentScreen {
NewAccount, NewAccount,
NewTransaction, NewTransaction,
} }
#[derive(PartialEq)]
pub enum TransactionInput {
Type,
Amount,
Date,
Description,
}

View File

@@ -4,6 +4,7 @@ mod entities;
mod enums; mod enums;
mod ui; mod ui;
use crate::{app::App, enums::*, ui::ui}; use crate::{app::App, enums::*, ui::ui};
use chrono::Local;
use entities::{Account, AccountType, Transaction}; use entities::{Account, AccountType, Transaction};
use ratatui::{ use ratatui::{
Terminal, Terminal,
@@ -87,6 +88,9 @@ where
} }
CurrentWidget::TrxList => { CurrentWidget::TrxList => {
app.current_screen = CurrentScreen::NewTransaction; app.current_screen = CurrentScreen::NewTransaction;
app.new_transaction
.set_account_id(app.acc_list.get_selected_id());
app.new_transaction.set_date(Local::now());
} }
_ => {} _ => {}
}, },
@@ -104,10 +108,22 @@ where
_ => {} _ => {}
}, },
CurrentScreen::NewTransaction => match key.code { CurrentScreen::NewTransaction => match key.code {
KeyCode::Down => {
app.next_tr_input();
}
KeyCode::Up => {
app.previous_tr_input();
}
KeyCode::Enter => { KeyCode::Enter => {
app.save_new_tr(); app.save_new_tr();
app.current_screen = CurrentScreen::Main; app.current_screen = CurrentScreen::Main;
} }
KeyCode::Backspace => {
app.current_input.pop();
}
KeyCode::Char(value) => {
app.current_input.push(value);
}
KeyCode::Esc => { KeyCode::Esc => {
app.current_screen = CurrentScreen::Main; app.current_screen = CurrentScreen::Main;
app.new_transaction = Transaction::new_empty(); app.new_transaction = Transaction::new_empty();

View File

@@ -3,6 +3,7 @@ use crate::{
entities::{Account, Transaction}, entities::{Account, Transaction},
enums::*, enums::*,
}; };
use chrono::{Date, Local};
use ratatui::{ use ratatui::{
Frame, Frame,
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
@@ -120,6 +121,41 @@ pub fn ui(frame: &mut Frame, app: &mut App) {
let area = centered_rect(50, 40, frame.area()); let area = centered_rect(50, 40, frame.area());
frame.render_widget(popup, area); frame.render_widget(popup, area);
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(1)
.constraints([
Constraint::Length(3),
Constraint::Length(3),
Constraint::Length(3),
Constraint::Length(3),
])
.split(area);
let tr_type = Paragraph::new(tr_input_str(TransactionInput::Type, app))
.style(tr_input_style(TransactionInput::Type, app))
.block(Block::default().borders(Borders::BOTTOM).title("Type"));
frame.render_widget(tr_type, chunks[0]);
let amnt = Paragraph::new(tr_input_str(TransactionInput::Amount, app))
.style(tr_input_style(TransactionInput::Amount, app))
.block(Block::default().borders(Borders::BOTTOM).title("Amount"));
frame.render_widget(amnt, chunks[1]);
let date = Paragraph::new(tr_input_str(TransactionInput::Date, app))
.style(tr_input_style(TransactionInput::Date, app))
.block(Block::default().borders(Borders::BOTTOM).title("Date"));
frame.render_widget(date, chunks[2]);
let desc = Paragraph::new(tr_input_str(TransactionInput::Description, app))
.style(tr_input_style(TransactionInput::Description, app))
.block(
Block::default()
.borders(Borders::BOTTOM)
.title("Description"),
);
frame.render_widget(desc, chunks[3]);
} }
if let CurrentScreen::Exiting = app.current_screen { if let CurrentScreen::Exiting = app.current_screen {
@@ -162,6 +198,28 @@ fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
.split(popup_layout[1])[1]; .split(popup_layout[1])[1];
} }
fn tr_input_style(input: TransactionInput, app: &mut App) -> Style {
if app.selected_transaction_input == input {
return SELECTED_STYLE;
}
return Style::default();
}
fn tr_input_str(input: TransactionInput, app: &mut App) -> String {
if app.selected_transaction_input == input {
return app.current_input.clone();
}
match input {
TransactionInput::Type => app.new_transaction.get_type().get_id().to_string(),
TransactionInput::Amount => app.new_transaction.get_amount().to_string(),
TransactionInput::Date => app
.new_transaction
.get_date()
.format("%Y-%m-%d")
.to_string(),
TransactionInput::Description => app.new_transaction.get_desc(),
}
}
impl From<&Account> for ListItem<'_> { impl From<&Account> for ListItem<'_> {
fn from(value: &Account) -> Self { fn from(value: &Account) -> Self {
let line = Line::styled( let line = Line::styled(