Fremde Gruppen-CCs in der Kette bleiben voll bedienbar

Der Eintrag am Fuss einer Kette - der Gruppen-CC, aus dem sich jemand
herausredesignt hat - liess sich weder ziehen noch bearbeiten. Das war meine
Entscheidung mit der Begruendung, es sei der Platz eines anderen. Beim
Nacherfassen ist das zu eng: Dort steht erst am Ende fest, welches Redesign
wohin fuehrte, und bis dahin muss sich auch einordnen lassen, was einem nicht
gehoert.

Er ist jetzt ein Kettenglied wie jedes andere - ziehen, bearbeiten,
Bezahlart, Verweise, Herausloesen - und traegt nur zusaetzlich das
Kennzeichen "war dabei" mit Zeitraum und Besitzer. Wer ihn an den Anfang
seiner Kette zieht, macht aus seiner Beitrittsbuchung den Kauf und aus dem
Herausredesignen ein Redesign; sein Platz bleibt dabei einer.

Dass nur Beteiligte etwas einreihen duerfen, gilt unveraendert.
This commit is contained in:
2026-09-21 19:16:07 +02:00
parent 1b643cb758
commit 46e339fdc4
4 changed files with 89 additions and 57 deletions
+54 -50
View File
@@ -280,7 +280,24 @@ export default function ChainView({
<div className="chain-arrow" aria-hidden="true">
⬆
</div>
<FruehererEintrag character={frueher} playerId={playerId} onAction={onAction} />
<ChainEntry
character={frueher}
playerId={playerId}
canEdit={canEdit}
admin={admin}
ziehend={ziehe?.id === frueher.id}
onDragStart={() => setZiehe(frueher)}
onDragEnd={() => {
setZiehe(null);
setUeber(null);
}}
onAction={onAction}
onDetach={() => void herausloesen(frueher)}
onChanged={onMoved}
onError={onError}
alleinInKette={false}
herkunft
/>
</div>
))}
</div>
@@ -297,11 +314,24 @@ export default function ChainView({
</p>
<div className="chains">
{vergangen.map((character) => (
<FruehererEintrag
<ChainEntry
key={character.id}
character={character}
playerId={playerId}
canEdit={canEdit}
admin={admin}
ziehend={ziehe?.id === character.id}
onDragStart={() => setZiehe(character)}
onDragEnd={() => {
setZiehe(null);
setUeber(null);
}}
onAction={onAction}
onDetach={() => void herausloesen(character)}
onChanged={onMoved}
onError={onError}
alleinInKette={false}
herkunft
/>
))}
</div>
@@ -311,54 +341,6 @@ export default function ChainView({
);
}
/**
* Ein CC, in dem der Spieler einmal steckte. Er gehört ihm nicht mehr,
* deshalb gibt es hier nichts zu entscheiden und nichts zu verschieben -
* nur nachzulesen, wann er dabei war und wohin es danach ging.
*/
function FruehererEintrag({
character,
playerId,
onAction,
}: {
character: Character;
playerId: number;
onAction: (action: ChainAction, character: Character) => void;
}) {
const eigene = eigeneMitgliedschaft(character, playerId);
const thread = character.forumThreads?.[0];
const besitzer = (character.members ?? []).find((m) => m.playerId === character.playerId);
return (
<article className="chain-entry is-past">
<div className="chain-entry-head">
{thread ? (
<a href={thread.url} target="_blank" rel="noreferrer" className="link-strong">
{character.name}
</a>
) : (
<strong>{character.name}</strong>
)}
<span className="badge">war dabei</span>
</div>
<p className="muted small">
{eigene?.joinedAt && `Dabei ab ${formatDate(eigene.joinedAt)}`}
{eigene?.leftAt && ` bis ${formatDate(eigene.leftAt)}`}
{eigene?.successor && ` · weiter als „${eigene.successor.name}"`}
{besitzer && besitzer.playerId !== playerId && ` · gehört ${besitzer.player.displayName}`}
</p>
{eigene?.note && <p className="muted small">{eigene.note}</p>}
<div className="chain-actions">
<button type="button" className="btn btn-tiny btn-ghost" onClick={() => onAction('links', character)}>
Verweise
</button>
</div>
</article>
);
}
function ChainEntry({
character,
playerId,
@@ -372,6 +354,7 @@ function ChainEntry({
onDetach,
onChanged,
onError,
herkunft = false,
}: {
character: Character;
playerId: number;
@@ -379,6 +362,13 @@ function ChainEntry({
admin: boolean;
ziehend: boolean;
alleinInKette: boolean;
/**
* Ein CC, in dem der Spieler einmal steckte und der zu dieser Kette
* führte - meist ein Gruppen-CC, der jemand anderem gehört. Er bleibt
* voll bedienbar: beim Nacherfassen muss sich auch das einordnen lassen,
* was einem nicht gehört.
*/
herkunft?: boolean;
onDragStart: () => void;
onDragEnd: () => void;
onAction: (action: ChainAction, character: Character) => void;
@@ -398,6 +388,10 @@ function ChainEntry({
if (!aktiv) klassen.push('is-inactive');
if (ziehend) klassen.push('is-dragging');
if (ruht) klassen.push('is-resting');
if (herkunft) klassen.push('is-past');
const eigene = (character.members ?? []).find((m) => m.playerId === playerId);
const besitzer = (character.members ?? []).find((m) => m.playerId === character.playerId);
return (
<article
@@ -438,8 +432,18 @@ function ChainEntry({
</span>
)}
{ruht && <span className="badge badge-dead">dein Platz ruht</span>}
{herkunft && <span className="badge">war dabei</span>}
</div>
{herkunft && (
<p className="muted small">
{eigene?.joinedAt && `Dabei ab ${formatDate(eigene.joinedAt)}`}
{eigene?.leftAt && ` bis ${formatDate(eigene.leftAt)}`}
{eigene?.successor && ` · weiter als „${eigene.successor.name}"`}
{besitzer && besitzer.playerId !== playerId && ` · gehört ${besitzer.player.displayName}`}
</p>
)}
{character.loreText && <p className="lore">{character.loreText}</p>}
{character.inactiveNote && <p className="muted small">{character.inactiveNote}</p>}
+4 -3
View File
@@ -1179,11 +1179,12 @@ textarea {
letter-spacing: 0;
}
/* Ein CC, der jemand anderem gehört und nur zur Geschichte beiträgt. */
/* Ein CC, der jemand anderem gehört und zur Geschichte dieser Kette führte.
Er tritt optisch zurück, bleibt aber voll bedienbar - beim Nacherfassen
muss sich auch einordnen lassen, was einem nicht gehört. */
.chain-entry.is-past {
opacity: 0.7;
opacity: 0.8;
border-style: dotted;
cursor: default;
}
.chain-past-head {