Skip to content

Commit

Permalink
feat: add page to show only group at a time
Browse files Browse the repository at this point in the history
  • Loading branch information
fdaciuk committed Jul 28, 2023
1 parent 760ee44 commit 550b327
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 21 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

> Backoffice application for Code in the Dark ⚡
**IMPORTANT: Node.js v20 is required to run this project.**

## Setup ⚙️

1. Install the deps:
Expand All @@ -19,7 +21,7 @@ cp .env.example .env
3. Run migrations to create the database:

```sh
yarn prisma migrate dev
yarn migrate
```

4. Run seed to fill up the database:
Expand Down
3 changes: 2 additions & 1 deletion prisma/seed/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ async function main() {
const promiseParticipants = participants.map((data) => {
const rand = getRandomInteger(1)

const event = events[rand]
// const event = events[rand]
const event = events[1]
return prisma.user.create({
data: {
...data,
Expand Down
169 changes: 169 additions & 0 deletions src/app/events/[event]/participants/[groupId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
"use client"

import {
FinalRound,
ParticipantImage,
ParticipantItem,
ParticipantName,
ParticipantsList,
RoundTitle,
} from "@/components"
import { Round } from "@/shared/types"
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import { RefreshCcw, ThumbsUp } from "lucide-react"

import {
getSelectedParticipants,
selectNewRandomPlayer,
setWinner,
} from "@/app/events/[event]/participants/data-participants"
import Link from "next/link"

type ParticipantsInGroupProps = {
params: {
event: string
groupId: string
}
}

export default function ParticipantsInGroup({
params,
}: ParticipantsInGroupProps) {
const { event } = params
const queryClient = useQueryClient()

const query = useQuery({
queryKey: ["selected-participants", { event }],
queryFn: () => getSelectedParticipants(event),
})

const winnerMutation = useMutation({
mutationFn: setWinner,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["selected-participants", { event }],
})
},
})

const selectNewRandomPlayerMutation = useMutation({
mutationFn: selectNewRandomPlayer,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["participants", { event }],
})
queryClient.invalidateQueries({
queryKey: ["selected-participants", { event }],
})
},
})

const selectedParticipants = query.data ?? []

const rounds = selectedParticipants.reduce<Round[]>((acc, participant) => {
const groupId = participant.groupId

acc[groupId - 1] = acc[groupId - 1] ?? {}
acc[groupId - 1].participants = acc[groupId - 1].participants ?? []
acc[groupId - 1].participants.push(participant)
return acc
}, [])

const finalRound = rounds.reduce(
(acc, round) => {
const winner = round.participants.find(
(participant) => participant.winner === true,
)
if (winner) {
acc.participants.push(winner)
}
return acc
},
{ participants: [] },
)

const round =
params.groupId === "final" ? finalRound : rounds[+params.groupId - 1]

console.log({ round })

type HandleSetWinnerInput = {
userId: string
event: string
groupId: number
}

const handleSetWinner =
({ userId, event, groupId }: HandleSetWinnerInput) =>
() => {
winnerMutation.mutate({ userId, event, groupId })
}

type HandleSelectNewRandomPlayerInput = {
userId: string
event: string
groupId: number
}
const handleSelectNewRandomPlayer =
({ userId, event, groupId }: HandleSelectNewRandomPlayerInput) =>
() => {
selectNewRandomPlayerMutation.mutate({ userId, event, groupId })
}

return (
<section className="font-sans">
<p className="text-body-xs leading-normal text-neutral-500 underline">
<Link href={`/events/${event}/participants`}>
Code in The Dark {params.event}
</Link>
</p>
<h2 className="mb-16 mt-1 text-title-sm font-bold leading-normal text-neutral-900">
Grupo {params.groupId}
</h2>

<FinalRound size="big">
<ParticipantsList>
{round?.participants.map((participant, index) => (
<ParticipantItem key={participant.id}>
<div className="group relative h-[69px] w-[69px] cursor-pointer">
<ParticipantImage
src={`https://github.com/${participant.github}.png`}
alt={`${participant.name} photo`}
lined={index !== round.participants.length - 1}
/>

{params.groupId !== "final" && (
<>
<button
className="absolute -top-1 right-0 z-aboveAll hidden h-[28px] w-[28px] items-center justify-center rounded-full bg-primary-100 group-hover:flex"
onClick={handleSelectNewRandomPlayer({
userId: participant.id,
event,
groupId: participant.groupId,
})}
>
<RefreshCcw size={18} />
</button>

<button
className="absolute -bottom-1 left-0 hidden h-[28px] w-[28px] items-center justify-center rounded-full bg-primary-100 transition-all group-hover:flex"
onClick={handleSetWinner({
userId: participant.id,
event,
groupId: participant.groupId,
})}
>
<ThumbsUp size={18} />
</button>
</>
)}
</div>

<ParticipantName>{participant.name}</ParticipantName>
</ParticipantItem>
))}
</ParticipantsList>
</FinalRound>
</section>
)
}
39 changes: 23 additions & 16 deletions src/app/events/[event]/participants/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
selectNewRandomPlayer,
setWinner,
} from "./data-participants"
import Link from "next/link"

export default function Participants({ params }: EventProps) {
const { event } = params
Expand Down Expand Up @@ -108,7 +109,9 @@ export default function Participants({ params }: EventProps) {
<RoundsList>
{rounds.map((round, index) => (
<RoundItem key={index}>
<RoundTitle>{index + 1}º Round</RoundTitle>
<Link href={`/events/${event}/participants/${index + 1}`}>
<RoundTitle>{index + 1}º Round</RoundTitle>
</Link>
<ParticipantsList>
{round.participants.map((participant, index) => (
<ParticipantItem key={participant.id}>
Expand Down Expand Up @@ -149,21 +152,25 @@ export default function Participants({ params }: EventProps) {
))}
</RoundsList>

<FinalRound>
<RoundTitle>Final</RoundTitle>
<ParticipantsList>
{finalRound.participants.map((participant, index) => (
<ParticipantItem key={participant.id}>
<ParticipantImage
src={`https://github.com/${participant.github}.png`}
alt={`${participant.name} photo`}
lined={index !== finalRound.participants.length - 1}
/>
<ParticipantName>{participant.name}</ParticipantName>
</ParticipantItem>
))}
</ParticipantsList>
</FinalRound>
{finalRound.participants.length > 0 && (
<FinalRound>
<Link href={`/events/${event}/participants/final`}>
<RoundTitle>Final</RoundTitle>
</Link>
<ParticipantsList>
{finalRound.participants.map((participant, index) => (
<ParticipantItem key={participant.id}>
<ParticipantImage
src={`https://github.com/${participant.github}.png`}
alt={`${participant.name} photo`}
lined={index !== finalRound.participants.length - 1}
/>
<ParticipantName>{participant.name}</ParticipantName>
</ParticipantItem>
))}
</ParticipantsList>
</FinalRound>
)}
</section>
)
}
9 changes: 7 additions & 2 deletions src/components/rounds-list/final-round.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { PropsWithChildren } from "react"

export function FinalRound({ children }: PropsWithChildren) {
type FinalRoundProps = PropsWithChildren & {
size?: "big"
}
export function FinalRound({ children, size }: FinalRoundProps) {
return (
<div className="flex justify-center">
<div className="w-[416px]">{children}</div>
<div className={`w-[416px] ${size === "big" ? "scale-150" : ""}`}>
{children}
</div>
</div>
)
}
1 change: 0 additions & 1 deletion src/components/rounds-list/participant-image.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Image from "next/image"
import { RefreshCcw, ThumbsUp } from "lucide-react"

type ParticipantImageProps = {
src: string
Expand Down

0 comments on commit 550b327

Please sign in to comment.