Datum auswählbar machen

This commit is contained in:
Franz Dietrich 2024-01-31 20:32:53 +01:00
parent 6ea404845a
commit 165d68ca50
6 changed files with 113 additions and 35 deletions

View File

@ -40,3 +40,11 @@ pub async fn get_unavailable_json(pool: web::Data<Pool>) -> Result<HttpResponse,
Ok(HttpResponse::Ok().json(tasks)) Ok(HttpResponse::Ok().json(tasks))
} }
pub async fn get_dates_json(pool: web::Data<Pool>) -> Result<HttpResponse, Error> {
let dates = db::read::get_dates(&pool)
.await
.map_err(error::ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(dates))
}

View File

@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
use sqlx::query_as; use sqlx::query_as;
use terminwahl_typen::{ use terminwahl_typen::{
AppointmentSlot, AppointmentSlots, IdType, Nutzer, SlotId, Subject, Subjects, Teacher, Teachers, AppointmentSlot, AppointmentSlots, Date, Dates, IdType, Nutzer, SlotId, Subject, Subjects,
Teacher, Teachers,
}; };
use super::Pool; use super::Pool;
@ -93,7 +94,20 @@ pub async fn get_unavailable(db: &Pool) -> Result<HashSet<SlotId>, sqlx::Error>
Err(e) => Err(e), Err(e) => Err(e),
} }
} }
pub async fn get_dates(db: &Pool) -> Result<Dates, sqlx::Error> {
match query_as!(
Date,
r#"
SELECT *
FROM `date`;"#,
)
.fetch_all(db)
.await
{
Ok(elems) => Ok(elems.into_iter().collect()),
Err(e) => Err(e),
}
}
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TeacherWithAppointments { pub struct TeacherWithAppointments {
teacher: Teacher, teacher: Teacher,

View File

@ -69,6 +69,7 @@ async fn main() -> std::io::Result<()> {
.wrap(Logger::default()) .wrap(Logger::default())
.wrap(session_store) .wrap(session_store)
.wrap(error_handlers) .wrap(error_handlers)
.service(web::resource("/get/dates").route(web::get().to(api::read::get_dates_json)))
.service( .service(
web::resource("/get/teachers/{date_key}") web::resource("/get/teachers/{date_key}")
.route(web::get().to(api::read::get_teachers_json)), .route(web::get().to(api::read::get_teachers_json)),

View File

@ -4,8 +4,8 @@ use std::collections::{HashMap, HashSet};
use gloo::console::log; use gloo::console::log;
use requests::{fetch_dates, fetch_slots, fetch_teachers, fetch_unavailable, send_appointments}; use requests::{fetch_dates, fetch_slots, fetch_teachers, fetch_unavailable, send_appointments};
use terminwahl_typen::{ use terminwahl_typen::{
AppointmentSlot, AppointmentSlots, Dates, IdType, Nutzer, PlannedAppointment, RequestState, AppointmentSlot, AppointmentSlots, Date, Dates, IdType, Nutzer, PlannedAppointment,
SlotId, Teacher, Teachers, RequestState, SlotId, Teacher, Teachers,
}; };
use web_sys::HtmlInputElement; use web_sys::HtmlInputElement;
use yew::prelude::*; use yew::prelude::*;
@ -16,11 +16,12 @@ pub enum Msg {
UpdateSchüler(String), UpdateSchüler(String),
UpdateEmail(String), UpdateEmail(String),
DataEntered(Nutzer), DataEntered(Nutzer),
GetTeachers, GetTeachers(IdType),
ReceivedTeachers(Teachers), ReceivedTeachers(Teachers),
GetDates, GetDates,
ReceivedDates(Dates), ReceivedDates(Dates),
GetSlots, SelectDate(IdType),
GetSlots(IdType),
ReceivedSlots(AppointmentSlots), ReceivedSlots(AppointmentSlots),
Selected(PlannedAppointment), Selected(PlannedAppointment),
TooMany, TooMany,
@ -33,6 +34,7 @@ pub struct App {
nutzer: Option<Nutzer>, nutzer: Option<Nutzer>,
tmp_nutzer: Nutzer, tmp_nutzer: Nutzer,
dates: Option<Dates>, dates: Option<Dates>,
selected_date: Option<Date>,
teachers: Option<Teachers>, teachers: Option<Teachers>,
slots: Option<AppointmentSlots>, slots: Option<AppointmentSlots>,
appointments: HashMap<SlotId, PlannedAppointment>, appointments: HashMap<SlotId, PlannedAppointment>,
@ -58,6 +60,7 @@ impl Component for App {
appointments: HashMap::new(), appointments: HashMap::new(),
slots: None, slots: None,
dates: None, dates: None,
selected_date: None,
unavailable: None, unavailable: None,
teachers: None, teachers: None,
nutzer: None, nutzer: None,
@ -89,8 +92,8 @@ impl Component for App {
true true
} }
Msg::TooMany => todo!(), Msg::TooMany => todo!(),
Msg::GetTeachers => { Msg::GetTeachers(id) => {
ctx.link().send_future(fetch_teachers()); ctx.link().send_future(fetch_teachers(id));
false false
} }
Msg::ReceivedTeachers(teachers) => { Msg::ReceivedTeachers(teachers) => {
@ -102,13 +105,25 @@ impl Component for App {
false false
} }
Msg::ReceivedDates(dates) => { Msg::ReceivedDates(dates) => {
if dates.len() == 1 {
ctx.link()
.send_message(Msg::SelectDate(dates.first().unwrap().id))
}
self.dates = Some(dates); self.dates = Some(dates);
ctx.link().send_message(Msg::GetTeachers);
ctx.link().send_message(Msg::GetSlots);
true true
} }
Msg::GetSlots => { Msg::SelectDate(date_id) => {
ctx.link().send_future(fetch_slots()); ctx.link().send_message(Msg::GetTeachers(date_id));
ctx.link().send_message(Msg::GetSlots(date_id));
let date = self
.dates
.as_ref()
.map(|dts| dts.iter().find(|d| d.id == date_id).unwrap());
self.selected_date = Some(date.expect("A date should be found").clone());
true
}
Msg::GetSlots(id) => {
ctx.link().send_future(fetch_slots(id));
ctx.link().send_future(fetch_unavailable()); ctx.link().send_future(fetch_unavailable());
false false
} }
@ -164,24 +179,35 @@ impl Component for App {
html! {<> html! {<>
<section class="hero is-warning"> <section class="hero is-warning">
<div class="hero-body"> <div class="hero-body">
<p class="title has-text-link">
{"Elternsprechtag"} {if let Some(d) = self.selected_date.as_ref(){ html!{
</p> <><p class="title has-text-link">
<p class="subtitle"> {&d.name}
{"Am 28.02.23"} </p><p class="subtitle">
</p> {&d.subtitle}
</p><p class="subtitle">
{"Am "}{d.start_time.format("%d.%m.%Y")}
</p></>}}else{html!(<p class="title has-text-link">{"Elternsprechtag"}</p>)}}
</div> </div>
</section> </section>
<div class="container"> <div class="container">
<div class="section"> <div class="section">
{ {
if let Some(_saved) = self.successfully_saved.as_ref(){self.view_dank_dialog(ctx)} else if self.nutzer.is_none(){ if let Some(dates) = self.dates.as_ref(){
self.view_eingabe_daten(ctx) if let Some(date) = self.selected_date.as_ref(){
} if let Some(_saved) = self.successfully_saved.as_ref(){
else self.view_dank_dialog(ctx)
{ } else if self.nutzer.is_none(){
self.view_auswahl_termine(ctx) self.view_eingabe_daten(ctx)
} }
else
{
self.view_auswahl_termine(ctx)
}
} else {
self.view_auswahl_date(dates, ctx)
}
}else{html!(<h1>{"Loading"}</h1>)}
} }
</div> </div>
</div> </div>
@ -192,6 +218,35 @@ impl Component for App {
} }
impl App { impl App {
fn view_auswahl_date(&self, dates: &Dates, ctx: &Context<Self>) -> Html {
let onchange = ctx.link().callback(|e: Event| {
let input: HtmlInputElement = e.target_unchecked_into();
Msg::SelectDate(input.value().parse().unwrap())
});
html! {
<div class="columns is-centered">
<div class="column is-half">
<div class="notification is-light">
<figure class="image container is-128x128" id="headerlogo">
<img src="/logoheader.png" />
</figure>
<div class="box mt-3 is-light">
<p>{"Anmeldung zum Elternsprechtag!"}</p><p>{"Bitte wählen Sie den Sprechtag zu welchem Sie sich anmelden möchten:"}</p>
</div>
<div class="select is-rounded is-fullwidth">
<select onchange={onchange}>
<option selected=true value="--">{"Bitte wählen Sie einen Termin"}</option>
{dates.iter().map(|dt|html!{
<option value={dt.id.to_string()}>{&dt.name}{" "}{&dt.start_time.format("%d.%m.%Y")}</option>
}).collect::<Html>()}
</select>
</div>
</div>
</div>
</div>
}
}
fn view_eingabe_daten(&self, ctx: &Context<Self>) -> Html { fn view_eingabe_daten(&self, ctx: &Context<Self>) -> Html {
html! { <div class="columns is-centered"> html! { <div class="columns is-centered">
<div class="column is-half"> <div class="column is-half">

View File

@ -1,5 +1,5 @@
use gloo::net::http::Request; use gloo::net::http::Request;
use terminwahl_typen::{Nutzer, PlannedAppointment, RequestState}; use terminwahl_typen::{IdType, Nutzer, PlannedAppointment, RequestState};
use crate::Msg; use crate::Msg;
@ -15,9 +15,9 @@ pub async fn fetch_dates() -> Result<Msg, Msg> {
Ok(Msg::ReceivedDates(response)) Ok(Msg::ReceivedDates(response))
} }
pub async fn fetch_teachers() -> Result<Msg, Msg> { pub async fn fetch_teachers(id: IdType) -> Result<Msg, Msg> {
// Send the request to the specified URL. // Send the request to the specified URL.
let response = Request::get("/get/teachers/1").send().await; let response = Request::get(&format!("/get/teachers/{}", id)).send().await;
// Return the ZuordnungMessage with the given network object and the response. // Return the ZuordnungMessage with the given network object and the response.
let response = response let response = response
.map_err(|_| Msg::AppointmentsSent(RequestState::Error))? .map_err(|_| Msg::AppointmentsSent(RequestState::Error))?
@ -27,9 +27,9 @@ pub async fn fetch_teachers() -> Result<Msg, Msg> {
Ok(Msg::ReceivedTeachers(response)) Ok(Msg::ReceivedTeachers(response))
} }
pub async fn fetch_slots() -> Result<Msg, Msg> { pub async fn fetch_slots(id: IdType) -> Result<Msg, Msg> {
// Send the request to the specified URL. // Send the request to the specified URL.
let response = Request::get("/get/slots/1").send().await; let response = Request::get(&format!("/get/slots/{}", id)).send().await;
// Return the ZuordnungMessage with the given network object and the response. // Return the ZuordnungMessage with the given network object and the response.
let response = response let response = response
.map_err(|_| Msg::AppointmentsSent(RequestState::Error))? .map_err(|_| Msg::AppointmentsSent(RequestState::Error))?

View File

@ -88,11 +88,11 @@ impl Nutzer {
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Date { pub struct Date {
id: IdType, pub id: IdType,
name: String, pub name: String,
subtitle: String, pub subtitle: String,
start_time: NaiveDateTime, pub start_time: NaiveDateTime,
end_time: NaiveDateTime, pub end_time: NaiveDateTime,
} }
pub type Dates = Vec<Date>; pub type Dates = Vec<Date>;