From 39996319ba38b447fe85d25ca3e81d0b46276b73 Mon Sep 17 00:00:00 2001 From: Lucas Vas Date: Fri, 19 Sep 2025 12:30:27 -0400 Subject: [PATCH] feat: alter OutlinedTextField to use ValueType enum Also implemented extra error checking when the values are passed as the incorrect type. For example, the only accepted types are strings and numbers, so that will be checked and handled accordingly. --- src/common/student_info.rs | 27 ++++++----- src/components/multi_entry/multi_entry.rs | 4 +- src/components/multi_entry/value_type.rs | 6 +++ src/components/text_field.rs | 55 ++++++++++++++--------- src/pages/home_page.rs | 52 +++++++++++---------- src/pages/provider_entry.rs | 4 +- 6 files changed, 89 insertions(+), 59 deletions(-) diff --git a/src/common/student_info.rs b/src/common/student_info.rs index 1533782..ca617a4 100644 --- a/src/common/student_info.rs +++ b/src/common/student_info.rs @@ -1,11 +1,12 @@ -use crate::components::MultiEntryData; +use crate::components::{MultiEntryData, ValueType}; use macros::Reactive; use serde::{Deserialize, Serialize}; use std::default::Default; use chrono::{DateTime, Utc}; +use reactive_stores::Store; /// Represents information about a student. -#[derive(Serialize, Deserialize, Debug, Clone, Reactive, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, Store, Reactive)] pub struct StudentInfo { /// The email address of the student. This was used in the previous version of the database, /// and should now be deprecated. @@ -14,32 +15,36 @@ pub struct StudentInfo { pub Email: String, /// The student's first name. #[serde(default)] - pub first_name: String, + pub first_name: ValueType, // String /// The student's last name. #[serde(default)] - pub last_name: String, + pub last_name: ValueType, // String /// The student's highest math score on the SAT. - #[serde(default)] - pub math_sat: i32, + #[serde(default = "default_number")] + pub math_sat: ValueType, // Number /// The student's desired contact email. #[serde(default)] - pub contact_email: String, + pub contact_email: ValueType, // String /// The student's address. #[serde(default)] - pub address: String, + pub address: ValueType, // String /// The student's town of residence. #[serde(default)] - pub town: String, + pub town: ValueType, // String /// The student's entered phone number. #[serde(default)] - pub phone_number: String, // May be stored as a straight number in the future. + pub phone_number: ValueType, // May be stored as a straight number in the future, but String /// The student's birthdate. #[serde(default)] pub birth_date: DateTime, /// The student's gender. #[serde(default)] - pub gender: String, + pub gender: ValueType, // String /// The student's athletic information. #[serde(default)] pub athletic_info: Vec, } + +fn default_number() -> ValueType { + ValueType::Number(0) +} \ No newline at end of file diff --git a/src/components/multi_entry/multi_entry.rs b/src/components/multi_entry/multi_entry.rs index 536f3c9..1e85385 100644 --- a/src/components/multi_entry/multi_entry.rs +++ b/src/components/multi_entry/multi_entry.rs @@ -9,7 +9,7 @@ use super::{multi_entry_data::*, multi_entry_member::*}; fn render_entry_component(entry_data: MultiEntryData, member_info: MultiEntryMember, label: String) -> impl IntoView { // Parse the multientry members into the correct components let data = entry_data.data.get(&member_info.member_name); - let reactive = RwSignal::new(data.unwrap().as_string().unwrap()); + let reactive = RwSignal::new(data.unwrap().clone()); let temp = either!(member_info.input_type, InputType::Text => view! { {render_entry_component(data, input, "test".to_owned())} + //
{render_entry_component(data, input, "test".to_owned())}
} }).collect::>() } diff --git a/src/components/multi_entry/value_type.rs b/src/components/multi_entry/value_type.rs index fbe78d2..8b8d7fb 100644 --- a/src/components/multi_entry/value_type.rs +++ b/src/components/multi_entry/value_type.rs @@ -59,6 +59,12 @@ impl ValueType { } } +impl Default for ValueType { + fn default() -> Self { + ValueType::String(String::new()) + } +} + impl Display for ValueType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let str = match self { diff --git a/src/components/text_field.rs b/src/components/text_field.rs index 46f8c4e..51d2dba 100644 --- a/src/components/text_field.rs +++ b/src/components/text_field.rs @@ -1,32 +1,42 @@ use leptos::prelude::*; -use std::str::FromStr; +use crate::components::ValueType; #[component] -pub fn OutlinedTextField( - #[prop(optional, into)] placeholder: T, - #[prop(optional)] value: RwSignal, +pub fn OutlinedTextField( + #[prop(optional, into)] placeholder: String, + // #[prop()] value: Subfield, + #[prop()] value: RwSignal, #[prop(optional)] disabled: RwSignal, #[prop(optional)] error: RwSignal, #[prop(optional, into)] name: String, #[prop(optional, into)] label: String, #[prop(optional, into)] input_type: String, -) -> impl IntoView -where - T: Default + 'static + FromStr + ToString + PartialEq + Send + Sync + Clone, -{ - // Parsing logic for non-string types which happens on each input. + #[prop(optional, into)] error_text: RwSignal +) -> impl IntoView { + // Check if the type is one of the supported formats. This input will only accept a string + // or a number value. let on_input = move |e| { - let input_value = event_target_value(&e); - let can_parse = T::from_str(&input_value); - if let Ok(parsed_value) = can_parse { - value.set(parsed_value); - } else { - error.set(true); - value.set(T::default()); + match value.get() { + ValueType::String(_) => { + // Define string parse function. + value.set(ValueType::String(event_target_value(&e))); + }, + ValueType::Number(_) => { + // Define number parse function. + let temp = event_target_value(&e); + value.set(ValueType::Number(temp.parse::().unwrap_or(0))); + }, + _ => { + // Create some custom function that reports failure. + let value_type = value.get(); + println!("Input {value_type:?} is not a valid type."); + error.set(true); + error_text.set(format!("InputType {value_type:?} is not a valid type.")); + } } }; - - view! ( + + view! {
- ) + } } diff --git a/src/pages/home_page.rs b/src/pages/home_page.rs index 5e36a68..4b08df1 100644 --- a/src/pages/home_page.rs +++ b/src/pages/home_page.rs @@ -7,10 +7,11 @@ use serde_dynamo::{from_item, to_item}; use crate::app::Unauthenticated; use crate::common::{StudentInfo, UserClaims}; -use crate::components::{ActionButton, Loading, OutlinedTextField, Panel, RadioList, Row, Select}; +use crate::components::{ActionButton, Loading, OutlinedTextField, Panel, Row}; use leptos::leptos_dom::logging::console_log; use leptos::prelude::*; use leptos_oidc::{Algorithm, AuthLoaded, AuthSignal, Authenticated}; +use reactive_stores::Store; use traits::{AsReactive, ReactiveCapture}; /// # Get Student Info @@ -124,6 +125,7 @@ pub fn HomePage() -> impl IntoView { server_resource .get() .map(|submission: StudentInfo| { + let store_info = Store::new(submission.clone()); let reactive_info = submission.as_reactive(); let elements_disabled = RwSignal::new(false); let result_msg = Signal::derive(move || { @@ -197,34 +199,36 @@ pub fn HomePage() -> impl IntoView { value=reactive_info.address /> - - - - - + // impl IntoView { placeholder = "Testing information..." name = "testing_input" label = "This is a testing question." - value = RwSignal::new("".to_owned()) + value = RwSignal::new(ValueType::String("".to_owned())) />