Skip to content

Commit

Permalink
Merge pull request #171 from Decatur-Robotics/picklist-improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
renatodellosso authored May 13, 2024
2 parents 1e5616d + 49c4f87 commit 00c62bb
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 58 deletions.
169 changes: 113 additions & 56 deletions components/stats/Picklist.tsx
Original file line number Diff line number Diff line change
@@ -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 = {
Expand All @@ -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;
}
});
Expand All @@ -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",
Expand Down Expand Up @@ -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);
}
Expand All @@ -119,7 +120,7 @@ function PicklistCard(props: { picklist: Picklist, picklists: Picklist[] }) {
<TeamCard
cardData={team}
draggable={false}
key={team.id}
key={team.number}
picklist={picklist}
rank={index}
lastRank={picklist.teams.length - 1}
Expand All @@ -132,7 +133,7 @@ function PicklistCard(props: { picklist: Picklist, picklists: Picklist[] }) {
);
}

export function TeamList(props: { teams: CardData[], picklists: Picklist[] }) {
export function TeamList(props: { teams: CardData[], picklists: Picklist[], expectedTeamCount: number }) {
const [{ isOver}, dropRef] = useDrop({
accept: "team",
drop: (item: CardData) => {
Expand All @@ -145,70 +146,126 @@ export function TeamList(props: { teams: CardData[], picklists: Picklist[] }) {

return (
<div ref={dropRef} className="w-full h-fit flex flex-row bg-base-300 space-x-2 p-2 overflow-x-scroll">
{props.teams.length > 0 ? props.teams.map((team) => (
<TeamCard
draggable={true}
cardData={team}
key={team.id}
></TeamCard>
)) :
<progress className="progress w-full"></progress>}
{
props.teams.map((team) => (
<TeamCard
draggable={true}
cardData={team}
key={team.number}
></TeamCard>
))
}
{ props.teams.length !== props.expectedTeamCount &&
<div className="loading loading-spinner" />
}
</div>);
}

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<Picklist[]>([]);
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<DbPicklist>((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 (
<div className="w-full h-fit flex flex-col space-y-2">
<TeamList teams={teams} picklists={picklists}></TeamList>
<TeamList teams={teams} picklists={picklists} expectedTeamCount={props.expectedTeamCount}></TeamList>

<div className="w-full h-[30rem] px-4 py-2 flex flex-row space-x-3">
{picklists.length === 0
? (
<div className="w-full h-full flex items-center justify-center">
<h1 className="text-3xl text-accent animate-bounce font-semibold">
Create A Picklist
</h1>
</div>
)
: picklists.map((picklist) => (
<PicklistCard key={picklist.index} picklist={picklist} picklists={picklists}></PicklistCard>
{
loadingPicklists
? <div className="w-full h-full flex items-center justify-center">
<div className="loading loading-spinner" />
</div>
: picklists.length === 0
? (
<div className="w-full h-full flex items-center justify-center">
<h1 className="text-3xl text-accent animate-bounce font-semibold">
Create A Picklist
</h1>
</div>
)
: picklists.map((picklist) => (
<PicklistCard key={picklist.index} picklist={picklist} picklists={picklists}></PicklistCard>
)
)
)}
}
</div>

<button
className="btn btn-circle btn-lg btn-primary absolute right-10 bottom-[21rem] animate-pulse font-bold "
onClick={addPicklist}
>
<FaPlus></FaPlus>
</button>
{ !loadingPicklists &&
<button
className="btn btn-circle btn-lg btn-primary absolute right-10 bottom-[21rem] animate-pulse font-bold "
onClick={addPicklist}
>
<FaPlus></FaPlus>
</button>
}
</div>
);
}
}
18 changes: 18 additions & 0 deletions lib/API.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
User,
Report,
Pitreport,
DbPicklist,
} from "./Types";
import { GenerateSlug, removeDuplicates } from "./Utils";
import { ObjectId } from "mongodb";
Expand Down Expand Up @@ -429,6 +430,11 @@ export namespace API {

const pitReports = await generatePitReports(tba, db, data.tbaId);

const picklist = await db.addObject<DbPicklist>(Collections.Picklists, {
_id: new ObjectId(),
picklists: {},
});

var comp = await db.addObject<Competition>(
Collections.Competitions,
new Competition(
Expand All @@ -439,6 +445,7 @@ export namespace API {
data.end,
pitReports,
matches.map((match) => String(match._id)),
picklist._id.toString()
)
);

Expand Down Expand Up @@ -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<DbPicklist>(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<DbPicklist>(Collections.Picklists, new ObjectId(data.picklist._id), picklist);
return res.status(200).send({ result: "success" });
}
};
}
1 change: 1 addition & 0 deletions lib/MongoDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export enum Collections {
Sessions = "sessions",
Forms = "Forms",
Pitreports = "Pitreports",
Picklists = "Picklists",
}

export async function GetDatabase(): Promise<MongoDBInterface> {
Expand Down
13 changes: 12 additions & 1 deletion lib/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,14 +235,17 @@ export class Competition {
pitReports: string[];
matches: string[];

picklist: string;

constructor(
name: string,
slug: string | undefined,
tbaId: string | undefined,
start: number,
end: number,
pitReports: string[] = [],
matches: string[] = []
matches: string[] = [],
picklist: string = ""
) {
this.name = name;
this.slug = slug;
Expand All @@ -251,6 +254,7 @@ export class Competition {
this.end = end;
this.pitReports = pitReports;
this.matches = matches;
this.picklist = picklist;
}
}

Expand Down Expand Up @@ -349,3 +353,10 @@ export interface EventData {
firstRanking: TheBlueAlliance.SimpleRank[];
oprRanking: TheBlueAlliance.OprRanking;
}

export type DbPicklist = {
_id: string;
picklists: {
[name: string]: number[];
};
}
9 changes: 9 additions & 0 deletions lib/client/ClientAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
FormData,
EventData,
Pitreport,
DbPicklist,
} from "../Types";

export enum ClientRequestMethod {
Expand Down Expand Up @@ -392,4 +393,12 @@ export default class ClientAPI {
return await this.request("/findScouterManagementData", { compId, scouterIds });
}

async getPicklist(id: string): Promise<DbPicklist> {
return await this.request("/getPicklist", { id });
}

async updatePicklist(picklist: DbPicklist) {
return await this.request("/updatePicklist", { picklist });
}

}
3 changes: 2 additions & 1 deletion pages/[teamSlug]/[seasonSlug]/[competitonSlug]/stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ export default function Stats(props: StatsPageProps) {
) : (
<></>
)}
{page === 1 ? <PicklistScreen teams={Array.from(teams)} reports={reports}></PicklistScreen> : <></>}
{page === 1 ? <PicklistScreen
teams={Array.from(teams)} reports={reports} expectedTeamCount={props.competition.pitReports.length} picklistId={props.competition.picklist}></PicklistScreen> : <></>}
</Container>
);
}
Expand Down

0 comments on commit 00c62bb

Please sign in to comment.