feat: spectator reactions with floating emoji particles
POST /api/fights/:fightId/react endpoint accepts emoji reactions (fist, fire, skull, 100, clown), aggregates counts, broadcasts via SSE. Reaction bar added to FightViewer with floating emoji particles that rise and fade. Live fight views receive reactions via SSE in real-time. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
baf153b115
commit
fd22b126e7
@@ -15,6 +15,10 @@ export const fightsRouter = new Hono()
|
||||
// Track spectator counts per fight
|
||||
const spectatorCounts = new Map<string, number>()
|
||||
|
||||
// Track reactions per fight
|
||||
const VALID_REACTIONS = new Set(['fist', 'fire', 'skull', '100', 'clown'])
|
||||
const fightReactions = new Map<string, Record<string, number>>()
|
||||
|
||||
export function getSpectatorCount(fightId: string): number {
|
||||
return spectatorCounts.get(fightId) || 0
|
||||
}
|
||||
@@ -383,3 +387,31 @@ fightsRouter.get('/:id/stream', (c) => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// React to a fight
|
||||
fightsRouter.post('/:id/react', async (c) => {
|
||||
const fightId = c.req.param('id')
|
||||
const body = await c.req.json<{ emoji?: string }>()
|
||||
const emoji = body?.emoji
|
||||
|
||||
if (!emoji || !VALID_REACTIONS.has(emoji)) {
|
||||
return c.json({ error: 'Invalid reaction. Use: fist, fire, skull, 100, clown' }, 400)
|
||||
}
|
||||
|
||||
// Aggregate
|
||||
if (!fightReactions.has(fightId)) {
|
||||
fightReactions.set(fightId, {})
|
||||
}
|
||||
const counts = fightReactions.get(fightId)!
|
||||
counts[emoji] = (counts[emoji] || 0) + 1
|
||||
|
||||
// Broadcast via SSE
|
||||
fightEvents.emit({
|
||||
fightId,
|
||||
type: 'reaction',
|
||||
data: { emoji, counts: { ...counts } },
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
|
||||
return c.json({ ok: true, counts })
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user