Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/app/rank/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@

import MainNavbar, { NavLink } from "@/components/shared/main-navbar";
import Footer from "@/components/shared/footer";
import { Ranking } from "@/components/league/sections/ranking";

const navLinks: NavLink[] = [];

export default function RankPage() {
{/* El contenido interno debe ocupar como mínimo el alto de la pantalla para que el footer se vea bien */ }
return (
<>
<div className="min-h-[100dvh] flex flex-col justify-between">
<MainNavbar navLinks={navLinks} />
{/* El contenido interno debe ocupar como mínimo el alto de la pantalla para que el footer se vea bien */}
<div className="mt-[10rem] w-full max-w-[90rem] mx-auto p-8">
<Ranking />
</div>
<Footer />
</>
</div>
);
}
15 changes: 15 additions & 0 deletions src/components/league/sections/ranking.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import RankingComponent from "../ui/ranking-component"

export const Ranking = () => {

return <div>

<RankingComponent.RankingContainer>
<RankingComponent.Padding className="max-w-[65rem] mx-auto">
<p className="text-lg font-semibold text-center">Ranking</p>
<RankingComponent.RankingList student_number={20} />
</RankingComponent.Padding>
</RankingComponent.RankingContainer>

</div>
}
2 changes: 1 addition & 1 deletion src/components/league/ui/podium/podium-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const Step = (props: {
showAvatar &&
<div className="absolute -top-[2rem] lg:-top-[3.5rem] left-1/2 transform -translate-x-1/2 mx-auto rounded-full border-2 border-[--azul-niebla] bg-[--azul-niebla] h-[4rem] lg:h-[7rem] aspect-square overflow-hidden">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={student.student.avatar.length == 0 ? null : student.student.avatar} alt={`Avatar de ${student.student.name}`} className="w-full h-full object-cover" />
<img src={student.student.avatar?.length == 0 ? null : student.student.avatar} alt={`Avatar de ${student.student.name}`} className="w-full h-full object-cover" />
</div>
}

Expand Down
119 changes: 119 additions & 0 deletions src/components/league/ui/ranking-component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { getRankingStudents } from "@/controllers/student.controller"
import { LevelEnum } from "@/models/level.enum"
import { Student } from "@/models/student.model"
import { ReactNode, useEffect, useState } from "react"

const RankingContainer = ({
className = "",
children
}: {
className?: string,
children: ReactNode
}) => {

return <div className={`p-2 rounded-md bg-[#fff] shadow-md ${className}`}>
{children}
</div>
}

const Padding = ({
className = "",
children
}: {
className?: string,
children: ReactNode
}) => {

return <div className={`p-2 ${className}`}>
{children}
</div>

}

const StudentComponent = ({ student, pos, skeleton = false }: {
student: Student,
pos: number,
skeleton?: boolean
}) => {
return <div className="flex gap-2 p-2 px-4 rounded-md bg-[#fff] shadow-md lg:px-6 text-xs lg:text-base hover:scale-[1.01] transition hover:shadow-lg">
{skeleton ?
<>
<div className="w-12 h-4 bg-neutral-200 rounded-sm"></div>
<div className="w-1/2 h-4 bg-neutral-200 rounded-sm"></div>
</>
:
<>
<p className={`w-10 m-0 ${pos == 0 ? "text-yellow-500" : pos == 1 ? "text-neutral-500" : pos == 2 ? "text-orange-500" : "text-[--azul-electrico]"} font-semibold`}>
{pos + 1}.
</p>
<div className="flex justify-between w-full">
<p className="flex gap-1 m-0 w-[90%] truncate text-ellipsis">
{student.name}
<span className="md:flex hidden">
{student.surname}
</span>
</p>
<p className="m-0">
<b className="text-base">{student.victory_count}</b>
/{student.matches_count}
</p>
</div>
</>
}
</div>
}

const RankingList = ({
className = "",
student_number = 20
}: {
className?: string,
student_number?: number
}) => {

const SKELETON_RANKING_USERS_COUNT = 5;

const [loading, setLoading] = useState<boolean>(true);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [students, setStudents] = useState<Student[]>(Array.from({ length: SKELETON_RANKING_USERS_COUNT }).map((_) => ({
_id: "",
avatar: "",
level: LevelEnum.Initial,
matches_count: 0,
victory_count: 0,
name: "",
supabase_user_id: "",
surname: ""
})));

const handlerGetRankingStudents = async () => {

try {
const response = await getRankingStudents({ student_number });

setStudents(response);
} catch {
return;
}

setLoading(false)
}

useEffect(() => {
handlerGetRankingStudents()
}, [])

return <div className={`flex flex-col gap-2 ${className}`}>
{students.map((s, i) => {

return <StudentComponent skeleton={loading} student={s} key={i} pos={i} />
})}
</div>
}

export default {
RankingContainer,
Padding,
RankingList
}
18 changes: 17 additions & 1 deletion src/controllers/student.controller.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Student } from "@/models/student.model";

export async function getStudents() {
const res = await fetch(new URL(`/students`, process.env.NEXT_PUBLIC_BACKEND_URL));

Expand All @@ -9,7 +11,7 @@ export async function getStudents() {
return json.data;
}

export async function getPodiumStudents() {
export async function getPodiumStudents(): Promise<Student[]>{
const res = await fetch(new URL(`/students?limit=3&ordercol=victory_count&subordercol=matches_count&subasc=1`, process.env.NEXT_PUBLIC_BACKEND_URL));

if (!res.ok) {
Expand All @@ -19,3 +21,17 @@ export async function getPodiumStudents() {
const json = await res.json();
return json.data;
}


export async function getRankingStudents({
student_number
}: { student_number: number }): Promise<Student[]> {
const res = await fetch(new URL(`/students?limit=${student_number}&ordercol=victory_count&subordercol=matches_count&subasc=1`, process.env.NEXT_PUBLIC_BACKEND_URL));

if (!res.ok) {
throw new Error("Error al obtener los estudiantes del ranking");
}

const json = await res.json();
return json.data;
}