1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
use std::fmt::{Display, Formatter};
use inquire::{
error::{CustomUserError, InquireResult},
required,
ui::RenderConfig,
CustomType, DateSelect, MultiSelect, Select, Text,
};
fn main() -> InquireResult<()> {
inquire::set_global_render_config(RenderConfig::empty());
let _date = DateSelect::new("Date:").prompt()?;
let _category = Select::new("Category:", get_categories()).prompt()?;
let _payee = Text::new("Payee:")
.with_validator(required!("This field is required"))
.with_autocomplete(&payee_suggestor)
.with_help_message("e.g. Music Store")
.with_page_size(5)
.prompt()?;
let amount: f64 = CustomType::new("Amount:")
.with_formatter(&|i: f64| format!("${i}"))
.with_error_message("Please type a valid number")
.with_help_message("Type the amount in US dollars using a decimal point as a separator")
.prompt()
.unwrap();
let _description = Text::new("Description:")
.with_help_message("Optional notes")
.prompt()?;
let mut accounts = get_accounts();
let accounts_mut = accounts.iter_mut().collect();
let account = Select::new("Account:", accounts_mut).prompt()?;
account.balance -= amount;
let _tags = MultiSelect::new("Tags:", get_tags()).prompt()?;
println!("Your transaction has been successfully recorded.");
println!("The balance of {account} is now $311.09");
Ok(())
}
/// This could be retrieved from a database, for example.
fn get_tags() -> Vec<&'static str> {
vec![
"august-surprise",
"birthday-gifts",
"cat-aurora",
"christmas-gifts-2020",
"dog-bob",
"dog-russ",
"new-zealand-jan-2020",
"roma-oct-2021",
]
}
struct Account {
name: &'static str,
balance: f64,
}
impl Account {
pub fn new(name: &'static str, balance: f64) -> Self {
Self { name, balance }
}
}
impl Display for Account {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "{}", self.name)
}
}
/// This could be retrieved from a database, for example.
fn get_accounts() -> Vec<Account> {
vec![
Account::new("401k", 1.00),
Account::new("Cash", 10.00),
Account::new("D40 Bank", 100.00),
Account::new("D40 Bank Credit Card", 1000.00),
Account::new("Digital Wallet", 100.00),
Account::new("Established Bank", 10.00),
Account::new("Investments Account", 1.00),
Account::new("Meal Voucher", 10.00),
Account::new("Mortgage", 100.00),
Account::new("Zeus Bank Credit Card", 354.08),
]
}
/// This could be retrieved from a database, for example.
fn get_categories() -> Vec<&'static str> {
vec![
"Rent",
"Energy",
"Water",
"Internet",
"Phone",
"Groceries",
"Eating Out",
"Transportation",
"Gifts",
"Clothes",
"Home Appliances",
]
}
/// This could be faster by using smarter ways to check for matches, when dealing with larger datasets.
fn payee_suggestor(input: &str) -> Result<Vec<String>, CustomUserError> {
let input = input.to_lowercase();
Ok(get_existing_payees()
.iter()
.filter(|p| p.to_lowercase().contains(&input))
.take(5)
.map(|p| String::from(*p))
.collect())
}
/// This could be retrieved from a database, for example.
fn get_existing_payees() -> &'static [&'static str] {
&[
"Armstrong-Jacobs",
"Barrows-Becker",
"Becker PLC",
"Bins, Fritsch and Hartmann",
"Feil PLC",
"Frami-Fisher",
"Goyette Group",
"Heathcote PLC",
"Hilpert-Kovacek",
"Keebler Inc",
"Kuhn-Rippin",
"McGlynn LLC",
"McKenzie, Kris and Yundt",
"Medhurst, Conroy and Will",
"Ruecker LLC",
"Steuber, Casper and Hermann",
"Torphy-Boyer",
"Volkman, Smith and Shanahan",
"VonRueden-Rath",
"Waelchi and Sons",
]
}
|