feat: implement procedural display of file drop inputs

This commit is contained in:
alphafetus committed 2026-03-02 15:43:58 -05:00
1 parent 9d156c17e9
commit fb90a9d8ac
1 file changed
+85 -28
+85 -28
View File
@@ -1,10 +1,12 @@
use crate::common::{ComparisonData, ExpandableInfo, SchemaNode, SchemaType, ValueType}; use crate::common::{ComparisonData, ExpandableInfo, ValueType};
use crate::components::ValueDisplay; use crate::components::{FileDrop, Header};
use crate::pages::api::files::list_files;
use crate::pages::api::students::get_all_student_data; use crate::pages::api::students::get_all_student_data;
use crate::pages::api::{get_all_scholarship_info, get_comparison_info}; use crate::pages::api::{get_all_scholarship_info, get_comparison_info};
use crate::utils::get_user_claims; use crate::utils::get_user_claims;
use leptos::logging::debug_log; use leptos::logging::debug_log;
use leptos::prelude::*; use leptos::prelude::*;
use leptos_oidc::AuthSignal;
#[component] #[component]
pub fn StudentEligibilityPage() -> impl IntoView { pub fn StudentEligibilityPage() -> impl IntoView {
@@ -18,9 +20,12 @@ pub fn StudentEligibilityPage() -> impl IntoView {
// My only reservation with showing the scholarships that aren't valid is that people will want // My only reservation with showing the scholarships that aren't valid is that people will want
// to know why. That's hard information to keep track of right now. // to know why. That's hard information to keep track of right now.
let auth = expect_context::<AuthSignal>();
let user_claims = get_user_claims(); let user_claims = get_user_claims();
let user_id = Memo::new(move |_| user_claims.get().map(|info| info.claims.subject.clone())); let user_id = Memo::new(move |_| user_claims.get().map(|info| info.claims.subject.clone()));
let form_id = StoredValue::new("scholarship_essays".to_string());
let refresh_trigger = Trigger::new(); let refresh_trigger = Trigger::new();
let scholarships_resource = Resource::new( let scholarships_resource = Resource::new(
@@ -38,7 +43,7 @@ pub fn StudentEligibilityPage() -> impl IntoView {
view! { view! {
<div class="flex-1" /> <div class="flex-1" />
<div> <div class="flex-2 mb-4 flex flex-col">
<Suspense fallback=move || { <Suspense fallback=move || {
view! { <div>"Checking eligibility..."</div> } view! { <div>"Checking eligibility..."</div> }
}> }>
@@ -117,39 +122,91 @@ pub fn StudentEligibilityPage() -> impl IntoView {
}); });
if valid { if valid {
debug_log!("Scholarship is valid."); debug_log!("Scholarship is valid.");
Some(scholarship.clone()) let scholarship_id = StoredValue::new(scholarship.subject.clone());
let resource = Resource::new(
move || (
auth
.try_with(|a| a.authenticated().map(|a| a.access_token()))
.flatten(),
form_id.get_value(),
scholarship_id.get_value(),
),
async move |(access_token, form_id, scholarship_id)| {
list_files(
access_token.unwrap_or_default(),
form_id,
scholarship_id,
)
.await
},
);
Some((scholarship.clone(), resource))
} else { } else {
None None
} }
}) })
.collect::<Vec<ExpandableInfo>>(); .collect::<
Vec<(ExpandableInfo, Resource<Result<Vec<String>, ServerFnError>>)>,
>();
view! { view! {
<div>{format!("Valid scholarships: {}", valid_list.len())}</div> <Header
<For title="Eligible Scholarships"
each=move || valid_list.clone() description="This is the list of scholarships that you are eligible for, as well as those that require essays.
key=|scholarship| { scholarship.subject.clone() } Once you have fulfilled the essay requirement, you will be automatically applied for that scholarship.
children=move |scholarship| { If there is no essay requirement, you have already been applied."
let scholarship = StoredValue::new(scholarship); />
let display_schema = SchemaNode::new(SchemaType::Map) <div>
.header("Eligible Scholarship") <For
.child( each=move || valid_list.clone()
"name", key=|(scholarship, _)| { scholarship.subject.clone() }
SchemaNode::new(SchemaType::String) children=move |(scholarship, resource)| {
.header("Scholarship Name"), let scholarship_id = StoredValue::new(
) scholarship.subject.clone(),
.child( );
"essay_prompt", let scholarship_name = StoredValue::new(
SchemaNode::new(SchemaType::String).header("Essay Prompt"), scholarship
.data
.get("name")
.map(|v| v.as_string().ok().flatten().unwrap_or_default())
.unwrap_or_default(),
);
let scholarship_essay = StoredValue::new(
scholarship
.data
.get("essay_prompt")
.map(|v| v.as_string().ok().flatten().unwrap_or_default())
.unwrap_or_default(),
); );
view! { view! {
<ValueDisplay <div class="m-1.5 flex flex-col gap-2 shadow-lg rounded-lg">
schema=display_schema <div class="rounded-t-lg bg-red-900 p-2 text-white font-bold">
data_map=scholarship.get_value().data {scholarship_name.get_value()}
/> </div>
<div class="p-2 flex flex-col gap-2">
<Show
when=move || !scholarship_essay.get_value().is_empty()
fallback=move || {
view! {
<div>"This scholarship does not require an essay."</div>
}
}
>
<div>{scholarship_essay.get_value()}</div>
<FileDrop
form_id=form_id.get_value()
name=scholarship_id.get_value()
existing_files=resource
/>
</Show>
</div>
</div>
}
} }
} />
/> </div>
} }
.into_any() .into_any()
}} }}