Skip to content

Commit

Permalink
Merge branch 'better-picklists' of github.com:Decatur-Robotics/Gearbo…
Browse files Browse the repository at this point in the history
…x into better-picklists
  • Loading branch information
renatodellosso committed Jan 6, 2025
2 parents 1b51912 + 2c0f4b7 commit 24580d7
Show file tree
Hide file tree
Showing 14 changed files with 270 additions and 1,165 deletions.
8 changes: 4 additions & 4 deletions components/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { useCurrentSession } from "@/lib/client/useCurrentSession";
import { User } from "@/lib/Types";
import { levelToClassName } from "@/lib/Xp";
import { BsGearFill } from "react-icons/bs";

export default function Avatar(props: {
user?: User | undefined;
scale?: string | undefined;
user?: { image: string | undefined; level: number; admin?: boolean };
scale?: string | undefined; // Use "scale-75" for 75% scale, etc.
imgHeightOverride?: string | undefined;
showLevel?: boolean | undefined;
borderThickness?: number | undefined;
onClick?: () => void | undefined;
className?: string | undefined;
online?: boolean;
gearSize?: number;
}) {
const { session, status } = useCurrentSession();
const user = props.user ?? session?.user;
Expand Down Expand Up @@ -39,7 +39,7 @@ export default function Avatar(props: {
</div>
{admin ? (
<div className="absolute z-10 -bottom-2 -left-2 text-slate-300 animate-spin-slow">
<BsGearFill size={36}></BsGearFill>
<BsGearFill size={props.gearSize ?? 36}></BsGearFill>
</div>
) : (
<></>
Expand Down
1 change: 1 addition & 0 deletions components/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ export default function Container(props: ContainerProps) {
imgHeightOverride="h-11"
showLevel={false}
borderThickness={2}
gearSize={24}
/>
</Link>
) : (
Expand Down
12 changes: 12 additions & 0 deletions components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import {
FaGithub,
FaInstagram,
FaList,
FaTrophy,
} from "react-icons/fa";
import { TbUfo } from "react-icons/tb";
import Link from "next/link";
import { MdAlternateEmail } from "react-icons/md";
import { HiStatusOnline } from "react-icons/hi";
import { useEffect, useState } from "react";
import Leaderboard from "../pages/leaderboard";

export default function Footer() {
const [swStatus, setSwStatus] = useState("Finding service worker...");
Expand Down Expand Up @@ -136,6 +138,16 @@ export default function Footer() {
/>
About Us
</Link>
<Link
className="link link-hover"
href="/leaderboard"
>
<FaTrophy
className="inline mr-1"
size={16}
/>
Leaderboard
</Link>
</nav>
<nav className="max-sm:pl-8">
<h6 className="footer-title">Debug</h6>
Expand Down
53 changes: 38 additions & 15 deletions components/XpProgressBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,44 @@ export default function XpProgressBar({
const [hovered, setHovered] = useState(false);

return (
<div
className={`radial-progress text-accent m-2 text-${hovered ? "xs" : "sm"}`}
style={
{
"--value": (user.xp / xpRequiredForNextLevel(user.level)) * 100,
"--size": size,
} as any
}
role="progressbar"
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
{hovered
? `${user.xp}/${xpRequiredForNextLevel(user.level)}`
: `Lvl ${user.level}`}
<div className="text-accent m-2">
{/* Desktop layout */}
<div
className={`max-sm:hidden radial-progress text-${hovered ? "xs" : "sm"}`}
style={
{
"--value":
((user.xp - xpRequiredForNextLevel(user.level - 1)) /
(xpRequiredForNextLevel(user.level) -
xpRequiredForNextLevel(user.level - 1))) *
100,
"--size": size,
} as any
}
role="progressbar"
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
{hovered
? `${user.xp}/${xpRequiredForNextLevel(user.level)}`
: `Lvl ${user.level}`}
</div>
{/* Desktop layout */}
<div className="sm:hidden">
<div className="divider" />
<div>
Level {user.level} - XP: {user.xp}/
{xpRequiredForNextLevel(user.level)}
</div>
<progress
className="progress progress-accent"
value={user.xp - xpRequiredForNextLevel(user.level - 1)}
max={
xpRequiredForNextLevel(user.level) -
xpRequiredForNextLevel(user.level - 1)
}
/>
</div>
</div>
);
}
1 change: 1 addition & 0 deletions components/competition/MatchScheduleCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ export default function MatchScheduleCard(props: {
showLevel={false}
borderThickness={2}
onClick={() => remindUserOnSlack(user._id!)}
gearSize={25}
/>
) : (
<div className="w-12 h-12"></div>
Expand Down
54 changes: 0 additions & 54 deletions lib/Socket.ts

This file was deleted.

17 changes: 17 additions & 0 deletions lib/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,3 +579,20 @@ export class WebhookHolder {
this.url = url;
}
}

export type LeaderboardUser = {
_id: string;
name: string;
image: string;
xp: number;
level: number;
teams: string[];
};

export type LeaderboardTeam = {
_id: string;
name: string;
number: number;
league: League;
xp: number;
};
2 changes: 1 addition & 1 deletion lib/Xp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function levelToXp(level: number) {
}

export function xpRequiredForNextLevel(level: number) {
return levelToXp(level + 1);
return Math.max(levelToXp(level + 1), 0);
}

export function levelToClassName(level: number | undefined) {
Expand Down
76 changes: 76 additions & 0 deletions lib/api/ClientApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
User,
Report,
WebhookHolder,
LeaderboardUser,
LeaderboardTeam,
} from "@/lib/Types";
import { NotLinkedToTba, removeDuplicates } from "../client/ClientUtils";
import {
Expand Down Expand Up @@ -2110,4 +2112,78 @@ export default class ClientApi extends NextApiTemplate<ApiDependencies> {
responseTime: Date.now() - times.responseTimestamp,
})),
);

getLeaderboard = createNextRoute<
[],
{ users: LeaderboardUser[]; teams: LeaderboardTeam[] },
ApiDependencies,
void
>({
isAuthorized: AccessLevels.AlwaysAuthorized,
handler: async (req, res, { db: dbPromise }, authData, args) => {
const db = await dbPromise;

const users = await db.findObjects<User>(CollectionId.Users, {
xp: { $gt: 0 },
email: { $ne: "[email protected]" },
});

console.log(
"ID Query:",
users.map((user) => user.teams.map((id) => new ObjectId(id))).flat(),
);

const teams = await db.findObjects<Team>(CollectionId.Teams, {
_id: {
$in: users
.map((user) => user.teams.map((id) => new ObjectId(id)))
.flat(),
},
});

console.log("Found", users, teams);

const leaderboardTeams = teams.reduce(
(acc, team) => {
acc[team._id!.toString()] = {
_id: team._id!.toString(),
name: team.name,
number: team.number,
league: team.league ?? League.FRC,
xp: 0,
};

return acc;
},
{} as { [_id: string]: LeaderboardTeam },
);

const leaderboardUsers = users
.map((user) => ({
_id: user._id!.toString(),
name: user.name?.split(" ")[0] ?? "Unknown",
image: user.image,
xp: user.xp,
level: user.level,
teams: user.teams
.map((id) => leaderboardTeams[id])
.map((team) => `${team.league ?? League.FRC} ${team.number}`),
}))
.sort((a, b) => b.xp - a.xp);

users.forEach((user) => {
user.teams.forEach((teamId) => {
leaderboardTeams[teamId].xp += user.xp;
});
});

const leaderboardTeamsArray = Object.values(leaderboardTeams).sort(
(a, b) => b.xp - a.xp,
);

return res
.status(200)
.send({ users: leaderboardUsers, teams: leaderboardTeamsArray });
},
});
}
8 changes: 0 additions & 8 deletions lib/client/ClientSocket.ts

This file was deleted.

Loading

0 comments on commit 24580d7

Please sign in to comment.