mentorenwahl/frontend/src/routes/home/student_vote.rs

221 lines
7.8 KiB
Rust

use graphql_client::reqwest::post_graphql;
use std::collections::HashMap;
use yew::prelude::*;
use crate::components;
use crate::graphql;
pub enum Msg {
DoneFetchingCanVote {
errors: Option<Vec<String>>,
can_vote: bool,
},
DoneFetchingConfig {
errors: Option<Vec<String>>,
min: usize,
},
DoneFetchingTeachers {
errors: Option<Vec<String>>,
teachers: Vec<graphql::queries::teachers::teachers::TeachersTeachers>,
},
RadioSelect {
priority: usize,
teacher: i64,
},
Submit,
}
#[derive(Properties, PartialEq)]
pub struct StudentVoteProps {
pub token: String,
}
pub struct StudentVote {
fetching: bool,
can_vote: bool,
errors: Option<Vec<String>>,
min: usize,
teachers: Option<Vec<graphql::queries::teachers::teachers::TeachersTeachers>>,
votes: HashMap<usize, Option<i64>>,
}
impl Component for StudentVote {
type Message = Msg;
type Properties = StudentVoteProps;
fn create(ctx: &Context<Self>) -> Self {
let client = graphql::client(Some(&ctx.props().token)).unwrap();
ctx.link().send_future(async move {
let can_vote_response =
post_graphql::<graphql::queries::students_can_vote::StudentsCanVote, _>(
&client,
graphql::URL.as_str(),
graphql::queries::students_can_vote::students_can_vote::Variables,
)
.await
.unwrap();
Msg::DoneFetchingCanVote {
errors: components::graphql_errors::convert(can_vote_response.errors),
can_vote: can_vote_response.data.unwrap().students_can_vote,
}
});
Self {
fetching: true,
can_vote: false,
errors: None,
min: 0,
teachers: None,
votes: HashMap::new(),
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::DoneFetchingCanVote { errors, can_vote } => {
self.errors = errors;
self.can_vote = can_vote;
let client = graphql::client(Some(&ctx.props().token)).unwrap();
ctx.link().send_future(async move {
let response = post_graphql::<graphql::queries::config::Config, _>(
&client,
graphql::URL.as_str(),
graphql::queries::config::config::Variables,
)
.await
.unwrap();
Msg::DoneFetchingConfig {
errors: components::graphql_errors::convert(response.errors),
min: response
.data
.unwrap()
.config
.minimum_teacher_selection_count as usize,
}
});
true
}
Msg::DoneFetchingConfig { errors, min } => {
self.errors = errors;
self.min = min;
let client = graphql::client(Some(&ctx.props().token)).unwrap();
ctx.link().send_future(async move {
let response = post_graphql::<graphql::queries::teachers::Teachers, _>(
&client,
graphql::URL.as_str(),
graphql::queries::teachers::teachers::Variables,
)
.await
.unwrap();
Msg::DoneFetchingTeachers {
errors: components::graphql_errors::convert(response.errors),
teachers: response.data.unwrap().teachers,
}
});
true
}
Msg::DoneFetchingTeachers { errors, teachers } => {
self.fetching = false;
self.errors = errors;
self.teachers = Some(teachers);
true
}
Msg::RadioSelect { priority, teacher } => {
self.votes.insert(priority, Some(teacher));
for (p, t) in self.votes.iter_mut() {
if *p > priority && *t == Some(teacher) {
*t = None;
}
}
true
}
Msg::Submit => {
log::debug!("{:?}", self.votes);
false
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
if self.fetching {
html! {
<p>{ "Fetching..." }</p>
}
} else {
let onsubmit = ctx.link().callback(|e: FocusEvent| {
e.prevent_default();
Msg::Submit
});
let mut teachers: Vec<i64> = vec![];
html! {
<>
<h3>{ "Wähle deine Wunschmentoren aus:" }</h3>
<form {onsubmit}>
{ for (0..self.min).map(|i| {
let curr_t = self.votes.get(&i);
if let Some(te) = curr_t {
if let Some(t) = te {
teachers.push(*t);
}
}
let name = format!("mentors_{}", i);
html! {
<>
<fieldset>
<legend>{ format!("{}. Wahl", i + 1) }</legend>
{ for self.teachers.as_ref().unwrap().iter().enumerate().filter_map(|(j, t)| {
let checked = curr_t == Some(&Some(t.id));
if teachers.contains(&t.id) && !checked {
None
} else {
let id = format!("{}_{}", name, j);
let teacher_id = t.id;
let onchange = ctx.link().callback(move |_| Msg::RadioSelect { priority: i, teacher: teacher_id });
Some(html! {
<div>
<input
type="radio"
id={id.to_owned()}
name={name.to_owned()}
value={t.user.name.to_owned()}
required=true
{onchange}
{checked}
/>
<label for={id}>{ &t.user.name }</label>
</div>
})
}
}) }
</fieldset>
if i < self.min - 1 {
<br />
}
</>
}
}) }
<div>
<button type="submit">{ "Submit" }</button>
</div>
</form>
</>
}
}
}
}