Files
mixmaker/frontend/src/api/demo.ts
lemintare 1239fcee08
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / compose (push) Has been cancelled
Initialize project with basic structure, including Docker configuration, backend and frontend setup, environment configuration, and essential files for development.
2026-07-19 00:17:31 +03:00

249 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type {
BalanceCandidate,
Bracket,
MixEvent,
Player,
Registration,
Series,
Session,
Team,
} from './client'
import type { RankOrdinal } from '../ranks'
// Fixtures keep local development and visual review useful without a backend.
// Production builds always use the real API.
export const demoMode =
import.meta.env.DEV && import.meta.env.VITE_DEMO_MODE !== 'false'
const now = new Date()
const daysFromNow = (days: number, hour = 19) => {
const date = new Date(now)
date.setDate(date.getDate() + days)
date.setHours(hour, 0, 0, 0)
return date.toISOString()
}
const makePlayer = (
id: string,
displayName: string,
tank: RankOrdinal,
damage: RankOrdinal,
support: RankOrdinal,
): Player => ({
id,
displayName,
battleTag: `${displayName.replace(/\s/g, '')}#${1000 + Number(id.replace(/\D/g, '') || 0)}`,
ratings: { tank, damage, support, updatedAt: daysFromNow(-4) },
preferredRoles: tank >= damage && tank >= support ? ['tank'] : damage >= support ? ['damage'] : ['support'],
preferredPlayerIds: [],
})
export const demoProfile: Player = {
...makePlayer('p1', 'Lemintare', 30, 33, 27),
preferredRoles: ['damage', 'tank'],
preferredPlayerIds: ['p2', 'p5'],
}
export const demoSession: Session = {
account: {
id: 'account-1',
discordId: '125661705720381444',
displayName: 'Lemintare',
role: 'admin',
},
player: demoProfile,
}
export const demoEvents: MixEvent[] = [
{
id: 'event-1',
title: 'Saturday Night Scrim',
description: 'Community draft night · 4 teams · Bo3 single elimination',
startsAt: daysFromNow(2),
endsAt: daysFromNow(2, 23),
registrationDeadline: daysFromNow(1, 21),
status: 'registration',
rulesetName: 'Community Bo3 v2',
counts: { going: 18, maybe: 4, not_going: 3 },
myRsvp: 'going',
},
{
id: 'event-2',
title: 'Midweek Mix',
description: 'Fast queue with two balanced teams',
startsAt: daysFromNow(5),
endsAt: daysFromNow(5, 23),
registrationDeadline: daysFromNow(4),
status: 'registration',
rulesetName: 'Quick Mix v1',
counts: { going: 9, maybe: 6, not_going: 2 },
myRsvp: 'maybe',
},
{
id: 'event-3',
title: 'Summer Clash #4',
description: 'Live playoff bracket',
startsAt: daysFromNow(0, 20),
endsAt: daysFromNow(1, 1),
registrationDeadline: daysFromNow(-1),
status: 'live',
rulesetName: 'Tournament Bo3 v2',
counts: { going: 22, maybe: 0, not_going: 4 },
myRsvp: 'going',
},
]
const players = [
demoProfile,
makePlayer('p2', 'Nova', 36, 28, 29),
makePlayer('p3', 'Kairo', 24, 35, 26),
makePlayer('p4', 'MercyMain', 18, 27, 37),
makePlayer('p5', 'Pulse', 25, 34, 29),
makePlayer('p6', 'Astra', 31, 25, 36),
makePlayer('p7', 'Hex', 35, 29, 23),
makePlayer('p8', 'Orbit', 22, 34, 30),
makePlayer('p9', 'Miko', 27, 30, 36),
makePlayer('p10', 'Rook', 37, 26, 24),
makePlayer('p11', 'Echo', 26, 32, 31),
makePlayer('p12', 'Zenith', 28, 30, 35),
]
players[1].preferredPlayerIds = ['p1']
players[4].preferredPlayerIds = ['p1']
export const demoRegistrations: Registration[] = players.map((player, index) => ({
id: `reg-${index + 1}`,
player,
status: index < 9 ? 'going' : index < 11 ? 'maybe' : 'not_going',
updatedAt: daysFromNow(-(index % 4)),
changedBy:
index === 4
? { id: 'account-1', displayName: 'Lemintare', source: 'admin' }
: { id: player.id, displayName: player.displayName, source: 'self' },
}))
const alpha: Team = {
id: 'team-alpha',
name: 'Ember Wolves',
side: 'alpha',
captainId: 'p2',
averageRating: 35.6,
members: [
{ player: players[1], assignedRole: 'tank' },
{ player: players[2], assignedRole: 'damage' },
{ player: players[4], assignedRole: 'damage' },
{ player: players[3], assignedRole: 'support' },
{ player: players[5], assignedRole: 'support' },
],
}
const beta: Team = {
id: 'team-beta',
name: 'Azure Phantoms',
side: 'beta',
captainId: 'p7',
averageRating: 34.4,
members: [
{ player: players[6], assignedRole: 'tank' },
{ player: players[7], assignedRole: 'damage' },
{ player: players[10], assignedRole: 'damage' },
{ player: players[8], assignedRole: 'support' },
{ player: players[11], assignedRole: 'support' },
],
}
export const demoBalanceCandidates: BalanceCandidate[] = [
{
id: 'candidate-1',
score: 4,
teams: [alpha, beta],
reserve: [players[0], players[9]],
explanations: ['9 preferred role assignments', '2 preferred teammate pairs kept together'],
},
{
id: 'candidate-2',
score: 9,
teams: [
{ ...alpha, averageRating: 35.2 },
{ ...beta, averageRating: 34.6 },
],
reserve: [players[0], players[9]],
explanations: ['8 preferred role assignments', '2 preferred teammate pairs kept together'],
},
{
id: 'candidate-3',
score: 13,
teams: [
{ ...alpha, averageRating: 35.4 },
{ ...beta, averageRating: 34.5 },
],
reserve: [players[0], players[9]],
explanations: ['10 preferred role assignments', '1 preferred teammate pair kept together'],
},
]
export const demoSeries: Series = {
id: 'series-1',
status: 'hero_draft',
roundLabel: 'Semifinal 1',
teamAlpha: alpha,
teamBeta: beta,
score: { alpha: 1, beta: 0 },
version: 12,
currentStep: {
title: 'Hero ban 2 of 4',
instruction: 'Azure Phantoms choose a hero to remove for Map 2.',
activeTeam: 'beta',
kind: 'hero_ban',
version: 12,
},
options: [
{ id: 'hero-1', name: 'Ana', role: 'support' },
{ id: 'hero-2', name: 'Kiriko', role: 'support' },
{ id: 'hero-3', name: 'Tracer', role: 'damage' },
{ id: 'hero-4', name: 'Sojourn', role: 'damage' },
{ id: 'hero-5', name: 'Winston', role: 'tank', disabled: true, disabledReason: 'Already banned by this team' },
{ id: 'hero-6', name: 'Sigma', role: 'tank' },
],
maps: [
{
number: 1,
name: 'Lijiang Tower',
mode: 'Control',
status: 'completed',
winner: 'alpha',
heroBans: [
{ hero: 'Sombra', team: 'alpha', role: 'damage' },
{ hero: 'Winston', team: 'beta', role: 'tank' },
{ hero: 'Ana', team: 'alpha', role: 'support' },
{ hero: 'Tracer', team: 'beta', role: 'damage' },
],
},
{
number: 2,
name: 'Kings Row',
mode: 'Hybrid',
status: 'drafting',
heroBans: [{ hero: 'D.Va', team: 'alpha', role: 'tank' }],
},
{ number: 3, name: 'TBD', mode: 'Control', status: 'ready', heroBans: [] },
],
audit: [
{ id: 'a1', kind: 'coin_toss', summary: 'Ember Wolves won the toss', actorName: 'System', createdAt: daysFromNow(0, 20) },
{ id: 'a2', kind: 'map_selected', summary: 'Lijiang Tower selected', actorName: 'Nova', createdAt: daysFromNow(0, 20) },
{ id: 'a3', kind: 'result', summary: 'Map 1 won by Ember Wolves', actorName: 'Lemintare', createdAt: daysFromNow(0, 21) },
{ id: 'a4', kind: 'map_selected', summary: 'Kings Row selected', actorName: 'Hex', createdAt: daysFromNow(0, 21) },
{ id: 'a5', kind: 'hero_ban', summary: 'D.Va banned by Ember Wolves', actorName: 'Nova', createdAt: daysFromNow(0, 21) },
],
}
export const demoBracket: Bracket = {
id: 'bracket-1',
title: 'Summer Clash #4',
rounds: ['Semifinals', 'Grand Final'],
matches: [
{ id: 'm1', round: 0, slot: 0, label: 'Semifinal 1', teamAlpha: 'Ember Wolves', teamBeta: 'Azure Phantoms', scoreAlpha: 1, scoreBeta: 0, status: 'live', seriesId: 'series-1' },
{ id: 'm2', round: 0, slot: 1, label: 'Semifinal 2', teamAlpha: 'Neon Foxes', teamBeta: 'Void Runners', scoreAlpha: 2, scoreBeta: 1, winner: 'alpha', status: 'completed', seriesId: 'series-2' },
{ id: 'm3', round: 1, slot: 0, label: 'Grand Final', teamBeta: 'Neon Foxes', status: 'pending' },
],
}