From a95e9a1034eabfc94d0ead124cf18e4f59a2811b Mon Sep 17 00:00:00 2001 From: Lucas Vas Date: Tue, 27 Jan 2026 14:13:55 -0500 Subject: [PATCH] feat: create full provider list setup --- src/pages/admin/provider_page.rs | 71 ++++++++++++++++++++++++------- src/pages/api/admin.rs | 44 +++++++++++++++++++ src/pages/api/comparisons.rs | 5 ++- src/pages/api/dates.rs | 2 +- src/pages/api/mod.rs | 22 ++++++++-- src/pages/api/providers.rs | 70 +++++++++++++++++++++++++++++++ src/pages/api/scholarships.rs | 2 +- src/pages/provider_contact.rs | 72 ++------------------------------ 8 files changed, 198 insertions(+), 90 deletions(-) create mode 100644 src/pages/api/admin.rs create mode 100644 src/pages/api/providers.rs diff --git a/src/pages/admin/provider_page.rs b/src/pages/admin/provider_page.rs index b7b88ff..92ac896 100644 --- a/src/pages/admin/provider_page.rs +++ b/src/pages/admin/provider_page.rs @@ -1,26 +1,69 @@ +use leptos::logging::log; use leptos::prelude::*; +use crate::common::ValueType; use crate::components::{NavListInfo, SelectableNavList}; +use crate::pages::api::get_all_providers; #[component] pub fn AdminProviderPage() -> impl IntoView { let selected_items = RwSignal::new(Vec::new()); - let provider_list = RwSignal::new(vec![ - NavListInfo { - text: vec!["Testing 1".to_string(), 3.to_string(), 500.to_string()], - id: "1".to_string(), - slug: "1".to_string(), - }, - NavListInfo { - text: vec!["Testing 2".to_string(), 2.to_string(), 1000.to_string()], - id: "2".to_string(), - slug: "2".to_string(), + let provider_list = RwSignal::new(Vec::new()); + + let provider_trigger = Trigger::new(); + let provider_resource = Resource::new( + move || provider_trigger.track(), + async move |_| { + get_all_providers().await } - ]); + ); + + Effect::new(move || { + if let Some(Err(err)) = provider_resource.get() { + log!("Found error: {}", err.to_string()); + } + let Some(Ok(list)) = provider_resource.get() else { + return; + }; + + let members_list = vec![ + "contact_email".to_string(), + "first_name".to_string(), + "last_name".to_string(), + ]; + + // Convert the list into a series of NavListInfo + let converted = list + .into_iter() + .map(|info| { + let mut text_list = vec![]; + members_list.iter().for_each(|member| { + let val = info.get(member) + .unwrap_or(&ValueType::String(None)) + .as_string() + .ok().flatten() + .unwrap_or_default(); + text_list.push(val); + }); + + let subject = info.get("subject") + .unwrap_or(&ValueType::String(None)) + .to_string(); + + NavListInfo { + text: text_list, + id: subject.clone(), + slug: subject, + } + }) + .collect(); + + provider_list.set(converted); + }); let headers = vec![ - "Scholarship Name", - "Number of Awards", - "Amount of Awards" + "Email", + "First Name", + "Last Name" ] .iter() .map(|s| s.to_string()) diff --git a/src/pages/api/admin.rs b/src/pages/api/admin.rs new file mode 100644 index 0000000..288c7bc --- /dev/null +++ b/src/pages/api/admin.rs @@ -0,0 +1,44 @@ +use leptos::prelude::*; +use std::collections::HashMap; +use crate::common::ValueType; +use leptos::logging::log; + +#[cfg(feature = "ssr")] +mod server_logic { + pub use crate::utils::server::create_dynamo_client; + pub use super::super::PROVIDER_CONTACT_TABLE; +} + +#[server] +pub async fn get_all_providers() -> Result>, ServerFnError> { + use server_logic::*; + + // We want to get all provider information from the contacts table. + // This will be migrated to the new table structure when it happens. + + let client = create_dynamo_client().await; + + log!("Scanning all provider information from {}", PROVIDER_CONTACT_TABLE); + + client + .scan() + .table_name(PROVIDER_CONTACT_TABLE) + .send() + .await + .map(|output| { + if let Some(items) = output.items { + items + .into_iter() + .map(|item| { + item.into_iter().map(|(key, attr)| { + let val = ValueType::from(&attr); + (key, val) + }).collect() + }) + .collect::>>() + } else { + Vec::new() + } + }) + .map_err(ServerFnError::from) +} diff --git a/src/pages/api/comparisons.rs b/src/pages/api/comparisons.rs index 679d6fa..49c6e02 100644 --- a/src/pages/api/comparisons.rs +++ b/src/pages/api/comparisons.rs @@ -7,6 +7,9 @@ use aws_sdk_dynamodb::error::ProvideErrorMetadata; #[cfg(feature = "ssr")] use leptos::logging::log; +#[cfg(feature = "ssr")] +use super::COMPARISONS_TABLE; + use crate::common::{ ComparisonData, ComparisonType, MapListComparison, NumberComparison, NumberListComparison, TextComparison, TextListComparison, ValueType, @@ -15,8 +18,6 @@ use std::collections::HashMap; use leptos::prelude::ServerFnError; use leptos::server; -#[cfg(feature = "ssr")] -static COMPARISONS_TABLE: &str = "leptos-comparisons"; /// Helper function to create all sports comparisons. Only used to create initial /// comparison data, and should be removed upon completion of a comparison editor page. diff --git a/src/pages/api/dates.rs b/src/pages/api/dates.rs index ee3a6a7..3cbf387 100644 --- a/src/pages/api/dates.rs +++ b/src/pages/api/dates.rs @@ -4,7 +4,7 @@ use leptos::prelude::*; use crate::common::DateInfo; #[cfg(feature = "ssr")] -static DATES_TABLE: &str = "leptos-dates"; +use super::DATES_TABLE; #[cfg(feature = "ssr")] use aws_sdk_dynamodb::{ diff --git a/src/pages/api/mod.rs b/src/pages/api/mod.rs index f7aa9bf..a34655e 100644 --- a/src/pages/api/mod.rs +++ b/src/pages/api/mod.rs @@ -1,7 +1,23 @@ mod comparisons; -pub use comparisons::*; mod scholarships; -pub use scholarships::*; mod dates; -pub use dates::*; +mod admin; +mod providers; +pub use comparisons::*; +pub use scholarships::*; +pub use dates::*; +pub use admin::*; +pub use providers::*; + +#[cfg(feature = "ssr")] +pub static COMPARISONS_TABLE: &str = "leptos-comparisons"; + +#[cfg(feature = "ssr")] +pub static DATES_TABLE: &str = "leptos-dates"; + +#[cfg(feature = "ssr")] +pub static SCHOLARSHIPS_TABLE: &str = "leptos-scholarships"; + +#[cfg(feature = "ssr")] +pub static PROVIDER_CONTACT_TABLE: &str = "leptos-provider-contacts"; diff --git a/src/pages/api/providers.rs b/src/pages/api/providers.rs new file mode 100644 index 0000000..76964bc --- /dev/null +++ b/src/pages/api/providers.rs @@ -0,0 +1,70 @@ +use leptos::prelude::*; +use leptos::logging::log; +use std::collections::HashMap; +use crate::common::ValueType; + +#[cfg(feature = "ssr")] +use crate::utils::server::{create_dynamo_client, into_attr_map}; + +#[cfg(feature = "ssr")] +static PROVIDER_CONTACT_TABLE: &str = "leptos-provider-contacts"; + +#[server] +pub async fn get_provider_contact(id: String) -> Result, ServerFnError> { + use aws_sdk_dynamodb::types::AttributeValue; + use aws_sdk_dynamodb::error::ProvideErrorMetadata; + + let client = create_dynamo_client().await; + + log!("Getting contact info for provider {}", id); + + match client + .get_item() + .table_name(PROVIDER_CONTACT_TABLE) + .key("subject", AttributeValue::S(id)) + .send() + .await + { + Ok(output) => { + let Some(item) = output.item else { + return Ok(HashMap::new()); + }; + + let map = item.iter().map(|(key, val)| { + let val_type = ValueType::from(val); + + (key.clone(), val_type) + }).collect::>(); + + Ok(map) + } + Err(err) => { + let msg = err.message().unwrap_or("An unknown error occurred."); + Err(ServerFnError::new(msg)) + } + } +} + +#[server] +pub async fn put_provider_contact(id: String, contact_info: HashMap) -> Result<(), ServerFnError> { + use aws_sdk_dynamodb::error::ProvideErrorMetadata; + + let client = create_dynamo_client().await; + + let mut item = into_attr_map(contact_info); + item.insert("subject".to_owned(), aws_sdk_dynamodb::types::AttributeValue::S(id)); + + match client + .put_item() + .table_name(PROVIDER_CONTACT_TABLE) + .set_item(Some(item)) + .send() + .await + { + Ok(_) => Ok(()), + Err(err) => { + let msg = err.message().unwrap_or("An unknown error occurred."); + Err(ServerFnError::new(msg)) + } + } +} \ No newline at end of file diff --git a/src/pages/api/scholarships.rs b/src/pages/api/scholarships.rs index 5101af6..0e5dd5a 100644 --- a/src/pages/api/scholarships.rs +++ b/src/pages/api/scholarships.rs @@ -18,7 +18,7 @@ use leptos::prelude::ServerFnError; use leptos::server; #[cfg(feature = "ssr")] -static SCHOLARSHIPS_TABLE: &str = "leptos-scholarships"; +use super::SCHOLARSHIPS_TABLE; #[server(GetScholarshipInfo)] pub async fn get_scholarship_info(id: String) -> Result { diff --git a/src/pages/provider_contact.rs b/src/pages/provider_contact.rs index f1c9ddc..b560cf6 100644 --- a/src/pages/provider_contact.rs +++ b/src/pages/provider_contact.rs @@ -1,77 +1,11 @@ -#[cfg(feature = "ssr")] -use crate::utils::server::{create_dynamo_client, into_attr_map}; - -use std::collections::HashMap; +use std::collections::HashMap; use leptos::logging::log; use leptos::prelude::*; use leptos_oidc::{AuthLoaded, Authenticated}; -use crate::common::ValueType; -use crate::components::{Banner, Loading, OutlinedTextField, Panel, Row, TextFieldType, Toast, ToastContext, ToastList, ValidatedForm}; +use crate::components::{Banner, Loading, OutlinedTextField, Panel, Row, TextFieldType, Toast, ToastContext, ValidatedForm}; use crate::pages::UnauthenticatedPage; use crate::utils::get_user_claims; - -#[cfg(feature = "ssr")] -static PROVIDER_CONTACT_TABLE: &str = "leptos-provider-contacts"; - -#[server] -async fn get_provider_contact(id: String) -> Result, ServerFnError> { - use aws_sdk_dynamodb::types::AttributeValue; - use aws_sdk_dynamodb::error::ProvideErrorMetadata; - - let client = create_dynamo_client().await; - - log!("Getting contact info for provider {}", id); - - match client - .get_item() - .table_name(PROVIDER_CONTACT_TABLE) - .key("subject", AttributeValue::S(id)) - .send() - .await - { - Ok(output) => { - let Some(item) = output.item else { - return Ok(HashMap::new()); - }; - - let map = item.iter().map(|(key, val)| { - let val_type = ValueType::from(val); - - (key.clone(), val_type) - }).collect::>(); - - Ok(map) - } - Err(err) => { - let msg = err.message().unwrap_or("An unknown error occurred."); - Err(ServerFnError::new(msg)) - } - } -} - -#[server] -async fn put_provider_contact(id: String, contact_info: HashMap) -> Result<(), ServerFnError> { - use aws_sdk_dynamodb::error::ProvideErrorMetadata; - - let client = create_dynamo_client().await; - - let mut item = into_attr_map(contact_info); - item.insert("subject".to_owned(), aws_sdk_dynamodb::types::AttributeValue::S(id)); - - match client - .put_item() - .table_name(PROVIDER_CONTACT_TABLE) - .set_item(Some(item)) - .send() - .await - { - Ok(_) => Ok(()), - Err(err) => { - let msg = err.message().unwrap_or("An unknown error occurred."); - Err(ServerFnError::new(msg)) - } - } -} +use super::api::{get_provider_contact, PutProviderContact}; #[component] pub fn ProviderContactPage() -> impl IntoView {