Bewerbungen der Modis bekommen eine eigene Spalte im Aufgabenbrett
Filipe: "ich will in dieser seite auch eine eigene kategorie fuer die
aufgaben wo die modis sich selbst bewerben. ich will dass man die
getrennt sieht. mach es richtig uebersichtlich."
WO SIE VORHER STANDEN, und warum das nicht reichte: nur auf dem
Vorlagenbrett, an der jeweiligen Karte. Das ist der richtige Ort zum
ENTSCHEIDEN -- man liest Aufgabe und Name nebeneinander. Es ist der
falsche Ort zum SEHEN: Wer morgens das Aufgabenbrett oeffnet, sieht
nicht, dass drei Leute auf eine Antwort warten, und das Vorlagenbrett
ist eine Seite weiter. Fuer den Modi gab es ueberhaupt keine Stelle,
an der stand "dein Wunsch ist angekommen".
DIE SPALTE STEHT GANZ VORN. Sie ist die einzige, in der jemand auf eine
ANTWORT wartet -- alle anderen zeigen Arbeit, die laeuft. Und sie
VERSCHWINDET, wenn nichts wartet: Eine leere Spalte "Bewerbungen"
stuende 360 Tage im Jahr im Weg, um an fuenf Tagen etwas zu sagen. Die
vier festen Spalten haben auch leer eine Aussage ("hier landet, was
fertig ist"); diese nicht.
WAS AUF DER KARTE STEHT: der TITEL der Vorlage (nicht ihr Schluessel),
wer sie uebernehmen moechte, und sein eigener Satz dazu -- als Zitat
gesetzt, mit Strich davor. Er gehoert ihm, nicht dem Brett. Ohne ihn
entscheidet man ueber einen Namen.
DER TITEL WIRD NACHGESCHLAGEN, NICHT MITGESPEICHERT. Er gehoert dem
Katalog; stuende er in der Bewerbungszeile, gaebe es zwei Wahrheiten,
und die aeltere gewinnt still, sobald jemand eine Vorlage umbenennt.
EIN EIGENER, KLEINER WEG statt eines Mitschleppens:
`/workspace/api/vorlagen/bewerbungen` liefert nur die Bewerbungen --
nicht den ganzen Katalog, der an `/workspace/api/vorlagen` haengt. Das
Brett zeichnet sich bei jedem Statuswechsel neu; der Katalog ist um ein
Vielfaches groesser als die Handvoll Bewerbungen.
WER ENTSCHEIDEN DARF, SAGT DER SERVER (`darf_entscheiden`) -- nicht der
Rollenname im Browser. `assets/js` bekommt jeder, der die Seite
oeffnet, und ein Rollenvergleich dort ist in diesem Haus allein diese
Woche dreimal veraltet. Bis die Antwort da ist, gilt `false`: lieber
einen Knopf zu spaet zeigen als einen, der eine Absage holt.
DIE FARBE IST NEU IM BRETT. Die vier vorhandenen stehen fuer einen
Arbeitsstand (grau, blau, gelb, gruen); hier wartet niemand auf Arbeit,
sondern auf eine Entscheidung. Kein Rot ("kaputt"), kein Gelb (heisst
schon "zur Freigabe") -- Violett, das im Chat seit gestern fuer "an
dich gerichtet" steht. Eine Sprache im Haus.
Geprueft: pruef-bewerbung-aufgaben 101 -> 111 Punkte. Darunter die drei
Gegenproben, ohne die "die Spalte ist da" nichts bewiese: ohne
Bewerbung gibt es sie NICHT, der Modi bekommt KEINE
Entscheidungsknoepfe (sondern "wartet auf Antwort"), und die Spalte
steht wirklich an erster Stelle. Dazu pruef-aufgabenbrett und
pruef-vorlagen (24), beide unveraendert gruen.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -788,6 +788,39 @@
|
||||
: alleAufgaben);
|
||||
}
|
||||
|
||||
/* ==== DIE BEWERBUNGEN DER MODIS (25.09.2026) ====================
|
||||
|
||||
Filipe: „ich will in dieser seite auch eine eigene kategorie fuer
|
||||
die aufgaben wo die modis sich selbst bewerben. ich will dass man
|
||||
die getrennt sieht. mach es richtig uebersichtlich."
|
||||
|
||||
SIE STANDEN BISHER NUR AUF DEM VORLAGENBRETT, an der jeweiligen
|
||||
Karte. Das ist der richtige Ort zum ENTSCHEIDEN -- man liest die
|
||||
Aufgabe und den Namen nebeneinander. Es ist aber der falsche Ort
|
||||
zum SEHEN: Wer morgens das Aufgabenbrett oeffnet, sieht nicht,
|
||||
dass drei Leute auf eine Antwort warten, und das Vorlagenbrett
|
||||
steht eine Seite weiter.
|
||||
|
||||
DER STAND WIRD GEMERKT, nicht bei jedem Zeichnen neu geholt: Das
|
||||
Brett zeichnet sich bei jedem Statuswechsel neu, und ein Abruf je
|
||||
Klick waere Last ohne Gegenwert. Geholt wird beim Laden und nach
|
||||
jeder Entscheidung -- also genau dann, wenn sich etwas aendert. */
|
||||
let bewerbungen = [];
|
||||
/* OB ICH ENTSCHEIDEN DARF, SAGT DER SERVER -- nicht der Rollenname.
|
||||
Bis die Antwort da ist, false: Lieber einen Knopf zu spaet zeigen
|
||||
als einen, der eine Absage holt. */
|
||||
let darfEntscheiden = false;
|
||||
|
||||
async function bewerbungenHolen() {
|
||||
try {
|
||||
const a = await hole('/workspace/api/vorlagen/bewerbungen');
|
||||
if (!a.ok) return;
|
||||
const d = await a.json();
|
||||
bewerbungen = d.bewerbungen || [];
|
||||
darfEntscheiden = d.darf_entscheiden === true;
|
||||
} catch { /* hole() hat schon gemeldet */ }
|
||||
}
|
||||
|
||||
function zeichne(aufgaben) {
|
||||
const brett = $('brett');
|
||||
brett.textContent = '';
|
||||
@@ -846,6 +879,40 @@
|
||||
brett.parentElement.insertBefore(band, brett);
|
||||
}
|
||||
|
||||
/* ==== DIE SPALTE STEHT GANZ VORN ==============================
|
||||
|
||||
Sie ist die einzige, in der jemand auf eine ANTWORT wartet --
|
||||
alle anderen zeigen Arbeit, die laeuft. Was auf eine Antwort
|
||||
wartet, gehoert an die Stelle, die man zuerst ansieht.
|
||||
|
||||
SIE VERSCHWINDET, WENN NICHTS WARTET. Eine leere Spalte
|
||||
„Bewerbungen" stuende 360 Tage im Jahr im Weg, um an fuenf
|
||||
Tagen etwas zu sagen -- anders als die vier festen Spalten, die
|
||||
auch leer eine Aussage haben („hier landet, was fertig ist").
|
||||
|
||||
DER MODI SIEHT SEINE EIGENE und nur die: Das entscheidet der
|
||||
Server (`vorlagenBewerbungenFuer`), nicht diese Datei. Fuer ihn
|
||||
ist sie die Antwort auf „ist mein Wunsch angekommen?" -- vorher
|
||||
gab es darauf nirgends eine. */
|
||||
if (bewerbungen.length) {
|
||||
const spalte = el('section', 'spalte spalte--bewerbung');
|
||||
spalte.dataset.status = 'beworben';
|
||||
spalte.dataset.leer = 'nein';
|
||||
spalte.style.setProperty('--wuchs', String(Math.min(bewerbungen.length, 6)));
|
||||
const kopf = el('h2', 'spalte__kopf');
|
||||
kopf.append(el('span', 'spalte__punkt'), el('span', null, 'Bewerbungen'),
|
||||
el('span', 'spalte__zahl', String(bewerbungen.length)));
|
||||
spalte.append(kopf);
|
||||
spalte.append(el('p', 'spalte__unter', darfEntscheiden
|
||||
? 'Modis möchten das übernehmen – du entscheidest'
|
||||
: 'Du hast dich beworben – DogFather oder die rechte Hand antworten'));
|
||||
|
||||
const kasten = el('div', 'spalte__karten');
|
||||
for (const b of bewerbungen) kasten.append(bewerbungsKarte(b));
|
||||
spalte.append(kasten);
|
||||
brett.append(spalte);
|
||||
}
|
||||
|
||||
for (const s of SPALTEN) {
|
||||
const eigene = gruppen.filter((g) => g.status === s.status);
|
||||
/* ZWEI ZAHLEN, UND SIE SAGEN VERSCHIEDENES: wie viele STUECKE
|
||||
@@ -923,6 +990,106 @@
|
||||
}
|
||||
}
|
||||
|
||||
/** Eine Karte fuer eine Bewerbung -- wer, worauf, und was er dazu
|
||||
* geschrieben hat.
|
||||
*
|
||||
* SIE SIEHT AUS WIE DIE ANDEREN KARTEN und ist doch eine andere
|
||||
* Sache: Es gibt sie noch nicht als Aufgabe. Deshalb dieselbe Form
|
||||
* (man soll das Brett lesen koennen, ohne umzulernen) und ein
|
||||
* eigenes Merkmal `data-art="bewerbung"` fuer die Farbe.
|
||||
*
|
||||
* DIE ZWEI KNOEPFE STEHEN NUR BEI DENEN, DIE ENTSCHEIDEN. Der Modi
|
||||
* sieht stattdessen einen Satz: Sein Wunsch ist angekommen. Ein
|
||||
* Knopf, der eine Absage holt, ist schlimmer als keiner.
|
||||
*/
|
||||
function bewerbungsKarte(b) {
|
||||
const k = el('article', 'karte karte--bewerbung');
|
||||
k.dataset.art = 'bewerbung';
|
||||
|
||||
const kopf = el('div', 'karte__kopf');
|
||||
kopf.append(el('h3', 'karte__titel', b.titel));
|
||||
k.append(kopf);
|
||||
|
||||
/* WER ES SEIN MOECHTE steht gross, nicht klein: Ueber die Person
|
||||
wird hier entschieden, nicht ueber den Titel. Den kennt man
|
||||
vom Vorlagenbrett. */
|
||||
const wer = el('p', 'karte__wer');
|
||||
wer.append(el('strong', null, b.selbst ? 'Du' : b.person_name));
|
||||
wer.append(document.createTextNode(b.selbst
|
||||
? ' hast dich beworben' : ' möchte das übernehmen'));
|
||||
k.append(wer);
|
||||
|
||||
if (b.text) {
|
||||
/* SEIN SATZ DAZU, als Zitat gesetzt -- er gehoert ihm, nicht
|
||||
dem Brett. Ohne ihn entscheidet man ueber einen Namen. */
|
||||
const zitat = el('p', 'karte__bwort');
|
||||
zitat.textContent = b.text;
|
||||
k.append(zitat);
|
||||
}
|
||||
|
||||
const fuss = el('div', 'karte__fuss');
|
||||
if (darfEntscheiden) {
|
||||
const ja = el('button', 'knopf knopf--klein', 'Annehmen');
|
||||
ja.type = 'button';
|
||||
ja.addEventListener('click', () => bewerbungEntscheiden(ja, b, true));
|
||||
const nein = el('button', 'knopf knopf--klein karte__ablehnen', 'Ablehnen');
|
||||
nein.type = 'button';
|
||||
nein.addEventListener('click', () => bewerbungEntscheiden(nein, b, false));
|
||||
fuss.append(ja, nein);
|
||||
} else {
|
||||
fuss.append(el('span', 'karte__warte', 'wartet auf Antwort'));
|
||||
}
|
||||
k.append(fuss);
|
||||
return k;
|
||||
}
|
||||
|
||||
/** Annehmen oder ablehnen -- mit der Moeglichkeit, ein Wort
|
||||
* dazuzuschreiben.
|
||||
*
|
||||
* DIE NOTIZ IST FREIWILLIG, aber sie wird GEFRAGT: Eine Absage ohne
|
||||
* Grund ist die Sorte Antwort, nach der man im Chat nachfragt --
|
||||
* und dann steht dieselbe Erklaerung doppelt. Abbrechen des
|
||||
* Dialogs bricht die ganze Handlung ab; sonst haette man aus
|
||||
* Versehen zugesagt, weil man das Fenster wegklicken wollte.
|
||||
*/
|
||||
async function bewerbungEntscheiden(knopf, b, ja) {
|
||||
const wer = b.selbst ? 'dich' : b.person_name;
|
||||
const antwort = await window.frageNach({
|
||||
titel: ja ? `„${b.titel}" an ${b.person_name}?` : `${b.person_name} absagen?`,
|
||||
was: ja
|
||||
? `Die Aufgabe wird angelegt und liegt danach bei ${b.person_name}.`
|
||||
: `Die Vorlage bleibt auf dem Brett – ${wer} kann sich später wieder bewerben.`,
|
||||
grund: 'Willst du etwas dazuschreiben? (freiwillig)',
|
||||
grundPflicht: false,
|
||||
platzhalter: ja ? 'z. B. super, mach das gern' : 'z. B. diesmal nicht, nächste Woche gern',
|
||||
ja: ja ? 'Annehmen' : 'Ablehnen',
|
||||
nein: 'Doch nicht',
|
||||
});
|
||||
/* `frageNach` gibt bei „Doch nicht" etwas Falsches zurueck --
|
||||
dann ist NICHTS passiert. Das ist wichtiger als es klingt: Wer
|
||||
das Fenster wegklickt, weil er sich vertan hat, darf damit
|
||||
keine Zusage ausloesen. */
|
||||
if (!antwort) return;
|
||||
const wort = (antwort && antwort.grund) || '';
|
||||
knopf.disabled = true;
|
||||
try {
|
||||
const a = await hole(`/workspace/api/vorlagen/bewerbung/${ja ? 'annehmen' : 'ablehnen'}`, {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: b.id, kommentar: wort || undefined }),
|
||||
});
|
||||
if (!a.ok) { melde('Das ließ sich gerade nicht entscheiden.'); return; }
|
||||
const antwort = await a.json().catch(() => ({}));
|
||||
/* DIE LISTE KOMMT AUS DER ANTWORT. Sie im Browser
|
||||
zusammenzustreichen waere eine zweite Wahrheit -- und bei
|
||||
zwei offenen Fenstern die falsche. */
|
||||
if (Array.isArray(antwort.bewerbungen)) bewerbungen = antwort.bewerbungen;
|
||||
else await bewerbungenHolen();
|
||||
await laden();
|
||||
} catch { /* hole() hat schon gemeldet */ } finally {
|
||||
knopf.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Eine Karte fuer ein Stueck Arbeit, an dem mehrere sitzen. */
|
||||
function sammelKarte(g) {
|
||||
const a = g.erste;
|
||||
@@ -1420,6 +1587,11 @@
|
||||
kanalFeldZeigen('f');
|
||||
kanalFeldZeigen('b');
|
||||
lageZeigen(alleAufgaben);
|
||||
/* ERST DIE BEWERBUNGEN, DANN ZEICHNEN. Andersherum entstuende
|
||||
das Brett ohne die Spalte und bekaeme sie erst beim naechsten
|
||||
Mal -- ein Flackern, bei dem drei wartende Menschen eine
|
||||
Sekunde lang nicht dastehen. */
|
||||
await bewerbungenHolen();
|
||||
neuZeichnen();
|
||||
bandZeigen();
|
||||
/* Erst NACH dem Zeichnen -- vorher gibt es die Karten nicht, und
|
||||
|
||||
Reference in New Issue
Block a user