diff --git a/src/common/expandable_info.rs b/src/common/expandable_info.rs index e7bafca..ebb0f8f 100644 --- a/src/common/expandable_info.rs +++ b/src/common/expandable_info.rs @@ -15,19 +15,19 @@ use crate::components::ValueType; /// now, the table will simply create a single massive `Map` field that contains all the stored /// information in the `HashMap`. We'd prefer to be able to get single values if possible, /// especially for interoperability with other applications, should they be created. -#[derive(Debug, Clone, Default, Serialize, Deserialize, Reactive)] +#[derive(Debug, Clone, Serialize, Deserialize, Reactive)] pub struct ExpandableInfo { /// The main key member. Required and used to get/put the information in a database. - key_member: String, + pub subject: String, /// The main data store. Contains all information that this struct needs to hold. - #[serde(default)] - data: HashMap, + #[serde(default, flatten)] + pub data: HashMap, } impl ExpandableInfo { pub fn new(key: String) -> Self { Self { - key_member: key, + subject: key, data: HashMap::new(), } } diff --git a/src/components/multi_entry/value_type.rs b/src/components/multi_entry/value_type.rs index 541c825..4572e1b 100644 --- a/src/components/multi_entry/value_type.rs +++ b/src/components/multi_entry/value_type.rs @@ -9,7 +9,7 @@ pub enum ValueType { /// Indicates a `String` value. String(Option), /// Indicates an `i32` value. - Number(Option), + Number(Option), /// Indicates a `Vec`, where `T` can be any other `ValueType`. List(Option>), } @@ -35,7 +35,7 @@ impl ValueType { } /// Attempts to get this value as an `i32`. - pub fn as_number(&self) -> Result, Self> { + pub fn as_number(&self) -> Result, Self> { if let ValueType::Number(v) = self { Ok(v.clone()) } else { @@ -69,7 +69,7 @@ impl Display for ValueType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let str = match self { ValueType::String(s) => s.clone().unwrap_or("".to_owned()), - ValueType::Number(n) => n.unwrap_or(0).to_string(), + ValueType::Number(n) => n.clone().unwrap_or("".to_owned()), ValueType::List(l) => format!("{l:?}"), }; write!(f, "{}", str) diff --git a/src/components/text_field.rs b/src/components/text_field.rs index a8aff8a..936ef68 100644 --- a/src/components/text_field.rs +++ b/src/components/text_field.rs @@ -44,7 +44,7 @@ pub fn OutlinedTextField( // If the number parses, Some(num), else None, but we want to keep the value that's // in the text field at this point, just set the error. console_log(format!("Parsing {to_parse} to a number").as_str()); - match to_parse.parse::().map(|n| ValueType::Number(Some(n))) { + match to_parse.parse::().map(|n| ValueType::Number(Some(n.to_string()))) { Ok(value_type) => { error.set(false); value.set(value_type.clone()); diff --git a/src/pages/home_page.rs b/src/pages/home_page.rs index ec862d7..24b79ac 100644 --- a/src/pages/home_page.rs +++ b/src/pages/home_page.rs @@ -7,12 +7,11 @@ use aws_sdk_dynamodb::{Client, error::ProvideErrorMetadata, types::AttributeValu use serde_dynamo::{from_item, to_item}; use crate::app::Unauthenticated; -use crate::common::{ExpandableInfo, StudentInfo, UserClaims}; -use crate::components::{ActionButton, CheckboxList, Loading, OutlinedTextField, Panel, RadioList, Row, Select, ValueType}; +use crate::common::{ExpandableInfo, UserClaims}; +use crate::components::{ActionButton, CheckboxList, Loading, OutlinedTextField, Panel, RadioList, Row, Select}; 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 @@ -20,18 +19,18 @@ use traits::{AsReactive, ReactiveCapture}; /// /// All information is found by using a `GetItemCommand` in the student application DynamoDB table. #[server(GetSubmission, endpoint = "/get-submission")] -pub async fn get_submission(id: String) -> Result { +pub async fn get_submission(subject: String) -> Result { let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await; let dbclient = Client::new(&config); - console_log(format!("Getting values from API using username {}", id).as_str()); + console_log(format!("Getting values from API using subject {}", subject).as_str()); // Gets the item from the database. It only returns an error if the database // experiences an error - not if the item is not found. match dbclient .get_item() - .table_name("student-applications") - .key("Email", AttributeValue::S(id.clone())) + .table_name("leptos-test") + .key("subject", AttributeValue::S(subject.clone())) .send() .await { @@ -41,8 +40,7 @@ pub async fn get_submission(id: String) -> Result { Ok(from_item(item)?) } else { console_log("Couldn't find entry, returning default."); - let mut info = StudentInfo::default(); - info.Email = id; // Set the correct subject + let info = ExpandableInfo::new(subject); Ok(info) } } @@ -69,7 +67,7 @@ pub async fn create_sample_submission(student_info: ExpandableInfo) -> Result<() console_log(format!("Arguments for sample submission: {:?}", item).as_str()); match dbclient .put_item() - .table_name("student-applications") + .table_name("leptos-test") .set_item(Some(item)) .send() .await @@ -92,7 +90,7 @@ pub async fn create_sample_submission(student_info: ExpandableInfo) -> Result<() pub async fn log_expandable(info: ExpandableInfo) -> Result<(), ServerFnError> { console_log(format!("Was given info: {:?}", info).as_str()); // Manually specify the type here since we're not able to infer the type later. - let item: HashMap = to_item(&info)?; + let item: HashMap = to_item(info)?; console_log(format!("Converted into a DynamoDB item: {:?}", item).as_str()); Ok(()) @@ -115,14 +113,14 @@ pub fn HomePage() -> impl IntoView { // Note that the value passed in MUST be equatable. // We get/unwrap the value repeatedly until we get a simple string value, then clone it so that // we don't lose access to it in the future, should we need it again. - let server_resource: Resource = Resource::new( + let server_resource: Resource = Resource::new( move || user_claims.get().map(|claim| claim.claims.subject.clone()), async |opt_username| match opt_username { - Some(username) => get_submission(username).await.unwrap_or_else(|e| { + Some(subject) => get_submission(subject.clone()).await.unwrap_or_else(|e| { console_log(e.to_string().as_str()); - StudentInfo::default() + ExpandableInfo::new(subject) }), - None => StudentInfo::default(), + None => ExpandableInfo::new("".to_owned()), }, ); let submit_action = ServerAction::::new(); @@ -137,13 +135,7 @@ pub fn HomePage() -> impl IntoView { server_resource .get() .map(|submission| { - let expandable = ExpandableInfo::new("email".into()); - let expandable_react = expandable.as_reactive(); - expandable_react.data.update(|map| { - map.insert("email".into(), ValueType::String(Some("test@region15.org".into()))); - map.insert("phone_number".into(), ValueType::String(Some("123456789-10".into()))); - map.insert("math_sat".into(), ValueType::Number(Some(1234))); - }); + let expandable_react = submission.as_reactive(); let elements_disabled = RwSignal::new(false); let result_msg = Signal::derive(move || { // Eventually, this function will show and hide a loading symbol @@ -246,6 +238,7 @@ pub fn HomePage() -> impl IntoView { /> + // Checkbox { data_member, label, items } impl IntoView { label="Gender:" value_list=vec!["Male", "Female", "Prefer not to answer"] .into_iter() - .map(|s| s.into()) + .map(|s| s.to_owned()) .collect() disabled=elements_disabled data_member="gender" @@ -275,10 +268,9 @@ pub fn HomePage() -> impl IntoView { on:click=move |_| { let captured_map = expandable_react.capture(); console_log(format!("Map values: {:?}", captured_map).as_str()); - submit_action - .dispatch(CreateSampleSubmission { - student_info: captured_map, - }); + submit_action.dispatch(CreateSampleSubmission { + student_info: captured_map, + }); } disabled=elements_disabled >"Submit"