summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/buy.rs23
-rw-r--r--src/components/form.rs120
-rw-r--r--src/components/input_placeholder.rs7
-rw-r--r--src/components/mod.rs11
-rw-r--r--src/components/select_placeholder.rs93
5 files changed, 120 insertions, 134 deletions
diff --git a/src/components/buy.rs b/src/components/buy.rs
index 0c294ee..6d9402e 100644
--- a/src/components/buy.rs
+++ b/src/components/buy.rs
@@ -1,7 +1,9 @@
 use leptos::{IntoView, component, view};
 use log::info;
+use rocie_client::models::UnitId;
+use uuid::Uuid;
 
-use crate::components::{form::Form, input_placeholder::InputPlaceholder, site_header::SiteHeader};
+use crate::components::{form::Form, site_header::SiteHeader};
 
 #[component]
 pub fn Buy() -> impl IntoView {
@@ -9,22 +11,27 @@ pub fn Buy() -> impl IntoView {
         <SiteHeader logo=icondata_io::IoPricetag back_location="/" name="Buy" />
 
         {Form! {
-            on_submit = |Inputs {product_barcode, amount}| {
-                info!("Got product barcode: {product_barcode} with amount: {amount}");
-            }
+            on_submit = |product_barcode, amount, unit_id| {
+                info!("Got product barcode: {product_barcode} with amount: {amount}, {unit_id}");
+            };
 
             <Input
                 name=product_barcode,
-                signal_name_get=product_barcode_get,
-                signal_name_set=product_barcode_set,
                 rust_type=u32,
                 html_type="number",
                 label="Product Barcode"
             />
+            <Select
+                name=unit_id,
+                rust_type=Uuid,
+                label="Unit",
+                options=[
+                    ("Kilogram", Uuid::new_v4()),
+                    ("Gram",  Uuid::new_v4())
+                ]
+            />
             <Input
                 name=amount,
-                signal_name_get=amount_get,
-                signal_name_set=amount_set,
                 rust_type=u16,
                 html_type="number",
                 label="Amount"
diff --git a/src/components/form.rs b/src/components/form.rs
index fd55897..9c371ad 100644
--- a/src/components/form.rs
+++ b/src/components/form.rs
@@ -1,119 +1 @@
-macro_rules! Form {
-    (
-        on_submit = |$bound:pat_param| $on_submit:block
-        $(
-            <Input
-                name=$name:ident,
-                signal_name_get=$signal_name_get:ident,
-                signal_name_set=$signal_name_set:ident,
-                rust_type=$rust_type:ty,
-                html_type=$input_type:literal,
-                label=$label:literal $(,)*
-            />
-        )*
-    ) => {{
-        use leptos::{
-            view,
-            prelude::{
-                Get,
-                NodeRef,
-                ElementChild,
-                ClassAttribute,
-                OnAttribute,
-                signal,
-                Set,
-                Show,
-            },
-            html::Input,
-            web_sys::SubmitEvent
-        };
-
-        use log::info;
-
-
-        $(
-            let ($signal_name_get, $signal_name_set) = signal(None);
-            let $name: NodeRef<Input> = NodeRef::new();
-        )*
-
-        let on_submit = move |ev: SubmitEvent| {
-            struct Inputs {
-                $(
-                    $name: $rust_type
-                ),*
-            }
-
-            // stop the page from reloading!
-            ev.prevent_default();
-
-            $(
-                let value = {
-                    let output = $name
-                        .get()
-                        // event handlers can only fire after the view
-                        // is mounted to the DOM, so the `NodeRef` will be `Some`
-                        .expect("<input> to exist")
-                        .value();
-
-                    let fin: Result<$rust_type, leptos::error::Error> = output
-                                .parse()
-                                .map_err(Into::<leptos::error::Error>::into);
-                    fin
-                };
-
-                let $name = match value {
-                    Ok(ok) => {
-                        // Reset the signal
-                        $signal_name_set.set(None);
-
-                        ok
-                    } ,
-                    Err(err) => {
-                        $signal_name_set.set(Some(err));
-
-                        // Skip running the real `on_submit`
-                        return
-                    }
-                };
-            )*
-
-            let real_on_submit = |$bound| $on_submit;
-            real_on_submit(Inputs {
-                $(
-                    $name
-                ),*
-            })
-        };
-
-
-        view! {
-            <form class="flex flex-col contents-start m-2 g-2" on:submit=on_submit>
-                $(
-                     <InputPlaceholder input_type=$input_type label=$label node_ref=$name />
-                     <Show
-                        when=move || $signal_name_get.get().is_some()
-                        fallback=|| ()
-                     >
-                         <p class="ps-2 text-red-300">{move ||
-                             format!(
-                                 "Input is invalid for type {}: {}",
-                                 stringify!($rust_type),
-                                 $signal_name_get.get().expect("Was `is_some`")
-                             )
-                         }</p>
-                     </Show>
-                )*
-
-                <div class="static">
-                    <input
-                        type="submit"
-                        value="Submit"
-                        class="absolute bottom-0 right-0 h-20 w-20 rounded-lg bg-green-300 m-2"
-                    />
-                </div>
-            </form>
-        }
-    }};
-}
-
-pub(crate) use Form;
+pub(crate) use rocie_macros::Form;
diff --git a/src/components/input_placeholder.rs b/src/components/input_placeholder.rs
index 05b9509..aeef838 100644
--- a/src/components/input_placeholder.rs
+++ b/src/components/input_placeholder.rs
@@ -1,5 +1,3 @@
-use std::sync::atomic::{AtomicU32, Ordering};
-
 use leptos::{
     IntoView, component,
     html::Input,
@@ -7,11 +5,8 @@ use leptos::{
     view,
 };
 
-fn get_id() -> u32 {
-    static ID: AtomicU32 = AtomicU32::new(0);
+use crate::components::get_id;
 
-    ID.fetch_add(1, Ordering::Relaxed)
-}
 
 #[component]
 pub fn InputPlaceholder(
diff --git a/src/components/mod.rs b/src/components/mod.rs
index f7b8dba..1ee37d5 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -1,9 +1,12 @@
+use std::sync::atomic::{AtomicU32, Ordering};
+
 // Generic
 pub mod async_fetch;
 pub mod container;
+pub mod form;
 pub mod icon_p;
 pub mod input_placeholder;
-pub mod form;
+pub mod select_placeholder;
 
 // Specific
 pub mod buy;
@@ -11,3 +14,9 @@ pub mod inventory;
 pub mod product_overview;
 pub mod recipies;
 pub mod site_header;
+
+fn get_id() -> u32 {
+    static ID: AtomicU32 = AtomicU32::new(0);
+
+    ID.fetch_add(1, Ordering::Relaxed)
+}
diff --git a/src/components/select_placeholder.rs b/src/components/select_placeholder.rs
new file mode 100644
index 0000000..947931c
--- /dev/null
+++ b/src/components/select_placeholder.rs
@@ -0,0 +1,93 @@
+use leptos::{
+    IntoView,
+    attr::{AttributeValue, IntoAttributeValue},
+    component,
+    html::Select,
+    prelude::{
+        ClassAttribute, CollectView, ElementChild, GlobalAttributes, NodeRef, NodeRefAttribute,
+    },
+    view,
+};
+
+use crate::components::get_id;
+
+#[component]
+pub fn SelectPlaceholder<T>(
+    label: &'static str,
+    node_ref: NodeRef<Select>,
+    options: Vec<(&'static str, T)>,
+) -> impl IntoView
+where
+    T: IntoAttributeValue,
+    <T as IntoAttributeValue>::Output: Send + AttributeValue,
+{
+    let id = get_id();
+
+    let options = options
+        .into_iter()
+        .map(|(label, value)| {
+            view! {
+                <option value=value>{label}</option>
+            }
+        })
+        .collect_view();
+
+    view! {
+        <div class="relative h-14">
+            <select
+                id=id.to_string()
+                class="\
+                absolute \
+                bottom-0 \
+                bg-gray-200 \
+                border-8 \
+                border-b-2 \
+                border-b-trasparent \
+                border-gray-200 \
+                focus:outline-none \
+                h-10 \
+                peer \
+                placeholder-transparent \
+                rounded-t-lg \
+                text-gray-900 \
+                w-full \
+                "
+                node_ref=node_ref
+            >
+                {options}
+            </select>
+
+            // TODO: Reference `var(--tw-border-2)` instead of the `2 px` <2025-10-01>
+            <div class="
+            absolute \
+            bottom-0 \
+            h-[2px] \
+            w-full \
+            bg-gray-300 \
+            peer-focus:bg-indigo-600 \
+            " />
+
+            <label
+                for=id.to_string()
+                class="\
+                bottom-10 \
+                absolute \
+                left-0 \
+                text-gray-700 \
+                text-sm \
+                transition-all \
+                peer-focus:bottom-10 \
+                peer-focus:left-0 \
+                peer-focus:text-gray-700 \
+                peer-focus:text-sm \
+                peer-placeholder-shown:text-base \
+                peer-placeholder-shown:text-gray-400 \
+                peer-placeholder-shown:bottom-2 \
+                peer-placeholder-shown:left-2 \
+                "
+            >
+                {label}
+            </label>
+        </div>
+    }
+}