mirror of
https://github.com/randyjc/Rahoot.git
synced 2026-03-13 20:15:35 +01:00
refactor(components): use arrow function syntax and improve consistency
This commit is contained in:
@@ -8,7 +8,7 @@ import { useManagerStore } from "@rahoot/web/stores/manager"
|
|||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
export default function Manager() {
|
const Manager = () => {
|
||||||
const { setGameId, setStatus } = useManagerStore()
|
const { setGameId, setStatus } = useManagerStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { socket } = useSocket()
|
const { socket } = useSocket()
|
||||||
@@ -40,3 +40,5 @@ export default function Manager() {
|
|||||||
|
|
||||||
return <SelectQuizz quizzList={quizzList} onSelect={handleCreate} />
|
return <SelectQuizz quizzList={quizzList} onSelect={handleCreate} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Manager
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { usePlayerStore } from "@rahoot/web/stores/player"
|
|||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import toast from "react-hot-toast"
|
import toast from "react-hot-toast"
|
||||||
|
|
||||||
export default function Home() {
|
const Home = () => {
|
||||||
const { isConnected, connect } = useSocket()
|
const { isConnected, connect } = useSocket()
|
||||||
const { player } = usePlayerStore()
|
const { player } = usePlayerStore()
|
||||||
|
|
||||||
@@ -27,3 +27,5 @@ export default function Home() {
|
|||||||
|
|
||||||
return <Room />
|
return <Room />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Home
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { GAME_STATE_COMPONENTS } from "@rahoot/web/utils/constants"
|
|||||||
import { useParams, useRouter } from "next/navigation"
|
import { useParams, useRouter } from "next/navigation"
|
||||||
import toast from "react-hot-toast"
|
import toast from "react-hot-toast"
|
||||||
|
|
||||||
export default function Game() {
|
const Game = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { socket } = useSocket()
|
const { socket } = useSocket()
|
||||||
const { gameId: gameIdParam }: { gameId?: string } = useParams()
|
const { gameId: gameIdParam }: { gameId?: string } = useParams()
|
||||||
@@ -95,3 +95,5 @@ export default function Game() {
|
|||||||
|
|
||||||
return <GameWrapper statusName={status.name}>{component}</GameWrapper>
|
return <GameWrapper statusName={status.name}>{component}</GameWrapper>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Game
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { GAME_STATE_COMPONENTS_MANAGER } from "@rahoot/web/utils/constants"
|
|||||||
import { useParams, useRouter } from "next/navigation"
|
import { useParams, useRouter } from "next/navigation"
|
||||||
import toast from "react-hot-toast"
|
import toast from "react-hot-toast"
|
||||||
|
|
||||||
export default function ManagerGame() {
|
const ManagerGame = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { gameId: gameIdParam }: { gameId?: string } = useParams()
|
const { gameId: gameIdParam }: { gameId?: string } = useParams()
|
||||||
const { socket } = useSocket()
|
const { socket } = useSocket()
|
||||||
@@ -131,3 +131,5 @@ export default function ManagerGame() {
|
|||||||
</GameWrapper>
|
</GameWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default ManagerGame
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ export const metadata: Metadata = {
|
|||||||
icons: "/icon.svg",
|
icons: "/icon.svg",
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RootLayout({ children }: PropsWithChildren) {
|
const RootLayout = ({ children }: PropsWithChildren) => (
|
||||||
return (
|
<html lang="en" suppressHydrationWarning={true} data-lt-installed="true">
|
||||||
<html lang="en" suppressHydrationWarning={true} data-lt-installed="true">
|
<body className={`${montserrat.variable} bg-secondary antialiased`}>
|
||||||
<body className={`${montserrat.variable} bg-secondary antialiased`}>
|
<SocketProvider>
|
||||||
<SocketProvider>
|
<main className="text-base-[8px] flex flex-col">{children}</main>
|
||||||
<main className="text-base-[8px] flex flex-col">{children}</main>
|
<Toaster />
|
||||||
<Toaster />
|
</SocketProvider>
|
||||||
</SocketProvider>
|
</body>
|
||||||
</body>
|
</html>
|
||||||
</html>
|
)
|
||||||
)
|
|
||||||
}
|
export default RootLayout
|
||||||
|
|||||||
@@ -6,22 +6,22 @@ type Props = PropsWithChildren &
|
|||||||
icon: ElementType
|
icon: ElementType
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AnswerButton({
|
const AnswerButton = ({
|
||||||
className,
|
className,
|
||||||
icon: Icon,
|
icon: Icon,
|
||||||
children,
|
children,
|
||||||
...otherProps
|
...otherProps
|
||||||
}: Props) {
|
}: Props) => (
|
||||||
return (
|
<button
|
||||||
<button
|
className={clsx(
|
||||||
className={clsx(
|
"shadow-inset flex items-center gap-3 rounded px-4 py-6 text-left",
|
||||||
"shadow-inset flex items-center gap-3 rounded px-4 py-6 text-left",
|
className,
|
||||||
className,
|
)}
|
||||||
)}
|
{...otherProps}
|
||||||
{...otherProps}
|
>
|
||||||
>
|
<Icon className="h-6 w-6" />
|
||||||
<Icon className="h-6 w-6" />
|
<span className="drop-shadow-md">{children}</span>
|
||||||
<span className="drop-shadow-md">{children}</span>
|
</button>
|
||||||
</button>
|
)
|
||||||
)
|
|
||||||
}
|
export default AnswerButton
|
||||||
|
|||||||
@@ -2,16 +2,17 @@ import clsx from "clsx"
|
|||||||
import { ButtonHTMLAttributes, PropsWithChildren } from "react"
|
import { ButtonHTMLAttributes, PropsWithChildren } from "react"
|
||||||
|
|
||||||
type Props = ButtonHTMLAttributes<HTMLButtonElement> & PropsWithChildren
|
type Props = ButtonHTMLAttributes<HTMLButtonElement> & PropsWithChildren
|
||||||
export default function Button({ children, className, ...otherProps }: Props) {
|
|
||||||
return (
|
const Button = ({ children, className, ...otherProps }: Props) => (
|
||||||
<button
|
<button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"btn-shadow bg-primary rounded-md p-2 text-lg font-semibold text-white",
|
"btn-shadow bg-primary rounded-md p-2 text-lg font-semibold text-white",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
<span>{children}</span>
|
<span>{children}</span>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
export default Button
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { PropsWithChildren } from "react"
|
import { PropsWithChildren } from "react"
|
||||||
|
|
||||||
export default function Form({ children }: PropsWithChildren) {
|
const Form = ({ children }: PropsWithChildren) => (
|
||||||
return (
|
<div className="z-10 flex w-full max-w-80 flex-col gap-4 rounded-md bg-white p-4 shadow-sm">
|
||||||
<div className="z-10 flex w-full max-w-80 flex-col gap-4 rounded-md bg-white p-4 shadow-sm">
|
{children}
|
||||||
{children}
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
|
||||||
}
|
export default Form
|
||||||
|
|||||||
@@ -3,19 +3,15 @@ import React from "react"
|
|||||||
|
|
||||||
type Props = React.InputHTMLAttributes<HTMLInputElement>
|
type Props = React.InputHTMLAttributes<HTMLInputElement>
|
||||||
|
|
||||||
export default function Input({
|
const Input = ({ className, type = "text", ...otherProps }: Props) => (
|
||||||
className,
|
<input
|
||||||
type = "text",
|
type={type}
|
||||||
...otherProps
|
className={clsx(
|
||||||
}: Props) {
|
"rounded-sm p-2 text-lg font-semibold outline-2 outline-gray-300",
|
||||||
return (
|
className,
|
||||||
<input
|
)}
|
||||||
type={type}
|
{...otherProps}
|
||||||
className={clsx(
|
/>
|
||||||
"rounded-sm p-2 text-lg font-semibold outline-2 outline-gray-300",
|
)
|
||||||
className,
|
|
||||||
)}
|
export default Input
|
||||||
{...otherProps}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
import { Status } from "@rahoot/common/types/game/status"
|
import { Status } from "@rahoot/common/types/game/status"
|
||||||
import background from "@rahoot/web/assets/background.webp"
|
import background from "@rahoot/web/assets/background.webp"
|
||||||
import Button from "@rahoot/web/components/Button"
|
import Button from "@rahoot/web/components/Button"
|
||||||
|
import Loader from "@rahoot/web/components/Loader"
|
||||||
import { useEvent, useSocket } from "@rahoot/web/contexts/socketProvider"
|
import { useEvent, useSocket } from "@rahoot/web/contexts/socketProvider"
|
||||||
import { usePlayerStore } from "@rahoot/web/stores/player"
|
import { usePlayerStore } from "@rahoot/web/stores/player"
|
||||||
import { useQuestionStore } from "@rahoot/web/stores/question"
|
import { useQuestionStore } from "@rahoot/web/stores/question"
|
||||||
import { MANAGER_SKIP_BTN } from "@rahoot/web/utils/constants"
|
import { MANAGER_SKIP_BTN } from "@rahoot/web/utils/constants"
|
||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
import { PropsWithChildren } from "react"
|
import { PropsWithChildren } from "react"
|
||||||
import Loader from "../Loader"
|
|
||||||
|
|
||||||
type Props = PropsWithChildren & {
|
type Props = PropsWithChildren & {
|
||||||
statusName: Status
|
statusName: Status
|
||||||
@@ -17,12 +17,7 @@ type Props = PropsWithChildren & {
|
|||||||
manager?: boolean
|
manager?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function GameWrapper({
|
const GameWrapper = ({ children, statusName, onNext, manager }: Props) => {
|
||||||
children,
|
|
||||||
statusName,
|
|
||||||
onNext,
|
|
||||||
manager,
|
|
||||||
}: Props) {
|
|
||||||
const { isConnected } = useSocket()
|
const { isConnected } = useSocket()
|
||||||
const { player } = usePlayerStore()
|
const { player } = usePlayerStore()
|
||||||
const { questionStates, setQuestionStates } = useQuestionStore()
|
const { questionStates, setQuestionStates } = useQuestionStore()
|
||||||
@@ -61,7 +56,7 @@ export default function GameWrapper({
|
|||||||
|
|
||||||
{manager && next && (
|
{manager && next && (
|
||||||
<Button
|
<Button
|
||||||
className="self-end bg-white px-4 !text-black"
|
className="self-end bg-white px-4 text-black!"
|
||||||
onClick={onNext}
|
onClick={onNext}
|
||||||
>
|
>
|
||||||
{next}
|
{next}
|
||||||
@@ -84,3 +79,5 @@ export default function GameWrapper({
|
|||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default GameWrapper
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ type Props = {
|
|||||||
onSubmit: (_password: string) => void
|
onSubmit: (_password: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ManagerPassword({ onSubmit }: Props) {
|
const ManagerPassword = ({ onSubmit }: Props) => {
|
||||||
const [password, setPassword] = useState("")
|
const [password, setPassword] = useState("")
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
@@ -38,3 +38,5 @@ export default function ManagerPassword({ onSubmit }: Props) {
|
|||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default ManagerPassword
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ type Props = {
|
|||||||
onSelect: (_id: string) => void
|
onSelect: (_id: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SelectQuizz({ quizzList, onSelect }: Props) {
|
const SelectQuizz = ({ quizzList, onSelect }: Props) => {
|
||||||
const [selected, setSelected] = useState<string | null>(null)
|
const [selected, setSelected] = useState<string | null>(null)
|
||||||
|
|
||||||
const handleSelect = (id: string) => () => {
|
const handleSelect = (id: string) => () => {
|
||||||
@@ -62,3 +62,5 @@ export default function SelectQuizz({ quizzList, onSelect }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default SelectQuizz
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useEvent, useSocket } from "@rahoot/web/contexts/socketProvider"
|
|||||||
import { usePlayerStore } from "@rahoot/web/stores/player"
|
import { usePlayerStore } from "@rahoot/web/stores/player"
|
||||||
import { KeyboardEvent, useState } from "react"
|
import { KeyboardEvent, useState } from "react"
|
||||||
|
|
||||||
export default function Room() {
|
const Room = () => {
|
||||||
const { socket } = useSocket()
|
const { socket } = useSocket()
|
||||||
const { join } = usePlayerStore()
|
const { join } = usePlayerStore()
|
||||||
const [invitation, setInvitation] = useState("")
|
const [invitation, setInvitation] = useState("")
|
||||||
@@ -35,3 +35,5 @@ export default function Room() {
|
|||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Room
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { usePlayerStore } from "@rahoot/web/stores/player"
|
|||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { KeyboardEvent, useState } from "react"
|
import { KeyboardEvent, useState } from "react"
|
||||||
|
|
||||||
export default function Username() {
|
const Username = () => {
|
||||||
const { socket } = useSocket()
|
const { socket } = useSocket()
|
||||||
const { gameId, login } = usePlayerStore()
|
const { gameId, login } = usePlayerStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -46,3 +46,5 @@ export default function Username() {
|
|||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Username
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ type Props = {
|
|||||||
data: CommonStatusDataMap["SELECT_ANSWER"]
|
data: CommonStatusDataMap["SELECT_ANSWER"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Answers({
|
const Answers = ({
|
||||||
data: { question, answers, image, time, totalPlayer },
|
data: { question, answers, image, time, totalPlayer },
|
||||||
}: Props) {
|
}: Props) => {
|
||||||
const { gameId }: { gameId?: string } = useParams()
|
const { gameId }: { gameId?: string } = useParams()
|
||||||
const { socket } = useSocket()
|
const { socket } = useSocket()
|
||||||
const { player } = usePlayerStore()
|
const { player } = usePlayerStore()
|
||||||
@@ -116,3 +116,5 @@ export default function Answers({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Answers
|
||||||
|
|||||||
@@ -4,23 +4,23 @@ type Props = {
|
|||||||
data: ManagerStatusDataMap["SHOW_LEADERBOARD"]
|
data: ManagerStatusDataMap["SHOW_LEADERBOARD"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Leaderboard({ data: { leaderboard } }: Props) {
|
const Leaderboard = ({ data: { leaderboard } }: Props) => (
|
||||||
return (
|
<section className="relative mx-auto flex w-full max-w-7xl flex-1 flex-col items-center justify-center px-2">
|
||||||
<section className="relative mx-auto flex w-full max-w-7xl 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">
|
{leaderboard.map(({ username, points }, key) => (
|
||||||
{leaderboard.map(({ username, points }, key) => (
|
<div
|
||||||
<div
|
key={key}
|
||||||
key={key}
|
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>
|
||||||
<span className="drop-shadow-md">{points}</span>
|
</div>
|
||||||
</div>
|
))}
|
||||||
))}
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</section>
|
)
|
||||||
)
|
|
||||||
}
|
export default Leaderboard
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ type Props = {
|
|||||||
data: ManagerStatusDataMap["FINISHED"]
|
data: ManagerStatusDataMap["FINISHED"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Podium({ data: { subject, top } }: Props) {
|
const Podium = ({ data: { subject, top } }: Props) => {
|
||||||
const [apparition, setApparition] = useState(0)
|
const [apparition, setApparition] = useState(0)
|
||||||
|
|
||||||
const { width, height } = useScreenSize()
|
const { width, height } = useScreenSize()
|
||||||
@@ -112,7 +112,7 @@ export default function Podium({ data: { subject, top } }: Props) {
|
|||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"z-20 flex h-[50%] w-full translate-y-full flex-col items-center justify-center gap-3 opacity-0 transition-all",
|
"z-20 flex h-[50%] w-full translate-y-full flex-col items-center justify-center gap-3 opacity-0 transition-all",
|
||||||
{ "!translate-y-0 opacity-100": apparition >= 2 },
|
{ "translate-y-0! opacity-100": apparition >= 2 },
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<p
|
<p
|
||||||
@@ -140,7 +140,7 @@ export default function Podium({ data: { subject, top } }: Props) {
|
|||||||
className={clsx(
|
className={clsx(
|
||||||
"z-30 flex h-[60%] w-full translate-y-full flex-col items-center gap-3 opacity-0 transition-all",
|
"z-30 flex h-[60%] w-full translate-y-full flex-col items-center gap-3 opacity-0 transition-all",
|
||||||
{
|
{
|
||||||
"!translate-y-0 opacity-100": apparition >= 3,
|
"translate-y-0! opacity-100": apparition >= 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"md:min-w-64": top.length < 2,
|
"md:min-w-64": top.length < 2,
|
||||||
@@ -170,7 +170,7 @@ export default function Podium({ data: { subject, top } }: Props) {
|
|||||||
className={clsx(
|
className={clsx(
|
||||||
"z-10 flex h-[40%] w-full translate-y-full flex-col items-center gap-3 opacity-0 transition-all",
|
"z-10 flex h-[40%] w-full translate-y-full flex-col items-center gap-3 opacity-0 transition-all",
|
||||||
{
|
{
|
||||||
"!translate-y-0 opacity-100": apparition >= 1,
|
"translate-y-0! opacity-100": apparition >= 1,
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -200,3 +200,5 @@ export default function Podium({ data: { subject, top } }: Props) {
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Podium
|
||||||
|
|||||||
@@ -7,27 +7,25 @@ type Props = {
|
|||||||
data: CommonStatusDataMap["SHOW_PREPARED"]
|
data: CommonStatusDataMap["SHOW_PREPARED"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Prepared({
|
const Prepared = ({ data: { totalAnswers, questionNumber } }: Props) => (
|
||||||
data: { totalAnswers, questionNumber },
|
<section className="anim-show relative mx-auto flex w-full max-w-7xl flex-1 flex-col items-center justify-center">
|
||||||
}: Props) {
|
<h2 className="anim-show mb-20 text-center text-3xl font-bold text-white drop-shadow-lg md:text-4xl lg:text-5xl">
|
||||||
return (
|
Question #{questionNumber}
|
||||||
<section className="anim-show relative mx-auto flex w-full max-w-7xl flex-1 flex-col items-center justify-center">
|
</h2>
|
||||||
<h2 className="anim-show mb-20 text-center text-3xl font-bold text-white drop-shadow-lg md:text-4xl lg:text-5xl">
|
<div className="anim-quizz grid aspect-square w-60 grid-cols-2 gap-4 rounded-2xl bg-gray-700 p-5 md:w-60">
|
||||||
Question #{questionNumber}
|
{[...Array(totalAnswers)].map((_, key) => (
|
||||||
</h2>
|
<div
|
||||||
<div className="anim-quizz grid aspect-square w-60 grid-cols-2 gap-4 rounded-2xl bg-gray-700 p-5 md:w-60">
|
key={key}
|
||||||
{[...Array(totalAnswers)].map((_, key) => (
|
className={clsx(
|
||||||
<div
|
"button shadow-inset flex aspect-square h-full w-full items-center justify-center rounded-2xl",
|
||||||
key={key}
|
ANSWERS_COLORS[key],
|
||||||
className={clsx(
|
)}
|
||||||
"button shadow-inset flex aspect-square h-full w-full items-center justify-center rounded-2xl",
|
>
|
||||||
ANSWERS_COLORS[key],
|
{createElement(ANSWERS_ICONS[key], { className: "h-10 md:h-14" })}
|
||||||
)}
|
</div>
|
||||||
>
|
))}
|
||||||
{createElement(ANSWERS_ICONS[key], { className: "h-10 md:h-14" })}
|
</div>
|
||||||
</div>
|
</section>
|
||||||
))}
|
)
|
||||||
</div>
|
|
||||||
</section>
|
export default Prepared
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ type Props = {
|
|||||||
data: CommonStatusDataMap["SHOW_QUESTION"]
|
data: CommonStatusDataMap["SHOW_QUESTION"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Question({
|
const Question = ({ data: { question, image, cooldown } }: Props) => {
|
||||||
data: { question, image, cooldown },
|
|
||||||
}: Props) {
|
|
||||||
const [sfxShow] = useSound(SFX_SHOW_SOUND, { volume: 0.5 })
|
const [sfxShow] = useSound(SFX_SHOW_SOUND, { volume: 0.5 })
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -40,3 +38,5 @@ export default function Question({
|
|||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Question
|
||||||
|
|||||||
@@ -1,48 +1,25 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { ManagerStatusDataMap } from "@rahoot/common/types/game/status"
|
import { ManagerStatusDataMap } from "@rahoot/common/types/game/status"
|
||||||
|
import AnswerButton from "@rahoot/web/components/AnswerButton"
|
||||||
import {
|
import {
|
||||||
ANSWERS_COLORS,
|
ANSWERS_COLORS,
|
||||||
ANSWERS_ICONS,
|
ANSWERS_ICONS,
|
||||||
SFX_ANSWERS_MUSIC,
|
SFX_ANSWERS_MUSIC,
|
||||||
SFX_RESULTS_SOUND,
|
SFX_RESULTS_SOUND,
|
||||||
} from "@rahoot/web/utils/constants"
|
} from "@rahoot/web/utils/constants"
|
||||||
|
import { calculatePercentages } from "@rahoot/web/utils/score"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import useSound from "use-sound"
|
import useSound from "use-sound"
|
||||||
import AnswerButton from "../../AnswerButton"
|
|
||||||
|
|
||||||
const calculatePercentages = (
|
|
||||||
objectResponses: Record<string, number>,
|
|
||||||
): Record<string, string> => {
|
|
||||||
const keys = Object.keys(objectResponses)
|
|
||||||
const values = Object.values(objectResponses)
|
|
||||||
|
|
||||||
if (!values.length) {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
const totalSum = values.reduce(
|
|
||||||
(accumulator, currentValue) => accumulator + currentValue,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
|
|
||||||
const result: Record<string, string> = {}
|
|
||||||
|
|
||||||
keys.forEach((key) => {
|
|
||||||
result[key] = `${((objectResponses[key] / totalSum) * 100).toFixed()}%`
|
|
||||||
})
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: ManagerStatusDataMap["SHOW_RESPONSES"]
|
data: ManagerStatusDataMap["SHOW_RESPONSES"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Responses({
|
const Responses = ({
|
||||||
data: { question, answers, responses, correct },
|
data: { question, answers, responses, correct },
|
||||||
}: Props) {
|
}: Props) => {
|
||||||
const [percentages, setPercentages] = useState<Record<string, string>>({})
|
const [percentages, setPercentages] = useState<Record<string, string>>({})
|
||||||
const [isMusicPlaying, setIsMusicPlaying] = useState(false)
|
const [isMusicPlaying, setIsMusicPlaying] = useState(false)
|
||||||
|
|
||||||
@@ -123,3 +100,5 @@ export default function Responses({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Responses
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ type Props = {
|
|||||||
data: CommonStatusDataMap["SHOW_RESULT"]
|
data: CommonStatusDataMap["SHOW_RESULT"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Result({
|
const Result = ({
|
||||||
data: { correct, message, points, myPoints, rank, aheadOfMe },
|
data: { correct, message, points, myPoints, rank, aheadOfMe },
|
||||||
}: Props) {
|
}: Props) => {
|
||||||
const player = usePlayerStore()
|
const player = usePlayerStore()
|
||||||
|
|
||||||
const [sfxResults] = useSound(SFX_RESULTS_SOUND, {
|
const [sfxResults] = useSound(SFX_RESULTS_SOUND, {
|
||||||
@@ -48,3 +48,5 @@ export default function Result({
|
|||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Result
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ type Props = {
|
|||||||
data: ManagerStatusDataMap["SHOW_ROOM"]
|
data: ManagerStatusDataMap["SHOW_ROOM"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Room({ data: { text, inviteCode } }: Props) {
|
const Room = ({ data: { text, inviteCode } }: Props) => {
|
||||||
const { socket } = useSocket()
|
const { socket } = useSocket()
|
||||||
const { players } = useManagerStore()
|
const { players } = useManagerStore()
|
||||||
const [playerList, setPlayerList] = useState<Player[]>(players)
|
const [playerList, setPlayerList] = useState<Player[]>(players)
|
||||||
@@ -70,3 +70,5 @@ export default function Room({ data: { text, inviteCode } }: Props) {
|
|||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Room
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ type Props = {
|
|||||||
data: CommonStatusDataMap["SHOW_START"]
|
data: CommonStatusDataMap["SHOW_START"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Start({ data: { time, subject } }: Props) {
|
const Start = ({ data: { time, subject } }: Props) => {
|
||||||
const [showTitle, setShowTitle] = useState(true)
|
const [showTitle, setShowTitle] = useState(true)
|
||||||
const [cooldown, setCooldown] = useState(time)
|
const [cooldown, setCooldown] = useState(time)
|
||||||
|
|
||||||
@@ -53,3 +53,5 @@ export default function Start({ data: { time, subject } }: Props) {
|
|||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Start
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ type Props = {
|
|||||||
data: PlayerStatusDataMap["WAIT"]
|
data: PlayerStatusDataMap["WAIT"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Wait({ data: { text } }: Props) {
|
const Wait = ({ data: { text } }: Props) => (
|
||||||
return (
|
<section className="relative mx-auto flex w-full max-w-7xl flex-1 flex-col items-center justify-center">
|
||||||
<section className="relative mx-auto flex w-full max-w-7xl flex-1 flex-col items-center justify-center">
|
<Loader />
|
||||||
<Loader />
|
<h2 className="mt-5 text-center text-3xl font-bold text-white drop-shadow-lg md:text-4xl lg:text-5xl">
|
||||||
<h2 className="mt-5 text-center text-3xl font-bold text-white drop-shadow-lg md:text-4xl lg:text-5xl">
|
{text}
|
||||||
{text}
|
</h2>
|
||||||
</h2>
|
</section>
|
||||||
</section>
|
)
|
||||||
)
|
|
||||||
}
|
export default Wait
|
||||||
|
|||||||
@@ -3,28 +3,22 @@ type Props = {
|
|||||||
fill?: string
|
fill?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Circle({ className, fill = "#FFF" }: Props) {
|
const Circle = ({ className, fill = "#FFF" }: Props) => (
|
||||||
return (
|
<svg
|
||||||
<svg
|
className={className}
|
||||||
className={className}
|
viewBox="0 0 512 512"
|
||||||
viewBox="0 0 512 512"
|
version="1.1"
|
||||||
version="1.1"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
>
|
||||||
>
|
<g id="Page-1" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
||||||
<g
|
<g id="icon" fill={fill} transform="translate(42.666667, 42.666667)">
|
||||||
id="Page-1"
|
<path
|
||||||
stroke="none"
|
d="M213.333333,3.55271368e-14 C331.15408,3.55271368e-14 426.666667,95.5125867 426.666667,213.333333 C426.666667,331.15408 331.15408,426.666667 213.333333,426.666667 C95.5125867,426.666667 3.55271368e-14,331.15408 3.55271368e-14,213.333333 C3.55271368e-14,95.5125867 95.5125867,3.55271368e-14 213.333333,3.55271368e-14 Z"
|
||||||
strokeWidth="1"
|
id="Combined-Shape"
|
||||||
fill="none"
|
></path>
|
||||||
fillRule="evenodd"
|
|
||||||
>
|
|
||||||
<g id="icon" fill={fill} transform="translate(42.666667, 42.666667)">
|
|
||||||
<path
|
|
||||||
d="M213.333333,3.55271368e-14 C331.15408,3.55271368e-14 426.666667,95.5125867 426.666667,213.333333 C426.666667,331.15408 331.15408,426.666667 213.333333,426.666667 C95.5125867,426.666667 3.55271368e-14,331.15408 3.55271368e-14,213.333333 C3.55271368e-14,95.5125867 95.5125867,3.55271368e-14 213.333333,3.55271368e-14 Z"
|
|
||||||
id="Combined-Shape"
|
|
||||||
></path>
|
|
||||||
</g>
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</g>
|
||||||
)
|
</svg>
|
||||||
}
|
)
|
||||||
|
|
||||||
|
export default Circle
|
||||||
|
|||||||
@@ -2,40 +2,40 @@ type Props = {
|
|||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CricleCheck({ className }: Props) {
|
const CricleCheck = ({ className }: Props) => (
|
||||||
return (
|
<svg
|
||||||
<svg
|
fill="#22c55e"
|
||||||
fill="#22c55e"
|
width="800px"
|
||||||
width="800px"
|
height="800px"
|
||||||
height="800px"
|
viewBox="0 0 56.00 56.00"
|
||||||
viewBox="0 0 56.00 56.00"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
stroke="#22c55e"
|
||||||
stroke="#22c55e"
|
strokeWidth="0.00056"
|
||||||
strokeWidth="0.00056"
|
className={className}
|
||||||
className={className}
|
>
|
||||||
>
|
<g strokeWidth="0" transform="translate(11.2,11.2), scale(0.6)">
|
||||||
<g strokeWidth="0" transform="translate(11.2,11.2), scale(0.6)">
|
<rect
|
||||||
<rect
|
x="0"
|
||||||
x="0"
|
y="0"
|
||||||
y="0"
|
width="56.00"
|
||||||
width="56.00"
|
height="56.00"
|
||||||
height="56.00"
|
rx="28"
|
||||||
rx="28"
|
fill="#ffffff"
|
||||||
fill="#ffffff"
|
strokeWidth="0"
|
||||||
strokeWidth="0"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<g
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
stroke="#CCCCCC"
|
|
||||||
strokeWidth="0.6719999999999999"
|
|
||||||
/>
|
/>
|
||||||
|
</g>
|
||||||
|
|
||||||
<g>
|
<g
|
||||||
<path d="M 27.9999 51.9063 C 41.0546 51.9063 51.9063 41.0781 51.9063 28 C 51.9063 14.9453 41.0312 4.0937 27.9765 4.0937 C 14.8983 4.0937 4.0937 14.9453 4.0937 28 C 4.0937 41.0781 14.9218 51.9063 27.9999 51.9063 Z M 24.7655 40.0234 C 23.9687 40.0234 23.3593 39.6719 22.6796 38.8750 L 15.9296 30.5312 C 15.5780 30.0859 15.3671 29.5234 15.3671 29.0078 C 15.3671 27.9063 16.2343 27.0625 17.2655 27.0625 C 17.9452 27.0625 18.5077 27.3203 19.0702 28.0469 L 24.6718 35.2890 L 35.5702 17.8281 C 36.0155 17.1016 36.6249 16.75 37.2343 16.75 C 38.2655 16.75 39.2733 17.4297 39.2733 18.5547 C 39.2733 19.0703 38.9687 19.6328 38.6640 20.1016 L 26.7577 38.8750 C 26.2421 39.6484 25.5858 40.0234 24.7655 40.0234 Z" />
|
strokeLinecap="round"
|
||||||
</g>
|
strokeLinejoin="round"
|
||||||
</svg>
|
stroke="#CCCCCC"
|
||||||
)
|
strokeWidth="0.6719999999999999"
|
||||||
}
|
/>
|
||||||
|
|
||||||
|
<g>
|
||||||
|
<path d="M 27.9999 51.9063 C 41.0546 51.9063 51.9063 41.0781 51.9063 28 C 51.9063 14.9453 41.0312 4.0937 27.9765 4.0937 C 14.8983 4.0937 4.0937 14.9453 4.0937 28 C 4.0937 41.0781 14.9218 51.9063 27.9999 51.9063 Z M 24.7655 40.0234 C 23.9687 40.0234 23.3593 39.6719 22.6796 38.8750 L 15.9296 30.5312 C 15.5780 30.0859 15.3671 29.5234 15.3671 29.0078 C 15.3671 27.9063 16.2343 27.0625 17.2655 27.0625 C 17.9452 27.0625 18.5077 27.3203 19.0702 28.0469 L 24.6718 35.2890 L 35.5702 17.8281 C 36.0155 17.1016 36.6249 16.75 37.2343 16.75 C 38.2655 16.75 39.2733 17.4297 39.2733 18.5547 C 39.2733 19.0703 38.9687 19.6328 38.6640 20.1016 L 26.7577 38.8750 C 26.2421 39.6484 25.5858 40.0234 24.7655 40.0234 Z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default CricleCheck
|
||||||
|
|||||||
@@ -2,34 +2,34 @@ type Props = {
|
|||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CricleXmark({ className }: Props) {
|
const CricleXmark = ({ className }: Props) => (
|
||||||
return (
|
<svg
|
||||||
<svg
|
fill="#ef4444"
|
||||||
fill="#ef4444"
|
width="800px"
|
||||||
width="800px"
|
height="800px"
|
||||||
height="800px"
|
viewBox="0 0 56.00 56.00"
|
||||||
viewBox="0 0 56.00 56.00"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
stroke="#ef4444"
|
||||||
stroke="#ef4444"
|
className={className}
|
||||||
className={className}
|
>
|
||||||
>
|
<g strokeWidth="0" transform="translate(12.4,12.4), scale(0.6)">
|
||||||
<g strokeWidth="0" transform="translate(12.4,12.4), scale(0.6)">
|
<rect
|
||||||
<rect
|
x="0"
|
||||||
x="0"
|
y="0"
|
||||||
y="0"
|
width="56.00"
|
||||||
width="56.00"
|
height="56.00"
|
||||||
height="56.00"
|
rx="28"
|
||||||
rx="28"
|
fill="#ffffff"
|
||||||
fill="#ffffff"
|
strokeWidth="0"
|
||||||
strokeWidth="0"
|
/>
|
||||||
/>
|
</g>
|
||||||
</g>
|
|
||||||
|
|
||||||
<g strokeLinecap="round" strokeLinejoin="round" />
|
<g strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
|
||||||
<g>
|
<g>
|
||||||
<path d="M 27.9999 51.9063 C 41.0546 51.9063 51.9063 41.0781 51.9063 28 C 51.9063 14.9453 41.0312 4.0937 27.9765 4.0937 C 14.8983 4.0937 4.0937 14.9453 4.0937 28 C 4.0937 41.0781 14.9218 51.9063 27.9999 51.9063 Z M 19.5858 38.4063 C 18.4843 38.4063 17.5936 37.5156 17.5936 36.4141 C 17.5936 35.8750 17.8280 35.4063 18.2030 35.0547 L 25.1874 28.0234 L 18.2030 20.9922 C 17.8280 20.6641 17.5936 20.1719 17.5936 19.6328 C 17.5936 18.5547 18.4843 17.6875 19.5858 17.6875 C 20.1249 17.6875 20.5936 17.8984 20.9452 18.2734 L 27.9765 25.2812 L 35.0546 18.25 C 35.4530 17.8281 35.8749 17.6406 36.3905 17.6406 C 37.4921 17.6406 38.3827 18.5312 38.3827 19.6094 C 38.3827 20.1484 38.1952 20.5937 37.7968 20.9688 L 30.7655 28.0234 L 37.7733 35.0078 C 38.1249 35.3828 38.3593 35.8516 38.3593 36.4141 C 38.3593 37.5156 37.4687 38.4063 36.3671 38.4063 C 35.8046 38.4063 35.3358 38.1719 34.9843 37.8203 L 27.9765 30.7890 L 20.9921 37.8203 C 20.6405 38.1953 20.1249 38.4063 19.5858 38.4063 Z" />
|
<path d="M 27.9999 51.9063 C 41.0546 51.9063 51.9063 41.0781 51.9063 28 C 51.9063 14.9453 41.0312 4.0937 27.9765 4.0937 C 14.8983 4.0937 4.0937 14.9453 4.0937 28 C 4.0937 41.0781 14.9218 51.9063 27.9999 51.9063 Z M 19.5858 38.4063 C 18.4843 38.4063 17.5936 37.5156 17.5936 36.4141 C 17.5936 35.8750 17.8280 35.4063 18.2030 35.0547 L 25.1874 28.0234 L 18.2030 20.9922 C 17.8280 20.6641 17.5936 20.1719 17.5936 19.6328 C 17.5936 18.5547 18.4843 17.6875 19.5858 17.6875 C 20.1249 17.6875 20.5936 17.8984 20.9452 18.2734 L 27.9765 25.2812 L 35.0546 18.25 C 35.4530 17.8281 35.8749 17.6406 36.3905 17.6406 C 37.4921 17.6406 38.3827 18.5312 38.3827 19.6094 C 38.3827 20.1484 38.1952 20.5937 37.7968 20.9688 L 30.7655 28.0234 L 37.7733 35.0078 C 38.1249 35.3828 38.3593 35.8516 38.3593 36.4141 C 38.3593 37.5156 37.4687 38.4063 36.3671 38.4063 C 35.8046 38.4063 35.3358 38.1719 34.9843 37.8203 L 27.9765 30.7890 L 20.9921 37.8203 C 20.6405 38.1953 20.1249 38.4063 19.5858 38.4063 Z" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
export default CricleXmark
|
||||||
|
|||||||
@@ -4,43 +4,43 @@ type Props = {
|
|||||||
stroke?: string
|
stroke?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Pentagon({ className, fill, stroke }: Props) {
|
const Pentagon = ({ className, fill, stroke }: Props) => (
|
||||||
return (
|
<svg
|
||||||
<svg
|
className={className}
|
||||||
className={className}
|
fill={fill}
|
||||||
fill={fill}
|
height="800px"
|
||||||
height="800px"
|
width="800px"
|
||||||
width="800px"
|
version="1.1"
|
||||||
version="1.1"
|
id="Layer_1"
|
||||||
id="Layer_1"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
viewBox="-40.96 -40.96 593.93 593.93"
|
||||||
viewBox="-40.96 -40.96 593.93 593.93"
|
transform="rotate(180)"
|
||||||
transform="rotate(180)"
|
stroke={fill}
|
||||||
stroke={fill}
|
strokeWidth="0.005120100000000001"
|
||||||
strokeWidth="0.005120100000000001"
|
>
|
||||||
|
<g strokeWidth="0" />
|
||||||
|
|
||||||
|
<g
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
stroke={stroke}
|
||||||
|
strokeWidth="71.6814"
|
||||||
>
|
>
|
||||||
<g strokeWidth="0" />
|
|
||||||
|
|
||||||
<g
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
stroke={stroke}
|
|
||||||
strokeWidth="71.6814"
|
|
||||||
>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path d="M507.804,200.28L262.471,12.866c-3.84-2.923-9.131-2.923-12.949,0L4.188,200.28c-3.605,2.773-5.077,7.531-3.648,11.84 l93.717,281.92c1.451,4.373,5.525,7.296,10.133,7.296h303.253c4.587,0,8.683-2.944,10.133-7.296l93.717-281.92 C512.882,207.789,511.41,203.053,507.804,200.28z" />{" "}
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<g>
|
<g>
|
||||||
<g>
|
<g>
|
||||||
<g>
|
<path d="M507.804,200.28L262.471,12.866c-3.84-2.923-9.131-2.923-12.949,0L4.188,200.28c-3.605,2.773-5.077,7.531-3.648,11.84 l93.717,281.92c1.451,4.373,5.525,7.296,10.133,7.296h303.253c4.587,0,8.683-2.944,10.133-7.296l93.717-281.92 C512.882,207.789,511.41,203.053,507.804,200.28z" />{" "}
|
||||||
<path d="M507.804,200.28L262.471,12.866c-3.84-2.923-9.131-2.923-12.949,0L4.188,200.28c-3.605,2.773-5.077,7.531-3.648,11.84 l93.717,281.92c1.451,4.373,5.525,7.296,10.133,7.296h303.253c4.587,0,8.683-2.944,10.133-7.296l93.717-281.92 C512.882,207.789,511.41,203.053,507.804,200.28z" />{" "}
|
|
||||||
</g>
|
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</g>
|
||||||
)
|
|
||||||
}
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M507.804,200.28L262.471,12.866c-3.84-2.923-9.131-2.923-12.949,0L4.188,200.28c-3.605,2.773-5.077,7.531-3.648,11.84 l93.717,281.92c1.451,4.373,5.525,7.296,10.133,7.296h303.253c4.587,0,8.683-2.944,10.133-7.296l93.717-281.92 C512.882,207.789,511.41,203.053,507.804,200.28z" />{" "}
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Pentagon
|
||||||
|
|||||||
@@ -3,22 +3,22 @@ type Props = {
|
|||||||
fill?: string
|
fill?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Rhombus({ className, fill = "#FFF" }: Props) {
|
const Rhombus = ({ className, fill = "#FFF" }: Props) => (
|
||||||
return (
|
<svg
|
||||||
<svg
|
className={className}
|
||||||
className={className}
|
fill={fill}
|
||||||
fill={fill}
|
viewBox="-56.32 -56.32 624.64 624.64"
|
||||||
viewBox="-56.32 -56.32 624.64 624.64"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
transform="rotate(45)"
|
||||||
transform="rotate(45)"
|
>
|
||||||
>
|
<g strokeWidth="0" />
|
||||||
<g strokeWidth="0" />
|
|
||||||
|
|
||||||
<g strokeLinecap="round" strokeLinejoin="round" />
|
<g strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
|
||||||
<g>
|
<g>
|
||||||
<rect x="48" y="48" width="416" height="416" />
|
<rect x="48" y="48" width="416" height="416" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
export default Rhombus
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ type Props = {
|
|||||||
fill?: string
|
fill?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Square({ className, fill = "#FFF" }: Props) {
|
const Square = ({ className, fill = "#FFF" }: Props) => (
|
||||||
return (
|
<svg
|
||||||
<svg
|
className={className}
|
||||||
className={className}
|
fill={fill}
|
||||||
fill={fill}
|
viewBox="0 0 512 512"
|
||||||
viewBox="0 0 512 512"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
>
|
||||||
>
|
<rect x="48" y="48" width="416" height="416" />
|
||||||
<rect x="48" y="48" width="416" height="416" />
|
</svg>
|
||||||
</svg>
|
)
|
||||||
)
|
|
||||||
}
|
export default Square
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ type Props = {
|
|||||||
fill?: string
|
fill?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Triangle({ className, fill = "#FFF" }: Props) {
|
const Triangle = ({ className, fill = "#FFF" }: Props) => (
|
||||||
return (
|
<svg
|
||||||
<svg
|
className={className}
|
||||||
className={className}
|
fill={fill}
|
||||||
fill={fill}
|
viewBox="0 0 512 512"
|
||||||
viewBox="0 0 512 512"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
>
|
||||||
>
|
<polygon points="256 32 20 464 492 464 256 32" />
|
||||||
<polygon points="256 32 20 464 492 464 256 32" />
|
</svg>
|
||||||
</svg>
|
)
|
||||||
)
|
|
||||||
}
|
export default Triangle
|
||||||
|
|||||||
23
packages/web/src/utils/score.ts
Normal file
23
packages/web/src/utils/score.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
export const calculatePercentages = (
|
||||||
|
objectResponses: Record<string, number>,
|
||||||
|
): Record<string, string> => {
|
||||||
|
const keys = Object.keys(objectResponses)
|
||||||
|
const values = Object.values(objectResponses)
|
||||||
|
|
||||||
|
if (!values.length) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalSum = values.reduce(
|
||||||
|
(accumulator, currentValue) => accumulator + currentValue,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
|
const result: Record<string, string> = {}
|
||||||
|
|
||||||
|
keys.forEach((key) => {
|
||||||
|
result[key] = `${((objectResponses[key] / totalSum) * 100).toFixed()}%`
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user