This commit is contained in:
2026-09-18 21:32:58 +02:00
parent 6c50d32d2b
commit 3a55ef1b2f
9 changed files with 68 additions and 68 deletions
+1 -1
View File
@@ -76,7 +76,7 @@ export default function AliasBox({
{aliases.length === 0 ? (
<p className="muted small">
Keine hinterlegt. Hat der Spieler früher einen anderen Steam- oder Forumsaccount
genutzt, trag ihn hier nach — Abgleich und Import finden ihn dann mit.
genutzt, trag ihn hier nach - Abgleich und Import finden ihn dann mit.
</p>
) : (
<div className="alias-groups">
+2 -2
View File
@@ -39,9 +39,9 @@ const dateFormat = new Intl.DateTimeFormat('de-DE', {
});
export function formatDate(value: string | null | undefined): string {
if (!value) return '—';
if (!value) return '-';
const parsed = new Date(value);
return Number.isNaN(parsed.getTime()) ? '—' : dateFormat.format(parsed);
return Number.isNaN(parsed.getTime()) ? '-' : dateFormat.format(parsed);
}
export function formatAmount(amount: number): string {
+1 -1
View File
@@ -97,7 +97,7 @@ export default function Account() {
{user?.mustChangePassword && (
<Notice kind="warn">
Dieses Konto verwendet noch ein vergebenes Erstpasswort. Bitte jetzt ändern — die
Dieses Konto verwendet noch ein vergebenes Erstpasswort. Bitte jetzt ändern - die
übrigen Seiten sind bis dahin gesperrt.
</Notice>
)}
+5 -5
View File
@@ -290,9 +290,9 @@ function CreateUserModal({
value={role}
onChange={(event) => setRole(event.target.value as Role)}
>
<option value="VIEWER">Viewer — nur lesen</option>
<option value="EDITOR">Editor — Spieler, Guthaben, CCs</option>
<option value="ADMIN">Admin — alles inkl. Import und Nutzer</option>
<option value="VIEWER">Viewer - nur lesen</option>
<option value="EDITOR">Editor - Spieler, Guthaben, CCs</option>
<option value="ADMIN">Admin - alles inkl. Import und Nutzer</option>
</select>
<div className="form-actions">
@@ -475,14 +475,14 @@ function AuditTab({ onError }: { onError: (message: string) => void }) {
{items.map((entry) => (
<tr key={entry.id}>
<td className="muted small">{formatDate(entry.createdAt)}</td>
<td>{entry.actor?.username ?? entry.actorName ?? '—'}</td>
<td>{entry.actor?.username ?? entry.actorName ?? '-'}</td>
<td className="mono">{entry.action}</td>
<td className="muted">
{entry.targetType}
{entry.targetId ? ` #${entry.targetId}` : ''}
</td>
<td className="muted small details">
{entry.details ? JSON.stringify(entry.details) : '—'}
{entry.details ? JSON.stringify(entry.details) : '-'}
</td>
</tr>
))}
+2 -2
View File
@@ -164,7 +164,7 @@ export default function Dashboard() {
</Link>
{player.forumName && <span className="muted"> · {player.forumName}</span>}
</td>
<td className="mono muted">{player.steamId ?? '—'}</td>
<td className="mono muted">{player.steamId ?? '-'}</td>
<td className="num">
<Counter value={player.balances.CC} title="CC-Guthaben" />
</td>
@@ -194,7 +194,7 @@ export default function Dashboard() {
{loading && <p className="muted">Lade …</p>}
{!loading && result.total > result.items.length && (
<p className="muted">
{result.items.length} von {result.total} angezeigt — Suche eingrenzen.
{result.items.length} von {result.total} angezeigt - Suche eingrenzen.
</p>
)}
+9 -9
View File
@@ -83,7 +83,7 @@ export default function Forum() {
<div>
<h1>Forums-Anträge</h1>
<p className="muted">
Jeder Antrag wird von Hand entschieden — Titel und Board sind kein verlässliches
Jeder Antrag wird von Hand entschieden - Titel und Board sind kein verlässliches
Signal und lösen nie eine Buchung aus. Aufgenommen werden nur Threads von Spielern,
die hier mit passendem Forum-Namen erfasst sind.
</p>
@@ -103,7 +103,7 @@ export default function Forum() {
<h2>Verschoben nach der Entscheidung ({notices.length})</h2>
<Notice kind="warn">
Diese Anträge wurden bereits entschieden, ihr Thread liegt inzwischen aber in einem
anderen Board. Das ist nur ein Hinweis — geprüft und geklickt wird von Hand.
anderen Board. Das ist nur ein Hinweis - geprüft und geklickt wird von Hand.
</Notice>
<ul className="cc-list">
@@ -312,7 +312,7 @@ function ClassifyModal({
/>
<span>
<strong>{label}</strong>
<span className="muted"> — {hint}</span>
<span className="muted"> - {hint}</span>
</span>
</label>
))}
@@ -333,7 +333,7 @@ function ClassifyModal({
onChange={(event) => setName(event.target.value)}
required
/>
<p className="muted small">Vorbelegt mit dem Thread-Titel — bitte anpassen.</p>
<p className="muted small">Vorbelegt mit dem Thread-Titel - bitte anpassen.</p>
</>
)}
@@ -346,11 +346,11 @@ function ClassifyModal({
onChange={(event) => setReviveId(Number(event.target.value) || null)}
required
>
<option value="">— bitte wählen —</option>
<option value="">- bitte wählen -</option>
{inactive.map((character) => (
<option key={character.id} value={character.id}>
{character.name}
{character.inactiveReason === 'REWORKED' ? ' (redesignt — kostet)' : ' (gratis)'}
{character.inactiveReason === 'REWORKED' ? ' (redesignt - kostet)' : ' (gratis)'}
</option>
))}
</select>
@@ -360,7 +360,7 @@ function ClassifyModal({
{gewaehlterCC && !reaktivierungKostet && (
<Notice kind="success">
Kommt gratis zurück — der CC existiert unverändert weiter.
Kommt gratis zurück - der CC existiert unverändert weiter.
</Notice>
)}
@@ -405,7 +405,7 @@ function ClassifyModal({
onChange={(event) => setPredecessorId(Number(event.target.value) || null)}
required
>
<option value="">— bitte wählen —</option>
<option value="">- bitte wählen -</option>
{characters.map((character) => (
<option key={character.id} value={character.id}>
{character.name}
@@ -500,7 +500,7 @@ function AssignModal({
<Modal title="Spieler zuordnen" onClose={onClose}>
<Notice kind="info">
Forumsname des Antragstellers: <strong>{thread.authorName ?? 'unbekannt'}</strong>. Passt
kein Eintrag, trag den Forumsnamen beim Spieler nach — dann findet der nächste Abgleich
kein Eintrag, trag den Forumsnamen beim Spieler nach - dann findet der nächste Abgleich
ihn von allein.
</Notice>
+6 -6
View File
@@ -200,7 +200,7 @@ export default function Import() {
<h2>Wartet auf Bestätigung ({open.length})</h2>
<Notice kind="warn">
Diese Importe sind angelegt, aber noch nicht gebucht. Der GExtension-Abgleich landet
ebenfalls hier — erst nach dem Bestätigen entstehen Guthaben.
ebenfalls hier - erst nach dem Bestätigen entstehen Guthaben.
</Notice>
<ul className="cc-list">
@@ -234,7 +234,7 @@ export default function Import() {
<section className="block">
<Notice kind="info">
CSV oder JSON hochladen. Danach werden die Spalten zugeordnet und eine Vorschau
gezeigt — gebucht wird erst nach Bestätigung. Bereits importierte Bestell-IDs
gezeigt - gebucht wird erst nach Bestätigung. Bereits importierte Bestell-IDs
werden automatisch übersprungen.
</Notice>
@@ -396,13 +396,13 @@ export default function Import() {
<tr key={row.id} className={row.plan.startsWith('SKIP') ? 'is-skipped' : undefined}>
<td className="muted">{row.lineNo}</td>
<td>
{row.playerName || row.playerKey || '—'}
{row.playerName || row.playerKey || '-'}
{row.resolvedPlayerId === null && row.plan === 'CREATE_PLAYER_AND_BOOK' && (
<span className="badge badge-new">neu</span>
)}
</td>
<td className="muted">{row.productName ?? '—'}</td>
<td className="mono muted">{row.externalId ?? '—'}</td>
<td className="muted">{row.productName ?? '-'}</td>
<td className="mono muted">{row.externalId ?? '-'}</td>
<td className="muted">{formatDate(row.purchasedAt)}</td>
<td className={row.plan.startsWith('SKIP') ? 'muted' : 'pos'}>
{PLAN_LABEL[row.plan]}
@@ -452,7 +452,7 @@ function MappingSelect({
<div className="field">
<label>{label}</label>
<select value={value} onChange={(event) => onChange(event.target.value)} required={required}>
<option value="">— nicht zuordnen —</option>
<option value="">- nicht zuordnen -</option>
{columns.map((column) => (
<option key={column} value={column}>
{column}
+11 -11
View File
@@ -95,9 +95,9 @@ export default function PlayerDetail() {
'bereits unter Import auf Bestätigung.',
);
} else if (result.unclear > 0) {
setFlash(`${result.unclear} unklare Einträge — siehe Kasten oben.`);
setFlash(`${result.unclear} unklare Einträge - siehe Kasten oben.`);
} else if (result.duplicates > 0) {
setFlash('Nichts Neues — alle Pakete sind bereits gebucht.');
setFlash('Nichts Neues - alle Pakete sind bereits gebucht.');
} else if (result.failedPlayers.length > 0) {
setError(`Profil nicht abrufbar: ${result.failedPlayers[0]?.reason ?? 'unbekannt'}`);
} else {
@@ -165,7 +165,7 @@ export default function PlayerDetail() {
GExtension meldet <strong>{detail.player.gextensionUsage}</strong> Mal verbraucht
{detail.player.gextensionSyncedAt &&
` (Stand ${formatDate(detail.player.gextensionSyncedAt)})`}
. Nur zum Abgleich — wird nicht automatisch verrechnet.
. Nur zum Abgleich - wird nicht automatisch verrechnet.
</p>
)}
@@ -302,7 +302,7 @@ export default function PlayerDetail() {
)}
<p className="muted small">
{free
? 'Kommt gratis zurück — kostet kein Guthaben.'
? 'Kommt gratis zurück - kostet kein Guthaben.'
: 'Reaktivierung kostet ein Redesign- oder CC-Guthaben.'}
</p>
</div>
@@ -320,7 +320,7 @@ export default function PlayerDetail() {
method: 'POST',
body: {},
}),
`"${character.name}" ist wieder aktiv — kostenlos.`,
`"${character.name}" ist wieder aktiv - kostenlos.`,
)
}
>
@@ -376,7 +376,7 @@ export default function PlayerDetail() {
</td>
<td>{SOURCE_LABEL[entry.source]}</td>
<td className="muted small">
{entry.note ?? '—'}
{entry.note ?? '-'}
{entry.character && ` (${entry.character.name})`}
</td>
<td className="muted small">{entry.createdBy?.username ?? 'System'}</td>
@@ -428,7 +428,7 @@ export default function PlayerDetail() {
method: 'POST',
body: values,
}),
`CC "${values.name}" angelegt — 1 CC-Guthaben verbraucht.`,
`CC "${values.name}" angelegt - 1 CC-Guthaben verbraucht.`,
)
}
/>
@@ -870,7 +870,7 @@ function DeactivateModal({
>
<Notice kind="info">
Der CC bleibt unverändert und kommt später in beiden Fällen gratis zurück. Nur ein
Redesign macht ihn kostenpflichtig — das läuft aber über die Redesign-Aktion.
Redesign macht ihn kostenpflichtig - das läuft aber über die Redesign-Aktion.
</Notice>
<div className="radio-group">
@@ -883,7 +883,7 @@ function DeactivateModal({
/>
<span>
<strong>Spieler-Inaktivität</strong>
<span className="muted"> — vom Server geputzt, weil der Spieler länger weg war</span>
<span className="muted"> - vom Server geputzt, weil der Spieler länger weg war</span>
</span>
</label>
<label className="radio">
@@ -895,7 +895,7 @@ function DeactivateModal({
/>
<span>
<strong>Anderer Grund</strong>
<span className="muted"> — etwa eine vorübergehend entfernte Einheit</span>
<span className="muted"> - etwa eine vorübergehend entfernte Einheit</span>
</span>
</label>
</div>
@@ -1083,7 +1083,7 @@ function DeletePlayerModal({
{characterCount === 1 ? 'CC' : 'CCs'} und <strong>{ledgerCount}</strong>{' '}
{ledgerCount === 1 ? 'Buchung' : 'Buchungen'} mit. Auch Spuren in Importen und in den
Details früherer Protokolleinträge werden entfernt. Das lässt sich nicht rückgängig
machen — für eine Fehleingabe ist eher das Bearbeiten gedacht.
machen - für eine Fehleingabe ist eher das Bearbeiten gedacht.
</Notice>
<label htmlFor="confirm-name">