From cfcc57775fbf1bc152b7050db95e6ae27a5f998f Mon Sep 17 00:00:00 2001 From: JohanGrims Date: Sun, 15 Dec 2024 01:00:14 +0100 Subject: [PATCH 1/2] Add power-search functionality to Assign component with advanced filtering options --- src/admin/vote/Assign.jsx | 294 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 282 insertions(+), 12 deletions(-) diff --git a/src/admin/vote/Assign.jsx b/src/admin/vote/Assign.jsx index 9bc6023..d259af9 100644 --- a/src/admin/vote/Assign.jsx +++ b/src/admin/vote/Assign.jsx @@ -11,6 +11,8 @@ export default function Assign() { const [loading, setLoading] = React.useState(false); const [mode, setMode] = React.useState("by-option"); + const [search, setSearch] = React.useState(""); + const [rules, setRules] = React.useState([ { apply: "*", @@ -412,6 +414,61 @@ export default function Assign() { snackbar({ message: "Ergebnisse gespeichert." }); } + const filteredResults = () => { + if (mode === "power-search") { + return sortedResults.filter(([key]) => { + const choice = choices.find((choice) => choice.id === key); + const searchTerms = search.split(","); + return searchTerms.every((term) => { + const orTerms = term.split("|"); + return orTerms.some((orTerm) => { + const isNegative = orTerm.startsWith("!"); + const [key, value] = isNegative + ? orTerm.slice(1).split("=") + : orTerm.split("="); + if (value) { + if (key === "name") { + return isNegative + ? !choice.name.toLowerCase().includes(value.toLowerCase()) + : choice.name.toLowerCase().includes(value.toLowerCase()); + } + if (key === "grade") { + return isNegative + ? choice.grade !== value + : choice.grade === value; + } + if (key === "assignedTo") { + return isNegative + ? results[choice.id] !== value + : results[choice.id] === value; + } + if (key === "choice") { + return isNegative + ? results[choice.id] !== choice.selected[parseInt(value) - 1] + : results[choice.id] === choice.selected[parseInt(value) - 1]; + } + if (key === "selected") { + return isNegative + ? !choice.selected.includes(value) + : choice.selected.includes(value); + } + if (key.startsWith("selected[")) { + const index = parseInt(key.match(/\d+/)?.[0]) - 1; + if (isNaN(index)) return false; + if (!choice.selected[index]) return false; + return isNegative + ? choice.selected[index] !== value + : choice.selected[index] === value; + } + } + return false; + }); + }); + }); + } + return sortedResults; + }; + return (

- Hier sind die optimierten Zuordnungen der Schüler zu den Projekten. + {mode !== "power-search" && ( + <> + Insgesamt wurden {Object.keys(results).length} Schüler zugeordnet. + Davon haben:{" "} + {Object.entries(wahlenCounts).map(([wahl, count]) => ( + <> + {count} Schüler die{" "} + {wahl === "1" + ? "Erstwahlen, " + : `${wahl}. Wahlen${ + wahl === vote.selectCount.toString() ? "." : "," + } `} + + ))} + + )}

- Insgesamt wurden {Object.keys(results).length} Schüler zugeordnet. Davon - haben: -

+ setMode("power-search")} + unchecked-icon="query_stats" + > + Power-Search + setMode("by-option")}> Nach Projekt @@ -469,7 +538,208 @@ export default function Assign() { Nach Name -

+ {mode === "power-search" && ( +

+
+ Durchsuchen Sie die Ergebnisse mit folgenden Operatoren: +
    +
  • + name=Johan: Schüler deren Name Johan enthält +
  • +
  • + grade=12: Schüler der 12. Klasse +
  • +
  • + assignedTo=abc: Schüler die zu dem Projekt mit der + ID abc zugewiesen sind +
  • +
  • + choice=2: Schüler die zu ihrer Zweitwahl zugewiesen + sind +
  • +
  • + selected=abc: Schüler die das Projekt mit der ID + abc gewählt haben +
  • +
  • + selected[1]=abc: Schüler die das Projekt mit der ID + abc als Erstwahl gewählt haben +
  • +
+

+ Kombinieren Sie beliegbig viele Operatoren mit einem Komma:{" "} + + name=Johan,grade=12,assignedTo=xyz,choice=2,selected=abc + +
+ Schreiben Sie ein logisches Oder mit einem Pipe:{" "} + name=Johan|name=Max,grade=12 +
+ Nutzen Sie ein ! um die Bedingung zu negieren:{" "} + !grade=12 +

+

+ + + + Projekte anzeigen + +

+ + + + + + + + + + + {options.map((option, i) => ( + + + + + + + ))} + +
+ Projekt + + Maximalanzahl + + Belegte Plätze + + ID +
{option.title}{option.max} + { + sortedResults.filter( + ([, value]) => value === option.id + ).length + } + {option.id}
+
+ + +

+

+ { + setSearch(e.target.value); + }} + value={search} + > + + { + const filtered = filteredResults(); + const randomIndex = Math.floor(Math.random() * filtered.length); + + const element = document.querySelector( + `#power-search tr:nth-child(${ + randomIndex + 1 + })` + ); + + console.log(element); + element.scrollIntoView({ + behavior: "smooth", + }); + element.style.backgroundColor = + "rgb(var(--mdui-color-tertiary-container-dark))"; + setTimeout(() => { + element.style.backgroundColor = ""; + }, 5000); + }} + icon="casino--outlined" + > + +
+
+ + + + + + + {Array.from( + { length: vote.selectCount }, + (_, i) => i + 1 + ).map((i) => ( + + ))} + + + + {filteredResults().map(([key, value]) => ( + + + + + {choices + .find((choice) => choice.id === key) + .selected.map((selected, i) => ( + + ))} + + ))} + +
+ Name + + Klasse + + # + + Wahl {i} +
{choices.find((choice) => choice.id === key).name}{choices.find((choice) => choice.id === key).grade} + {choices.find((choice) => choice.id === key).listIndex} + { + if (selected === value) return; + const newResults = { ...results }; + newResults[key] = selected; + setResults(newResults); + const previousResults = { ...results }; + snackbar({ + message: "Änderung rückgängig machen", + action: "Rückgängig", + onActionClick: () => setResults(previousResults), + }); + }} + > + {selected === value && `✓ `} + {`${ + options.find((option) => option.id === selected) + .title + } (${ + sortedResults.filter( + ([, value]) => value === selected + ).length + }/${ + options.find((option) => option.id === selected).max + })`} +
+
+
+ )} {mode === "by-option" && ( Date: Sun, 15 Dec 2024 01:05:49 +0100 Subject: [PATCH 2/2] Assign component: populate unassigned choices with first selected option --- src/admin/vote/Assign.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/admin/vote/Assign.jsx b/src/admin/vote/Assign.jsx index d259af9..32eb96c 100644 --- a/src/admin/vote/Assign.jsx +++ b/src/admin/vote/Assign.jsx @@ -28,6 +28,12 @@ export default function Assign() { newResults[result.id] = result.result; }); + // assign other results to first choice + choices.forEach((choice) => { + if (!newResults[choice.id]) { + newResults[choice.id] = choice.selected[0]; + } + }); setResults(newResults); }