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:
@@ -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.
|
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
|
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
|
der Spieler herausredesignt hat. Er trägt das Kennzeichen *war dabei* samt Zeitraum und
|
||||||
entscheiden lässt sich daran nichts, denn es ist der Platz eines anderen. Frühere
|
Besitzer, ist aber **genauso bedienbar wie jeder andere Eintrag**: ziehen, bearbeiten,
|
||||||
Mitgliedschaften, die zu keinem seiner Plätze führen, stehen darunter unter *Früher genutzt*.
|
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
|
### Verweise an einem CC
|
||||||
|
|
||||||
|
|||||||
@@ -758,7 +758,7 @@ describe('Eine Kette mit Vorgeschichte ausserhalb', () => {
|
|||||||
ctx,
|
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 () => {
|
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');
|
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 () => {
|
it('behält den Verweis auf die Herkunft', async () => {
|
||||||
const { dargon, eigenes, weiter } = await ausgestiegen();
|
const { dargon, eigenes, weiter } = await ausgestiegen();
|
||||||
|
|
||||||
|
|||||||
@@ -280,7 +280,24 @@ export default function ChainView({
|
|||||||
<div className="chain-arrow" aria-hidden="true">
|
<div className="chain-arrow" aria-hidden="true">
|
||||||
⬆
|
⬆
|
||||||
</div>
|
</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>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -297,11 +314,24 @@ export default function ChainView({
|
|||||||
</p>
|
</p>
|
||||||
<div className="chains">
|
<div className="chains">
|
||||||
{vergangen.map((character) => (
|
{vergangen.map((character) => (
|
||||||
<FruehererEintrag
|
<ChainEntry
|
||||||
key={character.id}
|
key={character.id}
|
||||||
character={character}
|
character={character}
|
||||||
playerId={playerId}
|
playerId={playerId}
|
||||||
|
canEdit={canEdit}
|
||||||
|
admin={admin}
|
||||||
|
ziehend={ziehe?.id === character.id}
|
||||||
|
onDragStart={() => setZiehe(character)}
|
||||||
|
onDragEnd={() => {
|
||||||
|
setZiehe(null);
|
||||||
|
setUeber(null);
|
||||||
|
}}
|
||||||
onAction={onAction}
|
onAction={onAction}
|
||||||
|
onDetach={() => void herausloesen(character)}
|
||||||
|
onChanged={onMoved}
|
||||||
|
onError={onError}
|
||||||
|
alleinInKette={false}
|
||||||
|
herkunft
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</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({
|
function ChainEntry({
|
||||||
character,
|
character,
|
||||||
playerId,
|
playerId,
|
||||||
@@ -372,6 +354,7 @@ function ChainEntry({
|
|||||||
onDetach,
|
onDetach,
|
||||||
onChanged,
|
onChanged,
|
||||||
onError,
|
onError,
|
||||||
|
herkunft = false,
|
||||||
}: {
|
}: {
|
||||||
character: Character;
|
character: Character;
|
||||||
playerId: number;
|
playerId: number;
|
||||||
@@ -379,6 +362,13 @@ function ChainEntry({
|
|||||||
admin: boolean;
|
admin: boolean;
|
||||||
ziehend: boolean;
|
ziehend: boolean;
|
||||||
alleinInKette: 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;
|
onDragStart: () => void;
|
||||||
onDragEnd: () => void;
|
onDragEnd: () => void;
|
||||||
onAction: (action: ChainAction, character: Character) => void;
|
onAction: (action: ChainAction, character: Character) => void;
|
||||||
@@ -398,6 +388,10 @@ function ChainEntry({
|
|||||||
if (!aktiv) klassen.push('is-inactive');
|
if (!aktiv) klassen.push('is-inactive');
|
||||||
if (ziehend) klassen.push('is-dragging');
|
if (ziehend) klassen.push('is-dragging');
|
||||||
if (ruht) klassen.push('is-resting');
|
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 (
|
return (
|
||||||
<article
|
<article
|
||||||
@@ -438,8 +432,18 @@ function ChainEntry({
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{ruht && <span className="badge badge-dead">dein Platz ruht</span>}
|
{ruht && <span className="badge badge-dead">dein Platz ruht</span>}
|
||||||
|
{herkunft && <span className="badge">war dabei</span>}
|
||||||
</div>
|
</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.loreText && <p className="lore">{character.loreText}</p>}
|
||||||
{character.inactiveNote && <p className="muted small">{character.inactiveNote}</p>}
|
{character.inactiveNote && <p className="muted small">{character.inactiveNote}</p>}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -1179,11 +1179,12 @@ textarea {
|
|||||||
letter-spacing: 0;
|
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 {
|
.chain-entry.is-past {
|
||||||
opacity: 0.7;
|
opacity: 0.8;
|
||||||
border-style: dotted;
|
border-style: dotted;
|
||||||
cursor: default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chain-past-head {
|
.chain-past-head {
|
||||||
|
|||||||
Reference in New Issue
Block a user