K oder R an den Kettenpfeilen anzeigen
This commit is contained in:
@@ -633,7 +633,7 @@ export async function revertCharacter(
|
|||||||
* überhaupt zu sehen ist.
|
* überhaupt zu sehen ist.
|
||||||
*/
|
*/
|
||||||
export async function listCharacters(playerId: number) {
|
export async function listCharacters(playerId: number) {
|
||||||
return prisma.character.findMany({
|
const ccs = await prisma.character.findMany({
|
||||||
where: { members: { some: { playerId } } },
|
where: { members: { some: { playerId } } },
|
||||||
orderBy: [{ lineageId: 'asc' }, { chainPosition: 'asc' }, { createdAt: 'asc' }],
|
orderBy: [{ lineageId: 'asc' }, { chainPosition: 'asc' }, { createdAt: 'asc' }],
|
||||||
include: {
|
include: {
|
||||||
@@ -657,6 +657,29 @@ export async function listCharacters(playerId: number) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Womit dieser Spieler den jeweiligen Eintrag bezahlt hat. In der Kette
|
||||||
|
// steht das am Übergang: der Pfeil zum nächsten Glied trägt die Art, mit
|
||||||
|
// der dieses Glied bezahlt wurde.
|
||||||
|
const buchungen = await prisma.creditLedger.findMany({
|
||||||
|
where: {
|
||||||
|
characterId: { in: ccs.map((c) => c.id) },
|
||||||
|
playerId,
|
||||||
|
source: CreditSource.CONSUME,
|
||||||
|
reversedBy: null,
|
||||||
|
},
|
||||||
|
select: { characterId: true, kind: true },
|
||||||
|
orderBy: { id: 'desc' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const artNach = new Map<number, CreditKind>();
|
||||||
|
for (const buchung of buchungen) {
|
||||||
|
if (buchung.characterId !== null && !artNach.has(buchung.characterId)) {
|
||||||
|
artNach.set(buchung.characterId, buchung.kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ccs.map((cc) => ({ ...cc, fundedWith: artNach.get(cc.id) ?? null }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -312,9 +312,9 @@ export default function ChainView({
|
|||||||
|
|
||||||
{i < vonObenNachUnten.length - 1 && (
|
{i < vonObenNachUnten.length - 1 && (
|
||||||
<>
|
<>
|
||||||
<div className="chain-arrow" aria-hidden="true">
|
{/* Der Pfeil führt zu diesem Eintrag - also trägt er,
|
||||||
⬆
|
womit dieser Schritt bezahlt wurde. */}
|
||||||
</div>
|
<Uebergang character={character} />
|
||||||
{zone(
|
{zone(
|
||||||
kette.lineageId,
|
kette.lineageId,
|
||||||
vonObenNachUnten[i + 1]?.id ?? null,
|
vonObenNachUnten[i + 1]?.id ?? null,
|
||||||
@@ -327,11 +327,9 @@ export default function ChainView({
|
|||||||
|
|
||||||
{zone(kette.lineageId, null, `${kette.lineageId}-unten`)}
|
{zone(kette.lineageId, null, `${kette.lineageId}-unten`)}
|
||||||
|
|
||||||
{kette.herkunft.map((frueher) => (
|
{kette.herkunft.map((frueher, i) => (
|
||||||
<div key={frueher.id}>
|
<div key={frueher.id}>
|
||||||
<div className="chain-arrow" aria-hidden="true">
|
<Uebergang character={i === 0 ? kette.glieder[0] : kette.herkunft[i - 1]} />
|
||||||
⬆
|
|
||||||
</div>
|
|
||||||
<ChainEntry
|
<ChainEntry
|
||||||
character={frueher}
|
character={frueher}
|
||||||
playerId={playerId}
|
playerId={playerId}
|
||||||
@@ -393,6 +391,35 @@ export default function ChainView({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kurzzeichen für die Bezahlart eines Übergangs.
|
||||||
|
const UEBERGANG: Record<string, { zeichen: string; titel: string; klasse: string }> = {
|
||||||
|
REDESIGN_KULANZ: { zeichen: 'K', titel: 'Kulanz-Redesign', klasse: 'is-kulanz' },
|
||||||
|
REDESIGN_PAID: { zeichen: 'R', titel: 'Bezahltes Redesign', klasse: 'is-paid' },
|
||||||
|
CC: { zeichen: 'CC', titel: 'Aus dem CC-Topf bezahlt', klasse: 'is-cc' },
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Der Pfeil zum nächsten Glied, mit dem Kurzzeichen der Bezahlart.
|
||||||
|
*
|
||||||
|
* Womit ein Schritt bezahlt wurde, gehört an den Schritt - nicht in die
|
||||||
|
* Karte darüber. So liest sich die Kette in einem Zug: Eintrag, womit,
|
||||||
|
* Eintrag.
|
||||||
|
*/
|
||||||
|
function Uebergang({ character }: { character: Character | undefined }) {
|
||||||
|
const art = character?.fundedWith ? UEBERGANG[character.fundedWith] : undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="chain-arrow">
|
||||||
|
<span aria-hidden="true">⬆</span>
|
||||||
|
{art && (
|
||||||
|
<span className={`chain-step ${art.klasse}`} title={art.titel}>
|
||||||
|
{art.zeichen}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function ChainEntry({
|
function ChainEntry({
|
||||||
character,
|
character,
|
||||||
playerId,
|
playerId,
|
||||||
|
|||||||
@@ -149,6 +149,8 @@ export interface Character {
|
|||||||
successors: CharacterRef[];
|
successors: CharacterRef[];
|
||||||
forumThreads?: ThreadRef[];
|
forumThreads?: ThreadRef[];
|
||||||
links?: CharacterLink[];
|
links?: CharacterLink[];
|
||||||
|
/// Womit dieser Eintrag bezahlt wurde, aus Sicht des betrachteten Spielers.
|
||||||
|
fundedWith?: CreditKind | null;
|
||||||
members?: CharacterMember[];
|
members?: CharacterMember[];
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1171,6 +1171,7 @@ textarea {
|
|||||||
/* Der Pfeil zeigt zum jüngeren Eintrag, also nach oben. Er ist bewusst
|
/* Der Pfeil zeigt zum jüngeren Eintrag, also nach oben. Er ist bewusst
|
||||||
deutlich: er ist das Einzige, was die Leserichtung der Kette verrät. */
|
deutlich: er ist das Einzige, was die Leserichtung der Kette verrät. */
|
||||||
.chain-arrow {
|
.chain-arrow {
|
||||||
|
position: relative;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
@@ -1287,3 +1288,42 @@ textarea {
|
|||||||
padding-left: 0.6rem;
|
padding-left: 0.6rem;
|
||||||
padding-right: 0.6rem;
|
padding-right: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Das Kurzzeichen sitzt am Pfeil, nicht in der Karte: womit ein Schritt
|
||||||
|
bezahlt wurde, gehört an den Schritt. Absolut gesetzt, damit die Pfeile
|
||||||
|
aller Ketten in einer Flucht bleiben. */
|
||||||
|
.chain-step {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(0.75rem, -50%);
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 1.35rem;
|
||||||
|
height: 1.35rem;
|
||||||
|
padding: 0 0.3rem;
|
||||||
|
border: 1px solid var(--border-strong);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--bg);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chain-step.is-kulanz {
|
||||||
|
border-color: var(--positive);
|
||||||
|
color: var(--positive);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chain-step.is-paid {
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Aus dem CC-Topf bezahlt - die Ausnahme, also auffälliger. */
|
||||||
|
.chain-step.is-cc {
|
||||||
|
border-color: var(--warn);
|
||||||
|
color: var(--warn);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user