diff --git a/components/stats/Picklist.tsx b/components/stats/Picklist.tsx index 6d50ccb6..ac947e91 100644 --- a/components/stats/Picklist.tsx +++ b/components/stats/Picklist.tsx @@ -1,13 +1,14 @@ -import { Report } from "@/lib/Types"; +import { DbPicklist, Report } from "@/lib/Types"; import { useDrag, useDrop } from "react-dnd"; import { ChangeEvent, useEffect, useState } from "react"; import { FaArrowDown, FaArrowUp, FaPlus } from "react-icons/fa"; +import { getServerSideProps } from '../../pages/[teamSlug]/[seasonSlug]/[competitonSlug]/stats'; +import ClientAPI from "@/lib/client/ClientAPI"; type CardData = { number: number; - id: number; - picklist?: number; + picklistIndex?: number; }; type Picklist = { @@ -19,8 +20,8 @@ type Picklist = { const Includes = (bucket: any[], item: CardData) => { let result = false; - bucket.forEach((i: { id: number }) => { - if (i.id === item.id) { + bucket.forEach((i: { number: number }) => { + if (i.number === item.number) { result = true; } }); @@ -29,17 +30,17 @@ const Includes = (bucket: any[], item: CardData) => { }; function removeTeamFromPicklist(team: CardData, picklists: Picklist[]) { - if (team.picklist === undefined) return; + if (team.picklistIndex === undefined) return; - const picklist = picklists[team.picklist]; + const picklist = picklists[team.picklistIndex]; if (!picklist) return; - picklist.teams = picklist.teams.filter((team) => team.id !== team.id); + picklist.teams = picklist.teams.filter((t) => t.number !== team.number); picklist.update(picklist); } function TeamCard(props: { cardData: CardData, draggable: boolean, picklist?: Picklist, rank?: number, lastRank?: number, width?: string, height?: string}) { - const { number: teamNumber, id, picklist } = props.cardData; + const { number: teamNumber, picklistIndex: picklist } = props.cardData; const [{ isDragging }, dragRef] = useDrag({ type: "team", @@ -89,12 +90,12 @@ function PicklistCard(props: { picklist: Picklist, picklists: Picklist[] }) { const [{ isOver }, dropRef] = useDrop({ accept: "team", drop: (item: CardData) => { - if (item.picklist === picklist.index) return; + if (item.picklistIndex === picklist.index) return; removeTeamFromPicklist(item, props.picklists); if (!Includes(picklist.teams, item)) { - item.picklist = picklist.index; + item.picklistIndex = picklist.index; picklist.teams.push(item); picklist.update(picklist); } @@ -119,7 +120,7 @@ function PicklistCard(props: { picklist: Picklist, picklists: Picklist[] }) { { @@ -145,70 +146,126 @@ export function TeamList(props: { teams: CardData[], picklists: Picklist[] }) { return (
- {props.teams.length > 0 ? props.teams.map((team) => ( - - )) : - } + { + props.teams.map((team) => ( + + )) + } + { props.teams.length !== props.expectedTeamCount && +
+ }
); } -export default function PicklistScreen(props: { teams: number[], reports: Report[] }) { +const api = new ClientAPI("gearboxiscool"); + +export default function PicklistScreen(props: { teams: number[], reports: Report[], expectedTeamCount: number, picklistId: string }) { const [picklists, setPicklists] = useState([]); + const [loadingPicklists, setLoadingPicklists] = useState(false); - const teams = props.teams.map((team) => ({ number: team, id: team })); + const teams = props.teams.map((team) => ({ number: team })); + + function savePicklists(picklists: Picklist[]) { + const picklistDict = picklists.reduce((acc, picklist) => { + acc.picklists[picklist.name] = picklist.teams.map((team) => team.number); + return acc; + }, { + _id: props.picklistId, + picklists: {} + }); + + api.updatePicklist(picklistDict); + } + + function updatePicklist(picklist: Picklist) { + setPicklists((old) => { + const newPicklists = old.map((p) => { + if (p.index === picklist.index) { + return picklist; + } else { + return p; + } + }); + + savePicklists(newPicklists); + return newPicklists; + }); + } + + useEffect(() => { + if (picklists.length > 0 || loadingPicklists) return; + + setLoadingPicklists(true); + api.getPicklist(props.picklistId).then((picklistDict) => { + setPicklists(Object.entries(picklistDict.picklists).map((picklist, index) => { + const newPicklist: Picklist = { + index, + name: picklist[0], + teams: picklist[1].map((team: number) => ({ number: team })), + update: updatePicklist + }; + + for (const team of newPicklist.teams) { + team.picklistIndex = newPicklist.index; + } + + return newPicklist; + })); + + setLoadingPicklists(false); + }); + }); const addPicklist = () => { const newPicklist: Picklist = { index: picklists.length, name: `Picklist ${picklists.length + 1}`, teams: [], - update: (picklist: Picklist) => { - setPicklists((old) => { - const newPicklists = old.map((p) => { - if (p.index === picklist.index) { - return picklist; - } else { - return p; - } - }); - - return newPicklists; - }); - }, + update: updatePicklist }; - setPicklists([...picklists, newPicklist]); + const newPicklists = [...picklists, newPicklist]; + savePicklists(newPicklists); + setPicklists(newPicklists); }; return (
- +
- {picklists.length === 0 - ? ( -
-

- Create A Picklist -

-
- ) - : picklists.map((picklist) => ( - + { + loadingPicklists + ?
+
+
+ : picklists.length === 0 + ? ( +
+

+ Create A Picklist +

+
+ ) + : picklists.map((picklist) => ( + + ) ) - )} + }
- + { !loadingPicklists && + + }
); -} +} \ No newline at end of file diff --git a/lib/API.ts b/lib/API.ts index 995224f5..c7bfa09c 100644 --- a/lib/API.ts +++ b/lib/API.ts @@ -10,6 +10,7 @@ import { User, Report, Pitreport, + DbPicklist, } from "./Types"; import { GenerateSlug, removeDuplicates } from "./Utils"; import { ObjectId } from "mongodb"; @@ -429,6 +430,11 @@ export namespace API { const pitReports = await generatePitReports(tba, db, data.tbaId); + const picklist = await db.addObject(Collections.Picklists, { + _id: new ObjectId(), + picklists: {}, + }); + var comp = await db.addObject( Collections.Competitions, new Competition( @@ -439,6 +445,7 @@ export namespace API { data.end, pitReports, matches.map((match) => String(match._id)), + picklist._id.toString() ) ); @@ -837,6 +844,17 @@ export namespace API { await Promise.all(promises); return res.status(200).send({ scouters, matches, reports }); + }, + + getPicklist: async (req, res, { db, data }) => { + const picklist = await db.findObjectById(Collections.Picklists, new ObjectId(data.id)); + return res.status(200).send(picklist); + }, + + updatePicklist: async (req, res, { db, data }) => { + const { _id, ...picklist } = data.picklist; + await db.updateObjectById(Collections.Picklists, new ObjectId(data.picklist._id), picklist); + return res.status(200).send({ result: "success" }); } }; } diff --git a/lib/MongoDB.ts b/lib/MongoDB.ts index 0a1e2bc0..b787ba51 100644 --- a/lib/MongoDB.ts +++ b/lib/MongoDB.ts @@ -35,6 +35,7 @@ export enum Collections { Sessions = "sessions", Forms = "Forms", Pitreports = "Pitreports", + Picklists = "Picklists", } export async function GetDatabase(): Promise { diff --git a/lib/Types.ts b/lib/Types.ts index 0e4f0228..121a8e0f 100644 --- a/lib/Types.ts +++ b/lib/Types.ts @@ -235,6 +235,8 @@ export class Competition { pitReports: string[]; matches: string[]; + picklist: string; + constructor( name: string, slug: string | undefined, @@ -242,7 +244,8 @@ export class Competition { start: number, end: number, pitReports: string[] = [], - matches: string[] = [] + matches: string[] = [], + picklist: string = "" ) { this.name = name; this.slug = slug; @@ -251,6 +254,7 @@ export class Competition { this.end = end; this.pitReports = pitReports; this.matches = matches; + this.picklist = picklist; } } @@ -349,3 +353,10 @@ export interface EventData { firstRanking: TheBlueAlliance.SimpleRank[]; oprRanking: TheBlueAlliance.OprRanking; } + +export type DbPicklist = { + _id: string; + picklists: { + [name: string]: number[]; + }; +} \ No newline at end of file diff --git a/lib/client/ClientAPI.ts b/lib/client/ClientAPI.ts index 63559048..3324641f 100644 --- a/lib/client/ClientAPI.ts +++ b/lib/client/ClientAPI.ts @@ -13,6 +13,7 @@ import { FormData, EventData, Pitreport, + DbPicklist, } from "../Types"; export enum ClientRequestMethod { @@ -392,4 +393,12 @@ export default class ClientAPI { return await this.request("/findScouterManagementData", { compId, scouterIds }); } + async getPicklist(id: string): Promise { + return await this.request("/getPicklist", { id }); + } + + async updatePicklist(picklist: DbPicklist) { + return await this.request("/updatePicklist", { picklist }); + } + } diff --git a/pages/[teamSlug]/[seasonSlug]/[competitonSlug]/stats.tsx b/pages/[teamSlug]/[seasonSlug]/[competitonSlug]/stats.tsx index cddf34fe..5cce2dbd 100644 --- a/pages/[teamSlug]/[seasonSlug]/[competitonSlug]/stats.tsx +++ b/pages/[teamSlug]/[seasonSlug]/[competitonSlug]/stats.tsx @@ -113,7 +113,8 @@ export default function Stats(props: StatsPageProps) { ) : ( <> )} - {page === 1 ? : <>} + {page === 1 ? : <>} ); }