mirror of
https://github.com/randyjc/Rahoot.git
synced 2026-03-13 20:15:35 +01:00
fix(game): fix leaderboard old state
This commit is contained in:
@@ -25,7 +25,9 @@ class Game {
|
|||||||
managerStatus: { name: Status; data: StatusDataMap[Status] } | null = null
|
managerStatus: { name: Status; data: StatusDataMap[Status] } | null = null
|
||||||
playerStatus: Map<string, { name: Status; data: StatusDataMap[Status] }> =
|
playerStatus: Map<string, { name: Status; data: StatusDataMap[Status] }> =
|
||||||
new Map()
|
new Map()
|
||||||
|
|
||||||
leaderboard: Player[]
|
leaderboard: Player[]
|
||||||
|
tempOldLeaderboard: Player[] | null
|
||||||
|
|
||||||
quizz: Quizz
|
quizz: Quizz
|
||||||
players: Player[]
|
players: Player[]
|
||||||
@@ -59,7 +61,9 @@ class Game {
|
|||||||
this.lastBroadcastStatus = null
|
this.lastBroadcastStatus = null
|
||||||
this.managerStatus = null
|
this.managerStatus = null
|
||||||
this.playerStatus = new Map()
|
this.playerStatus = new Map()
|
||||||
|
|
||||||
this.leaderboard = []
|
this.leaderboard = []
|
||||||
|
this.tempOldLeaderboard = null
|
||||||
|
|
||||||
this.players = []
|
this.players = []
|
||||||
|
|
||||||
@@ -370,6 +374,11 @@ class Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showResults(question: any) {
|
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(
|
const totalType = this.round.playersAnswers.reduce(
|
||||||
(acc: Record<number, number>, { answerId }) => {
|
(acc: Record<number, number>, { answerId }) => {
|
||||||
acc[answerId] = (acc[answerId] || 0) + 1
|
acc[answerId] = (acc[answerId] || 0) + 1
|
||||||
@@ -422,9 +431,11 @@ class Game {
|
|||||||
image: question.image,
|
image: question.image,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.leaderboard = sortedPlayers
|
||||||
|
this.tempOldLeaderboard = oldLeaderboard
|
||||||
|
|
||||||
this.round.playersAnswers = []
|
this.round.playersAnswers = []
|
||||||
}
|
}
|
||||||
|
|
||||||
selectAnswer(socket: Socket, answerId: number) {
|
selectAnswer(socket: Socket, answerId: number) {
|
||||||
const player = this.players.find((player) => player.id === socket.id)
|
const player = this.players.find((player) => player.id === socket.id)
|
||||||
const question = this.quizz.questions[this.round.currentQuestion]
|
const question = this.quizz.questions[this.round.currentQuestion]
|
||||||
@@ -491,11 +502,6 @@ class Game {
|
|||||||
const isLastRound =
|
const isLastRound =
|
||||||
this.round.currentQuestion + 1 === this.quizz.questions.length
|
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) {
|
if (isLastRound) {
|
||||||
this.started = false
|
this.started = false
|
||||||
|
|
||||||
@@ -507,10 +513,16 @@ class Game {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const oldLeaderboard = this.tempOldLeaderboard
|
||||||
|
? this.tempOldLeaderboard
|
||||||
|
: this.leaderboard
|
||||||
|
|
||||||
this.sendStatus(this.manager.id, STATUS.SHOW_LEADERBOARD, {
|
this.sendStatus(this.manager.id, STATUS.SHOW_LEADERBOARD, {
|
||||||
oldLeaderboard: oldLeaderboard.slice(0, 5),
|
oldLeaderboard: oldLeaderboard.slice(0, 5),
|
||||||
leaderboard: this.leaderboard.slice(0, 5),
|
leaderboard: this.leaderboard.slice(0, 5),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.tempOldLeaderboard = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,57 @@
|
|||||||
import { ManagerStatusDataMap } from "@rahoot/common/types/game/status"
|
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"
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: ManagerStatusDataMap["SHOW_LEADERBOARD"]
|
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 <span className="drop-shadow-md">{displayValue}</span>
|
||||||
|
}
|
||||||
|
|
||||||
const Leaderboard = ({ data: { oldLeaderboard, leaderboard } }: Props) => {
|
const Leaderboard = ({ data: { oldLeaderboard, leaderboard } }: Props) => {
|
||||||
const [displayedLeaderboard, setDisplayedLeaderboard] =
|
const [displayedLeaderboard, setDisplayedLeaderboard] =
|
||||||
useState(oldLeaderboard)
|
useState(oldLeaderboard)
|
||||||
|
const [isAnimating, setIsAnimating] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDisplayedLeaderboard(oldLeaderboard)
|
setDisplayedLeaderboard(oldLeaderboard)
|
||||||
|
setIsAnimating(false)
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
|
setIsAnimating(true)
|
||||||
setDisplayedLeaderboard(leaderboard)
|
setDisplayedLeaderboard(leaderboard)
|
||||||
}, 2000)
|
}, 1600)
|
||||||
|
|
||||||
return () => clearTimeout(timer)
|
return () => {
|
||||||
|
clearTimeout(timer)
|
||||||
|
}
|
||||||
}, [oldLeaderboard, leaderboard])
|
}, [oldLeaderboard, leaderboard])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative mx-auto flex w-full max-w-3xl flex-1 flex-col items-center justify-center px-2">
|
<section className="relative mx-auto flex w-full max-w-4xl flex-1 flex-col items-center justify-center px-2">
|
||||||
<h2 className="mb-6 text-5xl font-bold text-white drop-shadow-md">
|
<h2 className="mb-6 text-5xl font-bold text-white drop-shadow-md">
|
||||||
Leaderboard
|
Leaderboard
|
||||||
</h2>
|
</h2>
|
||||||
<div className="flex w-full flex-col gap-2">
|
<div className="flex w-full flex-col gap-2">
|
||||||
<AnimatePresence mode="popLayout">
|
<AnimatePresence mode="popLayout">
|
||||||
{displayedLeaderboard.map(({ username, points }) => (
|
{displayedLeaderboard.map(({ id, username, points }) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={username}
|
key={id}
|
||||||
layout
|
layout
|
||||||
initial={{ opacity: 0, y: 50 }}
|
initial={{ opacity: 0, y: 50 }}
|
||||||
animate={{
|
animate={{
|
||||||
@@ -51,7 +73,14 @@ const Leaderboard = ({ data: { oldLeaderboard, leaderboard } }: Props) => {
|
|||||||
className="bg-primary flex w-full justify-between rounded-md p-3 text-2xl font-bold text-white"
|
className="bg-primary flex w-full justify-between rounded-md p-3 text-2xl font-bold text-white"
|
||||||
>
|
>
|
||||||
<span className="drop-shadow-md">{username}</span>
|
<span className="drop-shadow-md">{username}</span>
|
||||||
<span className="drop-shadow-md">{points}</span>
|
{isAnimating ? (
|
||||||
|
<AnimatedPoints
|
||||||
|
from={oldLeaderboard.find((u) => u.id === id)?.points || 0}
|
||||||
|
to={leaderboard.find((u) => u.id === id)?.points || 0}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span className="drop-shadow-md">{points}</span>
|
||||||
|
)}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|||||||
Reference in New Issue
Block a user