feat: reorganize and add single selection to chip lists

This commit is contained in:
alphafetus committed 2026-01-07 00:22:46 -05:00
1 parent 105e6b3e55
commit 8d9faf126d
6 files changed
+214 -61

No files matched your search

+44 -4
View File
@@ -1,9 +1,13 @@
use std::collections::HashMap;
#[cfg(feature = "ssr")]
use crate::pages::utils::server_utils::create_dynamo_client;
#[cfg(feature = "ssr")]
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
#[cfg(feature = "ssr")]
use leptos::logging::log;
use crate::common::{
ComparisonData, ComparisonType, MapListComparison, NumberComparison, NumberListComparison,
TextComparison, TextListComparison, ValueType,
@@ -314,8 +318,6 @@ fn make_comp_list() -> Vec<ComparisonData> {
#[server(CreateTestComparisons, endpoint = "/comparisons/create-test")]
pub async fn create_test_comparisons() -> Result<(), ServerFnError> {
use leptos::logging::log;
let client = create_dynamo_client().await;
log!("Creating test comparisons");
@@ -340,8 +342,6 @@ pub async fn create_test_comparisons() -> Result<(), ServerFnError> {
#[server]
pub async fn get_comparison_info() -> Result<Vec<ComparisonData>, ServerFnError> {
use leptos::logging::log;
let client = create_dynamo_client().await;
log!("Getting all comparisons from the database");
@@ -368,3 +368,43 @@ pub async fn get_comparison_info() -> Result<Vec<ComparisonData>, ServerFnError>
}
}
}
#[server]
pub async fn get_comparisons_categorized() -> Result<HashMap<String, Vec<ComparisonData>>, ServerFnError> {
let client = create_dynamo_client().await;
log!("Getting all comparisons from the database, by category.");
match client
.scan()
.table_name("leptos-comparison-test")
.send()
.await
{
Ok(output) => {
if let Some(items) = output.items {
log!("Found comparisons, categorizing.");
let items: Vec<ComparisonData> = serde_dynamo::from_items(items)?;
let categorized = items.iter().fold(
HashMap::<String, Vec<ComparisonData>>::new(), |mut map, comp| {
// Load each comparison into a map, then return that map.
map.entry(comp.category.clone())
.and_modify(|vec| vec.push(comp.clone()))
.or_insert(vec![comp.clone()]);
map
}
);
Ok(categorized)
} else {
Err(ServerFnError::new("Couldn't find any comparisons."))
}
}
Err(err) => {
let msg = err.message().unwrap_or("An unknown error occurred");
Err(ServerFnError::new(msg))
}
}
}
+24 -1
View File
@@ -8,7 +8,7 @@ use std::process::{Command, Stdio};
#[cfg(feature = "ssr")]
use std::io::Write;
use crate::common::ExpandableInfo;
use crate::common::{ComparisonData, ExpandableInfo};
use crate::pages::UnauthenticatedPage;
use crate::pages::utils::get_user_claims;
use crate::components::{ActionButton, CheckboxList, Loading, MultiEntry, OutlinedTextField, Panel, RadioList, Row, Select, TextFieldType, ValidatedForm};
@@ -22,6 +22,7 @@ use leptos::task::spawn_local;
use leptos::web_sys::HtmlAnchorElement;
use leptos::wasm_bindgen::JsCast;
use std::collections::HashMap;
use crate::pages::api::get_comparisons_categorized;
/// # Get Student Info
/// Gets a student's information given their `subject`.
@@ -209,6 +210,28 @@ pub fn HomePage() -> impl IntoView {
};
//#endregion
let comparison_resource = Resource::new(
move || user_subject.get(),
async move |_| get_comparisons_categorized().await
);
let comparison_info = RwSignal::new(HashMap::<String, Vec<ComparisonData>>::new());
Effect::new(move || {
match comparison_resource.get() {
Some(Ok(comparisons)) => {
log!("Found comparison info: {:?}", comparisons);
comparison_info.set(comparisons);
}
Some(Err(err)) => {
log!("Error while getting comparisons: {:?}", err);
}
_ => {
log!("An unknown error occurred.");
}
}
});
view! {
<AuthLoaded fallback=Loading>
<Authenticated unauthenticated=UnauthenticatedPage>
+93 -20
View File
@@ -8,9 +8,8 @@ use leptos_router::hooks::{use_navigate, use_params};
use crate::common::{ExpandableInfo, ScholarshipFormParams, SubmitStatus, ValueType};
use crate::components::{ActionButton, Banner, ChipsList, Loading, OutlinedTextField, Panel, RadioList, Row, TextFieldType, ValidatedForm};
use super::UnauthenticatedPage;
use crate::common::ComparisonData;
use crate::pages::utils::get_user_claims;
use super::api::{get_comparison_info, get_provider_scholarships, get_scholarship_info, CreateScholarshipInfo, RegisterScholarship, DeleteProviderScholarship};
use super::api::{get_comparison_info, get_provider_scholarships, get_scholarship_info, CreateScholarshipInfo, RegisterScholarship, DeleteProviderScholarship, get_comparisons_categorized};
/// # Scholarship Info Page
@@ -245,7 +244,7 @@ fn ScholarshipList(
}}
</div>
<div>
<div class="p-2 bg-red-800 rounded-md text-center text-white hover:bg-red-900 transition-all"
<div class="p-2 bg-red-800 rounded-md text-center text-white hover:bg-red-900 transition-all cursor-pointer"
on:click=create_on_click>
"Create New"
</div>
@@ -383,7 +382,7 @@ fn ScholarshipForm(
}
});
let comparison_list: Resource<Vec<ComparisonData>> = Resource::new(
let comparison_list = Resource::new(
move || scholarship_id.get(), // There's no input to this function.
async move |_| {
get_comparison_info().await
@@ -394,6 +393,19 @@ fn ScholarshipForm(
}
);
let comparison_lists = Resource::new(
move || scholarship_id.get().is_some(),
async move |_| {
get_comparisons_categorized().await
}
);
Effect::new(move || {
if let Some(Ok(map)) = comparison_lists.get() {
log!("Available categories: {:?}", map.keys());
}
});
let scholarship_info = Resource::new(
move || scholarship_id.get(),
async move |opt_id| {
@@ -406,25 +418,67 @@ fn ScholarshipForm(
);
let form_data = RwSignal::new(HashMap::new());
let chips_data = RwSignal::new(HashMap::new());
Effect::new(move || {
if let Some(Ok(scholarship)) = scholarship_info.get() {
// Get the default chips data.
let chips_default = if let Some(ValueType::Map(Some(map))) = scholarship.data.get("requirements") {
map.clone()
} else {
HashMap::new()
};
chips_data.set(chips_default);
form_data.set(scholarship.data);
}
});
let comparison_ids = Memo::new(move |_| {
comparison_list.get().map(|list| list.iter()
.map(|comp| comp.clone().id)
let get_comp_category = move |category: &str| {
if let Some(Ok(map)) = comparison_lists.get() {
map.get(category).unwrap_or(&Vec::new()).clone()
} else {
Vec::new()
}
};
let get_comp_ids = move |category: &str| {
get_comp_category(category)
.into_iter()
.map(|comp| comp.id)
.collect::<Vec<String>>()
).unwrap_or_default()
};
let get_comp_text = move |category: &str| {
get_comp_category(category)
.into_iter()
.map(|comp| comp.display_text)
.collect::<Vec<String>>()
};
// Get comparison lists.
let sports_ids = Signal::derive(move || {
get_comp_ids("Sports Participation")
});
let comparison_text = Memo::new(move |_| {
comparison_list.get().map(|list| list.iter()
.map(|comp| comp.clone().display_text)
.collect::<Vec<String>>()
).unwrap_or_default()
let sports_text = Signal::derive(move || {
get_comp_text("Sports Participation")
});
let misc_ids = Signal::derive(move || {
get_comp_ids("Miscellaneous")
});
let misc_text = Signal::derive(move || {
get_comp_text("Miscellaneous")
});
let comm_ids = Signal::derive(move || {
get_comp_ids("Community Involvement")
});
let comm_text = Signal::derive(move || {
get_comp_text("Community Involvement")
});
// We'll collect the scholarship's name, num_awards, amount_per_award, total_awards,
@@ -546,11 +600,30 @@ fn ScholarshipForm(
</Row>
<Row>
<ChipsList
label="Scholarship Requirements"
data_member="requirements"
data_map=form_data
values=comparison_ids
displayed_text=comparison_text
label="Sports Participation"
data_member="sports_participation"
data_map=chips_data
values=sports_ids
displayed_text=sports_text
allows_multiple=true
/>
</Row>
<Row>
<ChipsList
label="Community Involvement"
data_member="community_involvement"
data_map=chips_data
values=comm_ids
displayed_text=comm_text
/>
</Row>
<Row>
<ChipsList
label="Miscellaneous"
data_member="misc"
data_map=chips_data
values=misc_ids
displayed_text=misc_text
/>
</Row>
})