diff --git a/README.md b/README.md
index d4edb58..8bb7920 100644
--- a/README.md
+++ b/README.md
@@ -95,9 +95,11 @@ damit seinen eigenen Beitritt um - die Buchung des Erstellers bleibt unberührt,
sein eigener Platz in seiner eigenen Kette. Einreihen darf, wer an beidem beteiligt war.
Am Fuß einer Kette kann ein CC stehen, der jemand anderem gehört - der Gruppen-CC, aus dem sich
-der Spieler herausredesignt hat. Er war darin, und das bleibt sichtbar; verschieben oder
-entscheiden lässt sich daran nichts, denn es ist der Platz eines anderen. Frühere
-Mitgliedschaften, die zu keinem seiner Plätze führen, stehen darunter unter *Früher genutzt*.
+der Spieler herausredesignt hat. Er trägt das Kennzeichen *war dabei* samt Zeitraum und
+Besitzer, ist aber **genauso bedienbar wie jeder andere Eintrag**: ziehen, bearbeiten,
+Bezahlart, Verweise. Beim Nacherfassen steht erst am Ende fest, welches Redesign wohin führte -
+da muss sich auch einordnen lassen, was einem nicht gehört. Frühere Mitgliedschaften, die zu
+keinem seiner Plätze führen, stehen darunter unter *Früher genutzt*.
### Verweise an einem CC
diff --git a/server/test/ketten.test.ts b/server/test/ketten.test.ts
index 3540a19..7ab9e7b 100644
--- a/server/test/ketten.test.ts
+++ b/server/test/ketten.test.ts
@@ -758,7 +758,7 @@ describe('Eine Kette mit Vorgeschichte ausserhalb', () => {
ctx,
);
- return { dargon, eigenes: eigenes.character, weiter: weiter.character };
+ return { dargon, fremd: fremd.character, eigenes: eigenes.character, weiter: weiter.character };
}
it('zählt drei Plätze und drei verbrauchte Pakete', async () => {
@@ -796,6 +796,31 @@ describe('Eine Kette mit Vorgeschichte ausserhalb', () => {
assert.equal(buchung?.kind, 'REDESIGN_PAID', 'es bleibt ein Redesign');
});
+ it('lässt auch den fremden Gruppen-CC selbst einreihen', async () => {
+ // Beim Nacherfassen muss sich einordnen lassen, was einem nicht gehört:
+ // Erst am Ende steht fest, welches Redesign wohin führte.
+ const { dargon, fremd, eigenes } = await ausgestiegen();
+
+ await characters.moveInChain(
+ fremd.id,
+ { lineageId: eigenes.lineageId, afterId: null, forPlayerId: dargon },
+ ctx,
+ );
+
+ const glieder = await kette(dargon, eigenes.lineageId);
+ assert.deepEqual(
+ glieder.map((g) => g.name),
+ ['Fremde Gruppe', 'Eigener Strang', 'Und weiter'],
+ 'der Gruppen-CC steht jetzt am Anfang der Kette',
+ );
+ verkettungStimmt(glieder);
+
+ // Sein Platz bleibt einer: die Beitrittsbuchung wird zum Kauf, das
+ // Herausredesignen zum Redesign - nicht beides zum Kauf.
+ const stand = await credits.getBalances(dargon);
+ assert.equal(stand.CC, 0, 'drei Pakete, drei Plätze');
+ });
+
it('behält den Verweis auf die Herkunft', async () => {
const { dargon, eigenes, weiter } = await ausgestiegen();
diff --git a/web/src/components/ChainView.tsx b/web/src/components/ChainView.tsx
index 3adf66d..a8c1365 100644
--- a/web/src/components/ChainView.tsx
+++ b/web/src/components/ChainView.tsx
@@ -280,7 +280,24 @@ export default function ChainView({
@@ -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 (
-
-
- {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}`}
-
- {eigene?.note &&
{eigene.note}
}
-
-
-
-
-
- );
-}
-
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 (
)}
{ruht && dein Platz ruht}
+ {herkunft && war dabei}
+ {herkunft && (
+
+ {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}`}
+
+ )}
+
{character.loreText &&
{character.loreText}
}
{character.inactiveNote &&
{character.inactiveNote}
}
diff --git a/web/src/styles.css b/web/src/styles.css
index 486527e..4addf71 100644
--- a/web/src/styles.css
+++ b/web/src/styles.css
@@ -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 {