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>, can_vote: bool, }, DoneFetchingConfig { errors: Option>, min: usize, }, DoneFetchingTeachers { errors: Option>, teachers: Vec, }, RadioSelect { priority: usize, teacher: i64, }, Submit, Vote(Option>), AddSlot, RemoveSlot, Reset, } #[derive(Properties, PartialEq)] pub struct StudentVoteProps { pub token: String, pub onvoted: Callback<()>, } pub struct StudentVote { fetching: bool, can_vote: bool, errors: Option>, min: usize, slots: usize, teachers: Vec, votes: HashMap>, } impl Component for StudentVote { type Message = Msg; type Properties = StudentVoteProps; fn create(ctx: &Context) -> Self { let client = graphql::client(Some(&ctx.props().token)).unwrap(); ctx.link().send_future(async move { let can_vote_response = post_graphql::( &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, slots: 0, teachers: vec![], votes: HashMap::new(), } } fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { match msg { Msg::DoneFetchingCanVote { errors, can_vote } => { self.errors = errors; self.can_vote = can_vote; if self.can_vote { let client = graphql::client(Some(&ctx.props().token)).unwrap(); ctx.link().send_future(async move { let response = post_graphql::( &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, } }); } else { self.fetching = false; } true } Msg::DoneFetchingConfig { errors, min } => { self.errors = errors; self.min = min; self.slots = self.min; let client = graphql::client(Some(&ctx.props().token)).unwrap(); ctx.link().send_future(async move { let response = post_graphql::( &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 = 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 => { let client = graphql::client(Some(&ctx.props().token)).unwrap(); let mut ids: Vec<(&usize, i64)> = self .votes .iter() .filter_map(|(p, t)| t.map(|x| (p, x))) .collect(); ids.sort_by(|a, b| a.0.cmp(b.0)); let teacher_ids: Vec = ids.into_iter().map(|(_, t)| t).collect(); ctx.link().send_future(async move { let response = post_graphql::( &client, graphql::URL.as_str(), graphql::mutations::vote::vote::Variables { teacher_ids }, ) .await .unwrap(); log::debug!("{:?}", response.data.unwrap().create_vote.unwrap()); Msg::Vote(components::graphql_errors::convert(response.errors)) }); false } Msg::Vote(errors) => { self.errors = errors; if self.errors.is_none() { ctx.props().onvoted.emit(()); false } else { true } } Msg::AddSlot => { if self.slots < self.teachers.len() { self.slots += 1; true } else { false } } Msg::RemoveSlot => { if self.slots > self.min { self.votes.remove(&(self.slots - 1)); self.slots -= 1; true } else { false } } Msg::Reset => { self.slots = self.min; true } } } fn view(&self, ctx: &Context) -> Html { if self.fetching { html! {

{ "Fetching..." }

} } else if !self.can_vote { html! {

{ "Noch nicht erlaubt zu wählen." }

} } else { let onsubmit = ctx.link().callback(|e: FocusEvent| { e.prevent_default(); Msg::Submit }); let mut teachers: Vec = vec![]; html! { <>

{ "Wähle deine Wunschmentoren aus:" }

{ for (0..self.slots).map(|i| { let curr_t = self.votes.get(&i); if let Some(Some(t)) = curr_t { teachers.push(*t); } let name = format!("mentors_{}", i); html! { <>
{ format!("{}. Wahl", i + 1) } { for self.teachers.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! {
}) } }) }
if i < self.slots - 1 {
} } }) }
} } } }