Zusätzliche modale anzeigen, sowie erste Zuweisung
This commit is contained in:
parent
4d46e985a5
commit
8a8030dc2b
@ -16,7 +16,7 @@ pub struct GemüseAnfrage {
|
|||||||
pub user: Benutzer,
|
pub user: Benutzer,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Hash, Eq)]
|
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Hash, Eq, Copy)]
|
||||||
pub struct VpWunsch {
|
pub struct VpWunsch {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub anfrage_id: i32,
|
pub anfrage_id: i32,
|
||||||
|
264
src/zuordnung.rs
264
src/zuordnung.rs
@ -39,6 +39,10 @@ pub enum ZuordnungMessage {
|
|||||||
ShowDialog(Dialog),
|
ShowDialog(Dialog),
|
||||||
/// A message indicating that the current dialog should be hidden.
|
/// A message indicating that the current dialog should be hidden.
|
||||||
HideDialog,
|
HideDialog,
|
||||||
|
AssignAll {
|
||||||
|
verteilpunkt: Verteilpunkt,
|
||||||
|
mitgliedschaften: Vec<VpWunsch>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Dialog {
|
pub struct Dialog {
|
||||||
@ -47,7 +51,9 @@ pub struct Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum DialogContent {
|
pub enum DialogContent {
|
||||||
Wunschliste(Vec<VpWunsch>),
|
Wunschliste(Verteilpunkt, Vec<VpWunsch>),
|
||||||
|
Vorjahr(Vec<VpZuordnung>),
|
||||||
|
Geplant(HashMap<i32, GeplanteVpZuordnung>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, PartialEq, Default)]
|
#[derive(Properties, PartialEq, Default)]
|
||||||
@ -66,7 +72,7 @@ pub struct ZuordnungApp {
|
|||||||
/// The assignments made for the previous year.
|
/// The assignments made for the previous year.
|
||||||
zuordnung_vorjahr: Option<JahresVpZuordnung>,
|
zuordnung_vorjahr: Option<JahresVpZuordnung>,
|
||||||
/// The planned assignments for the current year.
|
/// The planned assignments for the current year.
|
||||||
geplante_zuordnung: HashMap<i32, GeplanteVpZuordnung>,
|
geplante_zuordnung: HashMap<i32, HashMap<i32, GeplanteVpZuordnung>>,
|
||||||
/// The currently displayed dialog.
|
/// The currently displayed dialog.
|
||||||
dialog: Option<Dialog>,
|
dialog: Option<Dialog>,
|
||||||
}
|
}
|
||||||
@ -137,6 +143,12 @@ impl Component for ZuordnungApp {
|
|||||||
NetworkObjekte::Verteilpunkt(v) => {
|
NetworkObjekte::Verteilpunkt(v) => {
|
||||||
log!("Verteilpunkte geparsed");
|
log!("Verteilpunkte geparsed");
|
||||||
self.verteilpunkte = v;
|
self.verteilpunkte = v;
|
||||||
|
for vp in self.verteilpunkte.iter() {
|
||||||
|
log!(format!(
|
||||||
|
"{:?}",
|
||||||
|
self.geplante_zuordnung.insert(*vp.0, HashMap::new())
|
||||||
|
));
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
NetworkObjekte::Wunsch(v) => {
|
NetworkObjekte::Wunsch(v) => {
|
||||||
@ -163,6 +175,26 @@ impl Component for ZuordnungApp {
|
|||||||
self.dialog = None;
|
self.dialog = None;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
ZuordnungMessage::AssignAll {
|
||||||
|
verteilpunkt,
|
||||||
|
mitgliedschaften,
|
||||||
|
} => {
|
||||||
|
log!(format!("{:?}", mitgliedschaften));
|
||||||
|
if let Some(liste) = self.geplante_zuordnung.get_mut(&verteilpunkt.id) {
|
||||||
|
for m in mitgliedschaften {
|
||||||
|
liste.insert(
|
||||||
|
m.anfrage_id,
|
||||||
|
GeplanteVpZuordnung {
|
||||||
|
mitgliedschaft_id: m.anfrage_id,
|
||||||
|
user_mitgliedsnummer: m.user_id,
|
||||||
|
verteilpunkt_id: m.verteilpunkt_id,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
log!(format!("{:?}", self.geplante_zuordnung));
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,8 +217,8 @@ impl Component for ZuordnungApp {
|
|||||||
.map(|(id, v)| html! {
|
.map(|(id, v)| html! {
|
||||||
<tr>
|
<tr>
|
||||||
<td>{self.verteilpunkt_name(v)}</td>
|
<td>{self.verteilpunkt_name(v)}</td>
|
||||||
<td>{self.aktuelle_mitglieder(v, &self.zuordnung_vorjahr)}</td>
|
<td>{self.aktuelle_mitglieder(v, ctx)}</td>
|
||||||
<td>{self.zukünftige_mitglieder(v)}</td>
|
<td>{self.zukünftige_mitglieder(v, ctx)}</td>
|
||||||
{self.count_wünsche(*id, ctx)}
|
{self.count_wünsche(*id, ctx)}
|
||||||
</tr>
|
</tr>
|
||||||
})
|
})
|
||||||
@ -198,6 +230,9 @@ impl Component for ZuordnungApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ZuordnungApp {
|
impl ZuordnungApp {
|
||||||
|
/**
|
||||||
|
Erstelle Die Tabellenzellen für die 1. 2. und n. Wünsche.
|
||||||
|
*/
|
||||||
fn count_wünsche(&self, verteilpunkt_id: i32, ctx: &yew::Context<ZuordnungApp>) -> Html {
|
fn count_wünsche(&self, verteilpunkt_id: i32, ctx: &yew::Context<ZuordnungApp>) -> Html {
|
||||||
// Erst wenn die Wünsche geladen sind wird etwas angezeigt.
|
// Erst wenn die Wünsche geladen sind wird etwas angezeigt.
|
||||||
if let Some(wünsche) = &self.wünsche {
|
if let Some(wünsche) = &self.wünsche {
|
||||||
@ -206,6 +241,7 @@ impl ZuordnungApp {
|
|||||||
.wünsche
|
.wünsche
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, wunsch)| wunsch.verteilpunkt_id == verteilpunkt_id);
|
.filter(|(_, wunsch)| wunsch.verteilpunkt_id == verteilpunkt_id);
|
||||||
|
|
||||||
// A mapping from priority values to lists of wishes.
|
// A mapping from priority values to lists of wishes.
|
||||||
let counts: HashMap<i32, Vec<VpWunsch>> = wünsche
|
let counts: HashMap<i32, Vec<VpWunsch>> = wünsche
|
||||||
.prioritäten
|
.prioritäten
|
||||||
@ -214,11 +250,19 @@ impl ZuordnungApp {
|
|||||||
.collect();
|
.collect();
|
||||||
let counts: HashMap<i32, Vec<VpWunsch>> =
|
let counts: HashMap<i32, Vec<VpWunsch>> =
|
||||||
filtered.fold(counts, |mut counts, (_, wunsch)| {
|
filtered.fold(counts, |mut counts, (_, wunsch)| {
|
||||||
counts
|
if self
|
||||||
.entry(wunsch.prioritaet)
|
.geplante_zuordnung
|
||||||
.or_insert_with(Vec::new)
|
.iter()
|
||||||
.push(wunsch.clone());
|
.any(|(_, v)| v.contains_key(&wunsch.anfrage_id))
|
||||||
counts
|
{
|
||||||
|
counts
|
||||||
|
} else {
|
||||||
|
counts
|
||||||
|
.entry(wunsch.prioritaet)
|
||||||
|
.or_insert_with(Vec::new)
|
||||||
|
.push(*wunsch);
|
||||||
|
counts
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// sortiere nach Priorität
|
// sortiere nach Priorität
|
||||||
let sorted_and_grouped_by_priority = counts.into_iter().sorted_by_key(|x| x.0);
|
let sorted_and_grouped_by_priority = counts.into_iter().sorted_by_key(|x| x.0);
|
||||||
@ -230,14 +274,12 @@ impl ZuordnungApp {
|
|||||||
let verteilpunkte = self.verteilpunkte.clone();
|
let verteilpunkte = self.verteilpunkte.clone();
|
||||||
|
|
||||||
let onclick = ctx.link().callback(move |_| {
|
let onclick = ctx.link().callback(move |_| {
|
||||||
|
let vp = verteilpunkte
|
||||||
|
.get(&verteilpunkt_id)
|
||||||
|
.expect("should allways be there");
|
||||||
ZuordnungMessage::ShowDialog(Dialog {
|
ZuordnungMessage::ShowDialog(Dialog {
|
||||||
title: {
|
title: { format!("Wünsche für {}", vp.name) },
|
||||||
let vp = verteilpunkte
|
content: DialogContent::Wunschliste(vp.clone(), wunsch.clone()),
|
||||||
.get(&verteilpunkt_id)
|
|
||||||
.expect("should allways be there");
|
|
||||||
format!("Wünsche für {}", vp.name)
|
|
||||||
},
|
|
||||||
content: DialogContent::Wunschliste(wunsch.clone()),
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
html! {<td><b {onclick}>{length}</b></td>}
|
html! {<td><b {onclick}>{length}</b></td>}
|
||||||
@ -294,69 +336,112 @@ impl ZuordnungApp {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
Count the number of items in the zuordnungen map with the matching verteilpunkt_id
|
||||||
|
*/
|
||||||
|
fn count_zuordnungen(
|
||||||
|
v: &Verteilpunkt,
|
||||||
|
zuordnungen: &HashMap<i32, VpZuordnung>,
|
||||||
|
) -> Vec<VpZuordnung> {
|
||||||
|
zuordnungen
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(_, zuo)| {
|
||||||
|
if v.id == zuo.verteilpunkt_id {
|
||||||
|
Some(zuo.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn aktuelle_mitglieder(&self, v: &Verteilpunkt, z: &Option<JahresVpZuordnung>) -> Html {
|
fn aktuelle_mitglieder(
|
||||||
// Count the number of items in the zuordnungen map with the matching verteilpunkt_id
|
&self,
|
||||||
fn count_zuordnungen(v: &Verteilpunkt, zuordnungen: &HashMap<i32, VpZuordnung>) -> usize {
|
verteilpunkt: &Verteilpunkt,
|
||||||
zuordnungen
|
ctx: &yew::Context<ZuordnungApp>,
|
||||||
.iter()
|
) -> Html {
|
||||||
.filter(|(_, zuo)| v.id == zuo.verteilpunkt_id)
|
match &self.zuordnung_vorjahr {
|
||||||
.count()
|
|
||||||
}
|
|
||||||
|
|
||||||
match z {
|
|
||||||
Some(z) => {
|
Some(z) => {
|
||||||
// Render the count and the kapazitaet as "X/Y"
|
// Render the count and the kapazitaet as "X/Y"
|
||||||
let count = count_zuordnungen(v, &z.zuordnungen);
|
let liste = Self::count_zuordnungen(verteilpunkt, &z.zuordnungen);
|
||||||
html! {<>{count}{"/"} {v.kapazitaet}</>}
|
let count = liste.len();
|
||||||
|
let title = format!("Aktuelle Mitglieder am VP {}", verteilpunkt.name);
|
||||||
|
let onclick = ctx.link().callback(move |_| {
|
||||||
|
ZuordnungMessage::ShowDialog(Dialog {
|
||||||
|
title: title.clone(),
|
||||||
|
content: DialogContent::Vorjahr(liste.clone()),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
html! {<span {onclick}>{count}{"/"} {verteilpunkt.kapazitaet}</span>}
|
||||||
}
|
}
|
||||||
None => html!(),
|
None => html!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
fn zukünftige_mitglieder(&self, verteilpunkt: &Verteilpunkt) -> Html {
|
Count the number of items in the zuordnungen map with the matching verteilpunkt_id
|
||||||
|
*/
|
||||||
|
fn count_geplante_zuordnungen(
|
||||||
|
v: &Verteilpunkt,
|
||||||
|
zuordnungen: &HashMap<i32, HashMap<i32, GeplanteVpZuordnung>>,
|
||||||
|
) -> HashMap<i32, GeplanteVpZuordnung> {
|
||||||
|
zuordnungen.get(&v.id).cloned().unwrap_or_default()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Zeige die Anzahl und Kappazität der zukünftigen Mitglieder an diesem Verteilpunkt.
|
||||||
|
*/
|
||||||
|
fn zukünftige_mitglieder(
|
||||||
|
&self,
|
||||||
|
verteilpunkt: &Verteilpunkt,
|
||||||
|
ctx: &yew::Context<ZuordnungApp>,
|
||||||
|
) -> Html {
|
||||||
// Count the number of items in the z map with the matching verteilpunkt_id
|
// Count the number of items in the z map with the matching verteilpunkt_id
|
||||||
let count = &self
|
let liste = Self::count_geplante_zuordnungen(verteilpunkt, &self.geplante_zuordnung);
|
||||||
.geplante_zuordnung
|
let count = liste.len();
|
||||||
.iter()
|
let title = format!("Geplante Mitglieder am VP {}", verteilpunkt.name);
|
||||||
.filter(|(_, zuo)| verteilpunkt.id == zuo.verteilpunkt_id)
|
let onclick = ctx.link().callback(move |_| {
|
||||||
.count();
|
ZuordnungMessage::ShowDialog(Dialog {
|
||||||
|
title: title.clone(),
|
||||||
|
content: DialogContent::Geplant(liste.clone()),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
// Render the count and the kapazitaet as "X/Y"
|
// Render the count and the kapazitaet as "X/Y"
|
||||||
html! {<>{count}{"/"} {verteilpunkt.kapazitaet}</>}
|
html! {<div {onclick}>{count}{"/"} {verteilpunkt.kapazitaet}</div>}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_dialog(&self, ctx: &yew::Context<Self>) -> Html {
|
fn show_dialog(&self, ctx: &yew::Context<Self>) -> Html {
|
||||||
match &self.dialog {
|
match &self.dialog {
|
||||||
Some(dialog) => {
|
Some(dialog) => {
|
||||||
// Create a callback that calls the HideDialog function when triggered
|
|
||||||
let onclick = ctx.link().callback(|_| ZuordnungMessage::HideDialog);
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
// Render the dialog container with the onclick callback attached
|
// Render the dialog container with the onclick callback attached
|
||||||
<div class="modal_wasm" {onclick}>
|
<div class="modal show" tabindex="-1" role="dialog" style="display:block;" onclick={ctx.link().callback(|_| ZuordnungMessage::HideDialog)}>
|
||||||
<div class="container">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="body">
|
<div class="modal-content">
|
||||||
// Render the dialog title
|
<div class="modal-header">
|
||||||
<h3>{&dialog.title}</h3>
|
<h5 class="modal-title">{&dialog.title}</h5>
|
||||||
// Render the dialog content
|
<button type="button" class="btn btn-link link-secondary" data-dismiss="modal" aria-label="Close" onclick={ctx.link().callback(|_| ZuordnungMessage::HideDialog)}>
|
||||||
{self.show_dialog_content(&dialog.content)}
|
<span aria-hidden="true"><i class="bi bi-x-circle-fill"></i></span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{self.show_dialog_content(&dialog.content, ctx)}
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => html! {},
|
None => html! {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_dialog_content(&self, content: &DialogContent) -> Html {
|
fn show_dialog_content(&self, content: &DialogContent, ctx: &yew::Context<Self>) -> Html {
|
||||||
match content {
|
// Generate the lines and the buttons at the bottom for the different dialogs
|
||||||
DialogContent::Wunschliste(content) => {
|
let (lines, buttons) = match content {
|
||||||
|
DialogContent::Wunschliste(vp, content) => {
|
||||||
let mut htmlnodes = Vec::new();
|
let mut htmlnodes = Vec::new();
|
||||||
|
|
||||||
// Iterate over each wish in the list
|
// Iterate over each wish in the list
|
||||||
for wunsch in content {
|
for wunsch in content.clone() {
|
||||||
// Find the user associated with this wish
|
// Find the user associated with this wish
|
||||||
let user = match &self.user {
|
let user = match &self.user {
|
||||||
Some(users) => match users.get(&wunsch.user_id) {
|
Some(users) => match users.get(&wunsch.user_id) {
|
||||||
@ -368,11 +453,80 @@ impl ZuordnungApp {
|
|||||||
|
|
||||||
// Append the user's first and last name to the HTML
|
// Append the user's first and last name to the HTML
|
||||||
htmlnodes
|
htmlnodes
|
||||||
.push(html! {<tr><td>{&user.vorname}</td><td>{&user.nachname}</td></tr>});
|
.push(html! {<tr><td scope="col">{&user.vorname}</td><td scope="col">{&user.nachname}</td></tr>});
|
||||||
|
}
|
||||||
|
let lines = html! {{ htmlnodes.into_iter().collect::<Html>() }};
|
||||||
|
let vp = vp.clone();
|
||||||
|
let content = content.clone();
|
||||||
|
let onclick = ctx.link().callback(move |_| {
|
||||||
|
let verteilpunkt = vp.clone();
|
||||||
|
let mitgliedschaften = content.clone();
|
||||||
|
ZuordnungMessage::AssignAll {
|
||||||
|
verteilpunkt,
|
||||||
|
mitgliedschaften,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let buttons = html! {<>
|
||||||
|
<button type="button" class="btn btn-primary" {onclick}>{"Alle zuweisen"}</button>
|
||||||
|
</>};
|
||||||
|
(lines, buttons)
|
||||||
|
}
|
||||||
|
DialogContent::Vorjahr(content) => {
|
||||||
|
let mut htmlnodes = Vec::new();
|
||||||
|
|
||||||
|
// Iterate over each wish in the list
|
||||||
|
for mitgliedschaft in content {
|
||||||
|
// Find the user associated with this wish
|
||||||
|
let user = match &self.user {
|
||||||
|
Some(users) => match users.get(&mitgliedschaft.user_mitgliedsnummer) {
|
||||||
|
Some(user) => user,
|
||||||
|
None => continue, // Skip this wish if the user is not found
|
||||||
|
},
|
||||||
|
None => continue, // Skip this wish if self.user is not set
|
||||||
|
};
|
||||||
|
|
||||||
|
// Append the user's first and last name to the HTML
|
||||||
|
htmlnodes
|
||||||
|
.push(html! {<tr><td scope="col">{&user.vorname}</td><td scope="col">{&user.nachname}</td></tr>});
|
||||||
}
|
}
|
||||||
|
|
||||||
html! {{ htmlnodes.into_iter().collect::<Html>() }}
|
(html! {{ htmlnodes.into_iter().collect::<Html>() }}, html!())
|
||||||
}
|
}
|
||||||
|
DialogContent::Geplant(content) => {
|
||||||
|
let mut htmlnodes = Vec::new();
|
||||||
|
|
||||||
|
// Iterate over each wish in the list
|
||||||
|
for mitgliedschaft in content.values() {
|
||||||
|
// Find the user associated with this wish
|
||||||
|
let user = match &self.user {
|
||||||
|
Some(users) => match users.get(&mitgliedschaft.user_mitgliedsnummer) {
|
||||||
|
Some(user) => user,
|
||||||
|
None => continue, // Skip this wish if the user is not found
|
||||||
|
},
|
||||||
|
None => continue, // Skip this wish if self.user is not set
|
||||||
|
};
|
||||||
|
|
||||||
|
// Append the user's first and last name to the HTML
|
||||||
|
htmlnodes
|
||||||
|
.push(html! {<tr><td scope="col">{&user.vorname}</td><td scope="col">{&user.nachname}</td></tr>});
|
||||||
|
}
|
||||||
|
|
||||||
|
(html! {{ htmlnodes.into_iter().collect::<Html>() }}, html!())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
html! {
|
||||||
|
<>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-striped align-middle">
|
||||||
|
<thead><tr><th scope="col">{"Vorname"}</th><th scope="col">{"Nachname"}</th></tr></thead>
|
||||||
|
<tbody>{lines}</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
{buttons}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user