diff --git a/packages/socket/src/services/game.ts b/packages/socket/src/services/game.ts index 8fae6c2..435e83a 100644 --- a/packages/socket/src/services/game.ts +++ b/packages/socket/src/services/game.ts @@ -25,7 +25,9 @@ class Game { managerStatus: { name: Status; data: StatusDataMap[Status] } | null = null playerStatus: Map = new Map() + leaderboard: Player[] + tempOldLeaderboard: Player[] | null quizz: Quizz players: Player[] @@ -59,7 +61,9 @@ class Game { this.lastBroadcastStatus = null this.managerStatus = null this.playerStatus = new Map() + this.leaderboard = [] + this.tempOldLeaderboard = null this.players = [] @@ -370,6 +374,11 @@ class Game { } showResults(question: any) { + const oldLeaderboard = + this.leaderboard.length === 0 + ? this.players.map((p) => ({ ...p })) + : this.leaderboard.map((p) => ({ ...p })) + const totalType = this.round.playersAnswers.reduce( (acc: Record, { answerId }) => { acc[answerId] = (acc[answerId] || 0) + 1 @@ -422,9 +431,11 @@ class Game { image: question.image, }) + this.leaderboard = sortedPlayers + this.tempOldLeaderboard = oldLeaderboard + this.round.playersAnswers = [] } - selectAnswer(socket: Socket, answerId: number) { const player = this.players.find((player) => player.id === socket.id) const question = this.quizz.questions[this.round.currentQuestion] @@ -491,11 +502,6 @@ class Game { const isLastRound = this.round.currentQuestion + 1 === this.quizz.questions.length - const sortedPlayers = this.players.sort((a, b) => b.points - a.points) - const oldLeaderboard = - this.leaderboard.length === 0 ? sortedPlayers : this.leaderboard - this.leaderboard = this.players.sort((a, b) => b.points - a.points) - if (isLastRound) { this.started = false @@ -507,10 +513,16 @@ class Game { return } + const oldLeaderboard = this.tempOldLeaderboard + ? this.tempOldLeaderboard + : this.leaderboard + this.sendStatus(this.manager.id, STATUS.SHOW_LEADERBOARD, { oldLeaderboard: oldLeaderboard.slice(0, 5), leaderboard: this.leaderboard.slice(0, 5), }) + + this.tempOldLeaderboard = null } } diff --git a/packages/web/src/components/game/states/Leaderboard.tsx b/packages/web/src/components/game/states/Leaderboard.tsx index 4054fcb..364a1fa 100644 --- a/packages/web/src/components/game/states/Leaderboard.tsx +++ b/packages/web/src/components/game/states/Leaderboard.tsx @@ -1,35 +1,57 @@ import { ManagerStatusDataMap } from "@rahoot/common/types/game/status" -import { AnimatePresence, motion } from "motion/react" +import { AnimatePresence, motion, useSpring, useTransform } from "motion/react" import { useEffect, useState } from "react" type Props = { data: ManagerStatusDataMap["SHOW_LEADERBOARD"] } +const AnimatedPoints = ({ from, to }: { from: number; to: number }) => { + const spring = useSpring(from, { stiffness: 1000, damping: 30 }) + const display = useTransform(spring, (value) => Math.round(value)) + const [displayValue, setDisplayValue] = useState(from) + + useEffect(() => { + spring.set(to) + const unsubscribe = display.on("change", (latest) => { + setDisplayValue(latest) + }) + + return unsubscribe + }, [to, spring, display]) + + return {displayValue} +} + const Leaderboard = ({ data: { oldLeaderboard, leaderboard } }: Props) => { const [displayedLeaderboard, setDisplayedLeaderboard] = useState(oldLeaderboard) + const [isAnimating, setIsAnimating] = useState(false) useEffect(() => { setDisplayedLeaderboard(oldLeaderboard) + setIsAnimating(false) const timer = setTimeout(() => { + setIsAnimating(true) setDisplayedLeaderboard(leaderboard) - }, 2000) + }, 1600) - return () => clearTimeout(timer) + return () => { + clearTimeout(timer) + } }, [oldLeaderboard, leaderboard]) return ( -
+

Leaderboard

- {displayedLeaderboard.map(({ username, points }) => ( + {displayedLeaderboard.map(({ id, username, points }) => ( { className="bg-primary flex w-full justify-between rounded-md p-3 text-2xl font-bold text-white" > {username} - {points} + {isAnimating ? ( + u.id === id)?.points || 0} + to={leaderboard.find((u) => u.id === id)?.points || 0} + /> + ) : ( + {points} + )} ))}