feat: implement working MultiEntry component
This MultiEntry (Rewrite) is capable of storing and sending values through the server functions, as well as dynamically updating the master list as values are changed.
This commit is contained in:
1 parent
6b1e2174b6
commit
86bd471c1e
9 files changed
+369
-32
No files matched your search
+114
-12
@@ -1,18 +1,120 @@
|
||||
use std::collections::HashMap;
|
||||
use leptos::{view, IntoView};
|
||||
use leptos::either::EitherOf5;
|
||||
use leptos::prelude::RwSignal;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::components::{CheckboxList, OutlinedTextField, RadioList, Row, Select, ValueType};
|
||||
|
||||
/// Defines a series of options that allow a user to define a form.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub enum InputType{
|
||||
/// Represents a text input. Requires a `String` key. The entered value will be returned as a
|
||||
/// single `String` value.
|
||||
Text,
|
||||
/// Represents a number input. Requires a `String` key. The entered value will be returned as a
|
||||
/// single `i32` value.
|
||||
Number,
|
||||
/// Represents a radio input. Requires a `String` key and a series of options. The selected
|
||||
/// value will be returned as a single `String` value.
|
||||
Radio(Vec<String>),
|
||||
/// Represents a checkbox input. Requires a `String` key and a series of options. The selected
|
||||
/// value will be returned as a `Vec<String>`.
|
||||
Checkbox(Vec<String>)
|
||||
/// Represents a text input. Requires a `String` key, `String` label, and `String` placeholder.
|
||||
/// The entered value will be returned as a single `String` value.
|
||||
Text(String, String, String),
|
||||
/// Represents a number input. Requires a `String` key, `String` label, and a `String` placeholder.
|
||||
/// The entered value will be returned as a `String`, and will be parseable into any number type
|
||||
/// (i.e. an `i32`, `i64`, etc)
|
||||
Number(String, String, String),
|
||||
/// Represents a radio input. Requires a `String` key, `String` label, and a series of `String`
|
||||
/// options. The selected value will be returned as a `String`.
|
||||
Radio(String, String, Vec<String>),
|
||||
/// Represents a checkbox input. Requires a `String` key, `String` label, and a series of `String`
|
||||
/// options. The selected values will be returned as a `Vec<String>`.
|
||||
Checkbox(String, String, Vec<String>),
|
||||
/// Represents a dropdown input. Requires a `String` key, `String` label, and a series
|
||||
/// of `String` options. The selected value will be returned as a `String`.
|
||||
Select(String, String, Vec<String>)
|
||||
}
|
||||
|
||||
impl InputType {
|
||||
pub fn into_view(self, data_map: RwSignal<HashMap<String, ValueType>>) -> impl IntoView {
|
||||
view! {
|
||||
{match self {
|
||||
InputType::Text(member, label, placeholder) =>
|
||||
EitherOf5::A(view! {
|
||||
<Row>
|
||||
<OutlinedTextField
|
||||
label = label.clone()
|
||||
placeholder = placeholder.clone()
|
||||
data_member = member.clone()
|
||||
data_map = data_map
|
||||
/>
|
||||
</Row>
|
||||
}),
|
||||
InputType::Number(member, label, placeholder) =>
|
||||
EitherOf5::B(view! {
|
||||
<OutlinedTextField
|
||||
label = label.clone()
|
||||
placeholder = placeholder.clone()
|
||||
data_member = member.clone()
|
||||
data_map = data_map
|
||||
/>
|
||||
}),
|
||||
InputType::Checkbox(member, label, options) =>
|
||||
EitherOf5::C(view! {
|
||||
<CheckboxList
|
||||
label = label.clone()
|
||||
items = options.clone()
|
||||
data_member = member.clone()
|
||||
data_map = data_map
|
||||
/>
|
||||
}),
|
||||
InputType::Radio(member, label, options) =>
|
||||
EitherOf5::D(view! {
|
||||
<RadioList
|
||||
label = label.clone()
|
||||
data_member = member.clone()
|
||||
data_map = data_map
|
||||
items = options.clone()
|
||||
/>
|
||||
}),
|
||||
InputType::Select(member, label, options) =>
|
||||
EitherOf5::E(view! {
|
||||
<Select
|
||||
label = label.clone()
|
||||
value_list = options.clone()
|
||||
data_member = member.clone()
|
||||
data_map = data_map
|
||||
/>
|
||||
})
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_view_rows(self, data_map: RwSignal<HashMap<String, ValueType>>) -> impl IntoView {
|
||||
view! {
|
||||
<Row>
|
||||
{self.into_view(data_map)}
|
||||
</Row>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Shorthand macro for creating `InputType` enums.
|
||||
///
|
||||
/// Example usage:
|
||||
/// ```
|
||||
/// // To create an InputType::Text
|
||||
/// let text_input = input!(Text, "member", "label", "placeholder");
|
||||
///
|
||||
/// // To create an InputType::Select
|
||||
/// let select_input = input!(Select, "member", "label", ["option1", "option2"]);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! input {
|
||||
($variant:ident, $key:expr, $label:expr, [$($option:expr),* $(,)?]) => {
|
||||
$crate::common::InputType::$variant(
|
||||
$key.to_string(),
|
||||
$label.to_string(),
|
||||
vec![$($option.to_string()), *]
|
||||
)
|
||||
};
|
||||
|
||||
($variant:ident, $key:expr, $label:expr, $placeholder:expr) => {
|
||||
$crate::common::InputType::$variant(
|
||||
$key.to_string(),
|
||||
$label.to_string(),
|
||||
$placeholder.to_string()
|
||||
)
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
use std::collections::HashMap;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::fmt::Display;
|
||||
|
||||
/// Defines a set of possible input types. They allow for the type and value of every data member
|
||||
/// to be stored within a single `HashMap` or `Vec`. This means that even though all the data is
|
||||
/// created as a single type, the values are still able to be type safe.
|
||||
///
|
||||
/// A note: other structs cannot be stored in this enum, however it was designed to work with
|
||||
/// a `HashMap` of more `ValueType` enums. There are numerous ways to convert a struct into a
|
||||
/// `HashMap`, specifically storing all the struct's fields as `String` keys in the map.
|
||||
#[derive(PartialEq, Clone, Serialize, Deserialize, Debug)]
|
||||
pub enum ValueType {
|
||||
/// Indicates a `String` value.
|
||||
@@ -12,10 +17,12 @@ pub enum ValueType {
|
||||
Number(Option<String>),
|
||||
/// Indicates a `Vec<T>`, where `T` can be any other `ValueType`.
|
||||
List(Option<Vec<ValueType>>),
|
||||
/// Indicates a `HashMap<String, ValueType>`.
|
||||
Map(Option<HashMap<String, ValueType>>),
|
||||
}
|
||||
|
||||
impl ValueType {
|
||||
/// Returns true if this is a `String`.
|
||||
/// Returns true if this is a `String`, otherwise false.
|
||||
pub fn is_string(&self) -> bool {
|
||||
if let ValueType::String(_) = self { true } else { false }
|
||||
}
|
||||
@@ -29,7 +36,7 @@ impl ValueType {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this is a `Number`.
|
||||
/// Returns true if this is a `Number`, otherwise false.
|
||||
pub fn is_number(&self) -> bool {
|
||||
if let ValueType::Number(_) = self { true } else { false }
|
||||
}
|
||||
@@ -43,7 +50,7 @@ impl ValueType {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this is a `List`.
|
||||
/// Returns true if this is a `List`, otherwise false.
|
||||
pub fn is_list(&self) -> bool {
|
||||
if let ValueType::List(_) = self { true } else { false }
|
||||
}
|
||||
@@ -57,6 +64,20 @@ impl ValueType {
|
||||
Err(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this is a `Map`, otherwise false.
|
||||
pub fn is_map(&self) -> bool {
|
||||
if let ValueType::Map(_) = self { true } else { false }
|
||||
}
|
||||
|
||||
/// Attempts to get this value as a `HashMap<String, ValueType>`.
|
||||
pub fn as_map(&self) -> Result<Option<HashMap<String, ValueType>>, Self> {
|
||||
if let ValueType::Map(v) = self {
|
||||
Ok(v.clone())
|
||||
} else {
|
||||
Err(self.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ValueType {
|
||||
@@ -71,6 +92,7 @@ impl Display for ValueType {
|
||||
ValueType::String(s) => s.clone().unwrap_or("".to_owned()),
|
||||
ValueType::Number(n) => n.clone().unwrap_or("".to_owned()),
|
||||
ValueType::List(l) => format!("{l:?}"),
|
||||
ValueType::Map(m) => format!("{m:?}"),
|
||||
};
|
||||
write!(f, "{}", str)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user