feat: add CB loaner page skeleton
This commit is contained in:
1 parent
862ed59085
commit
0490964dde
2 files changed
+132
No files matched your search
@@ -0,0 +1,131 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use leptos::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use leptos::logging::log;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
use aws_sdk_dynamodb::{Client, error::ProvideErrorMetadata, types::AttributeValue};
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
use serde_dynamo::{from_item, to_item};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
struct LoanerReturnOutput {
|
||||
/// The first name of the student that is borrowing.
|
||||
name: String,
|
||||
/// The last name of the student that is borrowing.
|
||||
last_name: String,
|
||||
/// The type of loan that was given to the student.
|
||||
loan: String,
|
||||
/// The date that the student borrowed the loaner.
|
||||
date: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
struct LoanerBorrowInput {
|
||||
/// The first name of the student that is borrowing.
|
||||
first_name: String,
|
||||
/// The last name of the student that is borrowing.
|
||||
last_name: String,
|
||||
/// The email address of the student that is borrowing.
|
||||
email: String,
|
||||
/// The collateral that the student is leaving. Usually a phone, earbuds, etc.
|
||||
collateral: String,
|
||||
/// The type of loan that was given to the student. May be a Chromebook, headphones, etc.
|
||||
loan: String,
|
||||
/// The date that the loaner was borrowed.
|
||||
date: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[server]
|
||||
async fn get_loaners_return_list() -> Result<Vec<LoanerReturnOutput>, ServerFnError> {
|
||||
// We want to query the database for all loaners, but we only want the name and
|
||||
// date of borrowing. This will be cheaper than querying the entire table.
|
||||
let dbclient = Client::new(&aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await);
|
||||
|
||||
log!("Getting loaners from database.");
|
||||
|
||||
match dbclient
|
||||
.scan()
|
||||
.table_name("loaner-info")
|
||||
.projection_expression("name, date")
|
||||
.send()
|
||||
.await {
|
||||
Ok(output) => {
|
||||
if let Some(items) = output.items {
|
||||
Ok(items.into_iter().map(|item| from_item(item).unwrap()).collect())
|
||||
} else {
|
||||
Ok(vec![])
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
let msg = err.message().unwrap_or("Unknown error");
|
||||
Err(ServerFnError::new(msg))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[server]
|
||||
async fn create_borrow_entry(input: LoanerBorrowInput) -> Result<(), ServerFnError> {
|
||||
let dbclient = Client::new(&aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await);
|
||||
let item = to_item(input)?;
|
||||
|
||||
match dbclient
|
||||
.put_item()
|
||||
.table_name("loaner-info")
|
||||
.set_item(Some(item))
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
let msg = err.message().unwrap_or("An unknown error occurred.");
|
||||
Err(ServerFnError::new(msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Loaner Page
|
||||
///
|
||||
/// This page is going to temporarily piggy-back on the general scholarship app, at least until
|
||||
/// we spin off the components used here into a new standalone crate.
|
||||
///
|
||||
/// The loaner app handles management of Chromebook loaners to students. It was originally hosted
|
||||
/// using Google Apps Script, but has recently been broken by some unknown API error. I've chosen
|
||||
/// to rewrite this into a single new application, which we will host in AWS with a real database.
|
||||
///
|
||||
/// It should use all the same components as the scholarship loaner, maybe with a few extra
|
||||
/// alterations. The page will only use a single database table, and it will only have a few very
|
||||
/// basic APIs.
|
||||
///
|
||||
/// # Design
|
||||
///
|
||||
/// The page should have two sections - one for logging a loaner that's being taken out (borrowing)
|
||||
/// and another for a loaner that's being brought back (returning). As of right now, we have two
|
||||
/// separate buttons that handle these functions, and they slide open a panel at the bottom of the
|
||||
/// screen. The borrowing menu has a single, simple form, and the returning side has a list of
|
||||
/// buttons that allow students to choose their name and remove it from the list.
|
||||
///
|
||||
/// # New features
|
||||
///
|
||||
/// I believe that with a new workflow and an overhauled server with real data management, we should
|
||||
/// create a true admin page for this, simply to be able to survey and override/remove information
|
||||
/// from the lists.
|
||||
#[component]
|
||||
pub fn LoanerPage() -> impl IntoView {
|
||||
// Register server actions.
|
||||
let create_entry_action = ServerAction::<CreateBorrowEntry>::new();
|
||||
|
||||
// Register server resources
|
||||
let return_list_resource: Resource<Vec<LoanerReturnOutput>> = Resource::new(
|
||||
move || (),
|
||||
async |_| get_loaners_return_list().await.unwrap_or_else(|e| {
|
||||
log!("There was an error getting the loaner list: {}", e);
|
||||
vec![]
|
||||
})
|
||||
);
|
||||
|
||||
// We'll create the view here. Just remember that we want to have two sections, where they
|
||||
// preferably slide in when they're activated.
|
||||
view! {}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
mod about_page;
|
||||
mod home_page;
|
||||
mod unauthenticated_page;
|
||||
mod loaner_page;
|
||||
|
||||
pub use self::{about_page::*, home_page::*, unauthenticated_page::*};
|
||||
Reference in new issue
Block a user