cdb_client/src/page/consume.rs
2025-06-07 21:27:12 +02:00

159 lines
5.4 KiB
Rust

use dioxus::prelude::*;
use crate::{
api,
page::{BasicButton, LabeledInput, TransientHeader},
};
#[component]
pub fn ConsumePage(id: String, item: String, variant: String) -> Element {
println!("{item} {variant}");
let (item, variant) = (use_signal(|| item.clone()), use_signal(|| variant.clone()));
let destinations = use_resource(move || async move {
api::API::get_unique_field(item(), variant(), "destination".to_string()).await
});
let dest = use_signal(|| String::new());
let mut price = use_signal(|| 0.00);
rsx! {
div {
class: "w-full py-4 flex flex-col gap-6",
TransientHeader { title: format!("Consume {item} - {variant}") }
LabeledInput {
label: "Destination",
PredefinedSelector {
name: "Destination",
value: dest,
custom: true,
predefined: destinations
}
}
// Price Field
LabeledInput {
label: "Price",
input {
class: "rounded-md border border-neutral-300 dark:border-neutral-700 bg-white dark:bg-neutral-800 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400",
r#type: "number",
value: "{price}",
oninput: move |e| {
price.set(e.value().parse().unwrap())
}
}
}
BasicButton {
title: "Consume",
onclick: move |_| {
let id2 = id.clone();
spawn(async move {
api::API::consume_item(id2, dest(), price()).await;
navigator().go_back();
});
},
}
}
}
}
#[component]
pub fn PredefinedSelector(
name: String,
value: Signal<String>,
custom: bool,
predefined: Resource<Vec<String>>,
) -> Element {
let mut screen_visible = use_signal(|| false);
let mut input_value = use_signal(|| value.read().clone());
rsx! {
div {
class: "p-2",
button {
class: "\
cursor-pointer rounded-lg border border-neutral-300 dark:border-neutral-700 \
px-3 py-1 text-md font-medium text-neutral-700 dark:text-neutral-300 \
hover:bg-neutral-100 dark:hover:bg-neutral-800 transition-colors duration-200",
onclick: move |_| screen_visible.set(true),
"{name}: {value}"
}
}
if *screen_visible.read() {
div {
class: "\
fixed inset-0 z-40 flex flex-col bg-black bg-opacity-80 p-6 space-y-6 text-white \
backdrop-blur-sm",
h2 {
class: "text-2xl font-semibold",
"Select a value for {name}"
}
if custom {
input {
class: "\
rounded-md border border-neutral-600 bg-neutral-900 px-4 py-2 text-lg \
text-white focus:outline-none focus:ring-2 focus:ring-blue-500 transition",
r#type: "text",
value: "{input_value}",
oninput: move |evt| input_value.set(evt.value().clone()),
}
}
div {
class: "flex flex-wrap gap-3",
match &*predefined.read() {
Some(list) => rsx! {
{list.iter().map(|item| rsx! {
button {
class: "\
rounded-md bg-neutral-700 px-4 py-2 text-sm hover:bg-neutral-600 \
transition-colors cursor-pointer select-none",
onclick: {
let item = item.clone();
move |_| {
value.set(item.clone());
input_value.set(item.clone());
screen_visible.set(false);
}
},
"{item}"
}
})}
},
None => rsx!(p { "Loading..." }),
}
}
div {
class: "mt-auto flex gap-4",
button {
class: "\
flex-1 bg-blue-600 hover:bg-blue-700 rounded-md px-5 py-2 text-white font-semibold \
transition-colors cursor-pointer",
onclick: move |_| {
value.set(input_value.read().clone());
screen_visible.set(false);
},
"Confirm"
}
button {
class: "\
flex-1 text-center underline text-neutral-400 hover:text-neutral-200 \
transition-colors cursor-pointer",
onclick: move |_| screen_visible.set(false),
"Cancel"
}
}
}
}
}
}