vesys-bank-server/http-client/src/components/account.rs

152 lines
5.6 KiB
Rust

use std::str::FromStr;
use web_sys::{HtmlInputElement, HtmlSelectElement};
use yew::{classes, html, Component, Context, Html, Properties, NodeRef};
use yew_agent::{Dispatched, Dispatcher};
use crate::event_bus::{EventBus, Request};
use crate::events::Event;
pub enum Msg {
AmountChanged,
Deposit,
Withdraw,
Transfer,
}
#[derive(Properties, PartialEq)]
pub struct AccountProps {
pub account_nrs: Vec<String>,
pub balance: f64,
pub nr: String,
pub owner: String,
}
pub struct Account {
amount_ref: NodeRef,
transfer_account_ref: NodeRef,
amount_valid: bool,
event_bus: Dispatcher<EventBus>,
}
impl Account {
fn amount(&self) -> f64 {
if let Some(amount_el) = self.amount_ref.cast::<HtmlInputElement>() {
f64::from_str(&amount_el.value()).unwrap_or_default()
} else { 0_f64 }
}
fn is_amount_valid(&self) -> bool {
self.amount() > 0_f64
}
fn selected_transfer_account(&self) -> Option<String> {
if let Some(transfer_account_el) = self.transfer_account_ref.cast::<HtmlSelectElement>() {
let value: String = transfer_account_el.value();
if value.is_empty() || value == "undefined" { None } else { Some(value) }
} else { None }
}
}
impl Component for Account {
type Message = Msg;
type Properties = AccountProps;
fn create(_: &Context<Self>) -> Self {
Self {
amount_ref: NodeRef::default(),
transfer_account_ref: NodeRef::default(),
amount_valid: false,
event_bus: EventBus::dispatcher(),
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::AmountChanged => {
let is_amount_valid = self.is_amount_valid();
let needs_redraw = is_amount_valid != self.amount_valid;
self.amount_valid = is_amount_valid;
needs_redraw
}
Msg::Deposit => {
let amount = self.amount() + ctx.props().balance;
self.event_bus.send(Request::EventBusMsg(Event::SetBalance(amount, ctx.props().nr.clone())));
false
}
Msg::Withdraw => {
let amount = ctx.props().balance - self.amount();
if amount > 0_f64 {
self.event_bus.send(Request::EventBusMsg(Event::SetBalance(amount, ctx.props().nr.clone())));
} else {
self.event_bus.send(Request::EventBusMsg(Event::ShowError("Balance can not be overdrawn".into())));
}
false
}
Msg::Transfer => {
let amount = ctx.props().balance - self.amount();
if amount > 0_f64 {
self.event_bus.send(Request::EventBusMsg(Event::SetBalance(amount, ctx.props().nr.clone())));
} else {
let transfer_nr = self.selected_transfer_account();
if let Some(transfer_nr) = transfer_nr {
self.event_bus.send(Request::EventBusMsg(Event::Transfer(amount, ctx.props().nr.clone(), transfer_nr)));
}
}
false
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let onchange = ctx
.link()
.callback(|_| Msg::AmountChanged);
let on_deposit = ctx
.link()
.callback(|_| Msg::Deposit);
let on_withdraw = ctx
.link()
.callback(|_| Msg::Withdraw);
let on_transfer = ctx
.link()
.callback(|_| Msg::Transfer);
html! {
<>
<section class={classes!("account")}>
<fieldset class={classes!("account__grid")}>
<legend class={classes!("account__title")}>
{&ctx.props().owner} {""} {&ctx.props().balance}
</legend>
<div class={classes!("account__amount")}>
<label class={classes!("account__label")} for="amount">{"Amount"}</label>
<input {onchange} ref={self.amount_ref.clone()} class={classes!("account__input")} id="amount" type="number" step="0.01" min="0" placeholder="0.0" />
</div>
<div class={classes!("account__accounts")}>
<label class={classes!("account__label")} for="accounts">{"Remote Account"}</label>
<select ref={self.transfer_account_ref.clone()} class={classes!("account__input")} name="accounts" id="account-select">
{ for ctx.props().account_nrs.iter().filter(|e| {
ctx.props().nr != e.to_string()
}).map(|e| html!{ <option value={e.to_string()}>{e}</option> }) }
</select>
</div>
<button onclick={on_deposit} class={classes!("account__button")} disabled={!self.amount_valid}>{"deposit"}</button>
<button onclick={on_withdraw} class={classes!("account__button")} disabled={!self.amount_valid}>{"withdraw"}</button>
<button onclick={on_transfer} class={classes!("account__button")} disabled={!self.amount_valid}>{"transfer"}</button>
</fieldset>
</section>
</>
}
}
}