Rueckfragen im Stil der Anwendung, Kulanz-Ausgleich, Redesign aus dem CC-Topf

window.confirm und window.prompt sind raus - alle vierzehn Stellen. Sie sahen
nicht nur fremd aus: Wer sie im Browser abschaltet, bekommt stillschweigend
"nein" zurueck, und eine Aktion passiert einfach nicht, ohne dass jemand
erfaehrt warum. Stattdessen gibt es einen Dialog-Dienst mit drei Formen -
bestaetigen, abfragen, waehlen -, der sich wie der Rest der Anwendung
anfuehlt.

Die Wahl kam dazu, weil eine Stelle ein Ja/Nein fuer eine Auswahl
missbrauchte: "OK = Kulanz, Abbrechen = bezahltes Redesign". Das fuehrt jeden
in die Irre, der es zum ersten Mal sieht.

Neu: Steht der bezahlte Redesign-Topf im Minus, waehrend Kulanz uebrig ist,
erscheint "Minus mit Kulanz ausgleichen". Es bucht so viele Uebergaenge um,
wie beide Seiten hergeben - die aeltesten zuerst, damit das Ergebnis
wiederholbar ist. Unterm Strich aendert sich nichts, nur die Verteilung.

Ebenfalls neu: Ein Redesign laesst sich ausnahmsweise aus dem CC-Topf
bezahlen. Damit das Ausrichten an den Ketten so eine Entscheidung nicht beim
naechsten Umsortieren wieder einebnet, tragen von Hand gewaehlte Buchungen
jetzt einen Merker.

Dabei aufgefallen: Die Tests wurden gar nicht typgeprueft - tsconfig schloss
nur src ein. Sieben Aufrufe von bookKulanz hatten vertauschte Argumente und
liefen trotzdem durch, weil JavaScript das hinnimmt; sie pruefte damit etwas
anderes als gedacht. Tests haengen jetzt in der Typpruefung.
This commit is contained in:
2026-09-22 09:39:57 +02:00
parent 9b93844be2
commit 34819d44cc
19 changed files with 709 additions and 61 deletions
+24 -2
View File
@@ -27,6 +27,7 @@ import {
changeFunding,
addMemberToChain,
rebuildFunding,
settleWithKulanz,
} from '../services/characters.js';
import { parseThreadId } from '../lib/forum.js';
import { linkThreadToCharacter } from '../services/forum.js';
@@ -49,7 +50,13 @@ async function linkThread(
await linkThreadToCharacter(threadId, characterId, classification, ctx);
}
const redesignKind = z.enum([CreditKind.REDESIGN_PAID, CreditKind.REDESIGN_KULANZ]);
/// Der Regelfall für ein Redesign sind die Redesign-Töpfe. Ein CC-Paket
/// geht ausnahmsweise auch - dann gilt die Wahl als von Hand getroffen.
const redesignKind = z.enum([
CreditKind.REDESIGN_PAID,
CreditKind.REDESIGN_KULANZ,
CreditKind.CC,
]);
const reviveKind = z.enum([CreditKind.CC, CreditKind.REDESIGN_PAID, CreditKind.REDESIGN_KULANZ]);
export async function characterRoutes(app: FastifyInstance): Promise<void> {
@@ -208,6 +215,15 @@ export async function characterRoutes(app: FastifyInstance): Promise<void> {
return rebuildFunding(id, contextOf(request));
});
/**
* Gleicht ein Minus im bezahlten Redesign-Topf mit vorhandener Kulanz aus,
* indem ebenso viele Übergänge auf Kulanz umgebucht werden.
*/
app.post('/api/players/:id/credits/settle', { preHandler: requireEditor }, async (request) => {
const { id } = parseWith(idParam, request.params);
return settleWithKulanz(id, contextOf(request));
});
// --- Ketten ---
/**
@@ -294,7 +310,13 @@ export async function characterRoutes(app: FastifyInstance): Promise<void> {
z.object({
name: z.string().trim().min(1).max(160),
loreText: z.string().trim().max(5000).optional(),
useKind: z.enum([CreditKind.REDESIGN_PAID, CreditKind.REDESIGN_KULANZ]),
/// Der Regelfall sind die Redesign-Töpfe; ein CC-Paket geht
/// ausnahmsweise auch.
useKind: z.enum([
CreditKind.REDESIGN_PAID,
CreditKind.REDESIGN_KULANZ,
CreditKind.CC,
]),
note: optionalNote,
}),
request.body,