refactor(components): use arrow function syntax and improve consistency

This commit is contained in:
Ralex
2025-10-25 15:04:03 +02:00
parent ac486b3d7d
commit dbefaa0557
32 changed files with 351 additions and 337 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -15,8 +15,7 @@ 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>
@@ -26,4 +25,5 @@ export default function RootLayout({ children }: PropsWithChildren) {
</body> </body>
</html> </html>
) )
}
export default RootLayout

View File

@@ -6,13 +6,12 @@ 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",
@@ -24,4 +23,5 @@ export default function AnswerButton({
<span className="drop-shadow-md">{children}</span> <span className="drop-shadow-md">{children}</span>
</button> </button>
) )
}
export default AnswerButton

View File

@@ -2,8 +2,8 @@ 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",
@@ -14,4 +14,5 @@ export default function Button({ children, className, ...otherProps }: Props) {
<span>{children}</span> <span>{children}</span>
</button> </button>
) )
}
export default Button

View File

@@ -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

View File

@@ -3,12 +3,7 @@ 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,
type = "text",
...otherProps
}: Props) {
return (
<input <input
type={type} type={type}
className={clsx( className={clsx(
@@ -18,4 +13,5 @@ export default function Input({
{...otherProps} {...otherProps}
/> />
) )
}
export default Input

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -4,8 +4,7 @@ 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
@@ -23,4 +22,5 @@ export default function Leaderboard({ data: { leaderboard } }: Props) {
</div> </div>
</section> </section>
) )
}
export default Leaderboard

View File

@@ -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

View File

@@ -7,10 +7,7 @@ type Props = {
data: CommonStatusDataMap["SHOW_PREPARED"] data: CommonStatusDataMap["SHOW_PREPARED"]
} }
export default function Prepared({ const Prepared = ({ data: { totalAnswers, questionNumber } }: Props) => (
data: { totalAnswers, questionNumber },
}: Props) {
return (
<section className="anim-show relative mx-auto flex w-full max-w-7xl flex-1 flex-col items-center justify-center"> <section className="anim-show relative mx-auto flex w-full max-w-7xl flex-1 flex-col items-center justify-center">
<h2 className="anim-show mb-20 text-center text-3xl font-bold text-white drop-shadow-lg md:text-4xl lg:text-5xl"> <h2 className="anim-show mb-20 text-center text-3xl font-bold text-white drop-shadow-lg md:text-4xl lg:text-5xl">
Question #{questionNumber} Question #{questionNumber}
@@ -30,4 +27,5 @@ export default function Prepared({
</div> </div>
</section> </section>
) )
}
export default Prepared

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -5,8 +5,7 @@ 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">
@@ -14,4 +13,5 @@ export default function Wait({ data: { text } }: Props) {
</h2> </h2>
</section> </section>
) )
}
export default Wait

View File

@@ -3,21 +3,14 @@ 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 <g id="Page-1" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
id="Page-1"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<g id="icon" fill={fill} transform="translate(42.666667, 42.666667)"> <g id="icon" fill={fill} transform="translate(42.666667, 42.666667)">
<path <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" 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"
@@ -27,4 +20,5 @@ export default function Circle({ className, fill = "#FFF" }: Props) {
</g> </g>
</svg> </svg>
) )
}
export default Circle

View File

@@ -2,8 +2,7 @@ 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"
@@ -38,4 +37,5 @@ export default function CricleCheck({ className }: Props) {
</g> </g>
</svg> </svg>
) )
}
export default CricleCheck

View File

@@ -2,8 +2,7 @@ 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"
@@ -32,4 +31,5 @@ export default function CricleXmark({ className }: Props) {
</g> </g>
</svg> </svg>
) )
}
export default CricleXmark

View File

@@ -4,8 +4,7 @@ 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}
@@ -43,4 +42,5 @@ export default function Pentagon({ className, fill, stroke }: Props) {
</g> </g>
</svg> </svg>
) )
}
export default Pentagon

View File

@@ -3,8 +3,7 @@ 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}
@@ -21,4 +20,5 @@ export default function Rhombus({ className, fill = "#FFF" }: Props) {
</g> </g>
</svg> </svg>
) )
}
export default Rhombus

View File

@@ -3,8 +3,7 @@ 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}
@@ -14,4 +13,5 @@ export default function Square({ className, fill = "#FFF" }: Props) {
<rect x="48" y="48" width="416" height="416" /> <rect x="48" y="48" width="416" height="416" />
</svg> </svg>
) )
}
export default Square

View File

@@ -3,8 +3,7 @@ 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}
@@ -14,4 +13,5 @@ export default function Triangle({ className, fill = "#FFF" }: Props) {
<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

View 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
}