From 823a6f99812aeb89712deffc16435447816366d0 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Sun, 1 Feb 2026 21:26:54 +0200 Subject: [PATCH 01/18] karni- started working on the router --- .../backend/src/routes/forms-router.ts | 2 +- .../backend/src/routes/general-router.ts | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 apps/scouting/backend/src/routes/general-router.ts diff --git a/apps/scouting/backend/src/routes/forms-router.ts b/apps/scouting/backend/src/routes/forms-router.ts index 97b04e5..1719551 100644 --- a/apps/scouting/backend/src/routes/forms-router.ts +++ b/apps/scouting/backend/src/routes/forms-router.ts @@ -12,7 +12,7 @@ import { mongofyQuery } from "../middleware/query"; export const formsRouter = Router(); -const getCollection = flow( +export const getCollection = flow( getDb, map((db) => db.collection("forms")), ); diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts new file mode 100644 index 0000000..87ae402 --- /dev/null +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -0,0 +1,58 @@ +//בס"ד +/* eslint-disable @typescript-eslint/no-magic-numbers */ //for the example bps + +import { Router } from "express"; +import { getCollection } from "./forms-router"; +import { pipe } from "fp-ts/lib/function"; +import { fold, map } from "fp-ts/lib/TaskEither"; +import { mongofyQuery } from "../middleware/query"; +import { generalCalculateFuel } from "../fuel/fuel-general"; +import type { BPS } from "../fuel/fuel-object"; +import { StatusCodes } from "http-status-codes"; + +export const generalRouter = Router(); + +const EXAMPLE_BPS: BPS[] = [ + { + match: { + number: 42, + type: "qualification", + }, + events: [ + { + shoot: [12, 45, 88, 110], + score: [12, 88], + }, + { + shoot: [135, 140], + score: [135, 140], + }, + ], + }, +]; + +generalRouter.get("/", (req, res) => { + pipe( + getCollection(), + map((collection) => collection.find(mongofyQuery(req.query)).toArray()), + map( + async (forms) => + (await forms).map((form) => { + generalCalculateFuel(form, EXAMPLE_BPS); + }), + //write a way to get only the avarages + forEach((calculatedFuel)=>{ + + }) + ), + + fold( + (error) => () => + Promise.resolve(res.status(error.status).send(error.reason)), + (calculatedFuel) => async () => + res + .status(StatusCodes.OK) + .json({ calculatedFuel: await calculatedFuel }), + ), + ); +}); From b555d8867270a3bbc83a54170fe181bc483d32bd Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:39:13 +0200 Subject: [PATCH 02/18] karni- started working on the router --- apps/scouting/backend/src/routes/general-router.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index 87ae402..271336b 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -41,9 +41,7 @@ generalRouter.get("/", (req, res) => { generalCalculateFuel(form, EXAMPLE_BPS); }), //write a way to get only the avarages - forEach((calculatedFuel)=>{ - - }) + forEach((calculatedFuel) => {}), ), fold( From c47f4a0232a80d149aa701b8a4882b0eeb438df3 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:40:09 +0200 Subject: [PATCH 03/18] karni- wrote the get command --- .../scouting/backend/src/fuel/fuel-general.ts | 2 +- .../backend/src/routes/general-router.ts | 106 +++++++++++++++--- 2 files changed, 90 insertions(+), 18 deletions(-) diff --git a/apps/scouting/backend/src/fuel/fuel-general.ts b/apps/scouting/backend/src/fuel/fuel-general.ts index 520b178..c0ffe33 100644 --- a/apps/scouting/backend/src/fuel/fuel-general.ts +++ b/apps/scouting/backend/src/fuel/fuel-general.ts @@ -3,7 +3,7 @@ import type { BPS, FuelObject } from "./fuel-object"; import { createFuelObject } from "./fuel-object"; import type { ScoutingForm, ShiftsArray } from "@repo/scouting_types"; -interface GeneralFuelData { +export interface GeneralFuelData { fullGame:FuelObject; auto:FuelObject; tele:FuelObject; diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index 271336b..cb51621 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -4,11 +4,14 @@ import { Router } from "express"; import { getCollection } from "./forms-router"; import { pipe } from "fp-ts/lib/function"; -import { fold, map } from "fp-ts/lib/TaskEither"; +import { flatMap, fold, map, tryCatch } from "fp-ts/lib/TaskEither"; import { mongofyQuery } from "../middleware/query"; +import type { GeneralFuelData } from "../fuel/fuel-general"; import { generalCalculateFuel } from "../fuel/fuel-general"; -import type { BPS } from "../fuel/fuel-object"; +import type { BPS, FuelObject } from "../fuel/fuel-object"; import { StatusCodes } from "http-status-codes"; +import { first } from "fp-ts/lib/Semigroup"; +import { reduce } from "fp-ts/lib/Foldable"; export const generalRouter = Router(); @@ -31,26 +34,95 @@ const EXAMPLE_BPS: BPS[] = [ }, ]; -generalRouter.get("/", (req, res) => { - pipe( +interface TeamNumberAndFuelData { + teamNumber: number; + generalFuelData: GeneralFuelData; +} + +const calcAverage = (num1: number, num2: number) => { + return (num1 + num2) / 2; +}; + +const calcAverageFuelObject = ( + firstData: FuelObject, + secondData: FuelObject, +) => { + const newData: FuelObject = { + scored: calcAverage(firstData.scored, secondData.scored), + shot: calcAverage(firstData.shot, secondData.shot), + missed: calcAverage(firstData.missed, secondData.missed), + positions: [...firstData.positions, ...secondData.positions], + }; + return newData; +}; + +const calcAverageGeneralFuelData = (fuelData: GeneralFuelData[]) => { + if (fuelData.length === 1 || fuelData.length === 0) { + return fuelData[0]; + } + return fuelData.reduce((accumulatedFuelData, currentFuelData) => { + const newFuelData: GeneralFuelData = { + fullGame: calcAverageFuelObject( + accumulatedFuelData.fullGame, + currentFuelData.fullGame, + ), + auto: calcAverageFuelObject( + accumulatedFuelData.auto, + currentFuelData.auto, + ), + tele: calcAverageFuelObject( + accumulatedFuelData.tele, + currentFuelData.tele, + ), + }; + return newFuelData; + }, fuelData[0]); +}; + +generalRouter.get("/", async (req, res) => { + await pipe( getCollection(), - map((collection) => collection.find(mongofyQuery(req.query)).toArray()), - map( - async (forms) => - (await forms).map((form) => { - generalCalculateFuel(form, EXAMPLE_BPS); - }), - //write a way to get only the avarages - forEach((calculatedFuel) => {}), + flatMap((collection) => + tryCatch( + () => collection.find(mongofyQuery(req.query)).toArray(), + (error) => ({ status: 500, reason: `DB Error: ${error}` }), + ), ), + map((forms) => + forms.map((form) => { + const newFuelData: TeamNumberAndFuelData = { + teamNumber: form.teamNumber, + generalFuelData: generalCalculateFuel(form, EXAMPLE_BPS), + }; + return newFuelData; + }), + ), + + map((generalFuelsData) => { + const teamMap: Map = new Map(); + generalFuelsData.forEach((current) => { + if (teamMap.has(current.teamNumber)) return; + + const sameTeamFuelData = generalFuelsData.filter( + (teamAndFuelData) => + teamAndFuelData.teamNumber === current.teamNumber, + ); + const averagedFuelData: TeamNumberAndFuelData = { + teamNumber: current.teamNumber, + generalFuelData: calcAverageGeneralFuelData( + sameTeamFuelData.map((fuelData) => fuelData.generalFuelData), + ), + }; + teamMap.set(current.teamNumber, averagedFuelData); + }); + return Array.from(teamMap.values()); + }), fold( (error) => () => Promise.resolve(res.status(error.status).send(error.reason)), - (calculatedFuel) => async () => - res - .status(StatusCodes.OK) - .json({ calculatedFuel: await calculatedFuel }), + (calculatedFuel) => () => + Promise.resolve(res.status(StatusCodes.OK).json({ calculatedFuel })), ), - ); + )(); }); From 22a6a8054219b45143b5b869a8cb535800ad1c68 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Wed, 4 Feb 2026 20:25:54 +0200 Subject: [PATCH 04/18] karni- added a fuel types folder --- .../backend/src/fuel/fuel-averaging.ts | 3 +- .../scouting/backend/src/fuel/fuel-general.ts | 9 +---- apps/scouting/backend/src/fuel/fuel-object.ts | 15 +------ apps/scouting/backend/src/game-object.ts | 15 ------- .../backend/src/routes/general-router.ts | 5 +-- apps/scouting/backend/src/routes/index.ts | 6 ++- .../scouter/components/GeneralDataTable.tsx | 32 +++++++++++++++ package.json | 1 + packages/scouting_types/index.ts | 6 +-- .../scouting_types/rebuilt/fuel/FuelTypes.ts | 39 +++++++++++++++++++ .../rebuilt/{ => scouting_form}/GameData.ts | 0 .../rebuilt/{ => scouting_form}/Interval.ts | 0 .../rebuilt/{ => scouting_form}/Movement.ts | 0 .../{ => scouting_form}/ScoutingForm.ts | 0 .../rebuilt/{ => scouting_form}/Segments.ts | 0 .../rebuilt/{ => scouting_form}/Serde.ts | 0 .../rebuilt/{ => scouting_form}/Shift.ts | 0 .../rebuilt/{ => scouting_form}/ShootEvent.ts | 0 .../rebuilt/{ => scouting_form}/index.ts | 0 19 files changed, 85 insertions(+), 46 deletions(-) create mode 100644 apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx create mode 100644 packages/scouting_types/rebuilt/fuel/FuelTypes.ts rename packages/scouting_types/rebuilt/{ => scouting_form}/GameData.ts (100%) rename packages/scouting_types/rebuilt/{ => scouting_form}/Interval.ts (100%) rename packages/scouting_types/rebuilt/{ => scouting_form}/Movement.ts (100%) rename packages/scouting_types/rebuilt/{ => scouting_form}/ScoutingForm.ts (100%) rename packages/scouting_types/rebuilt/{ => scouting_form}/Segments.ts (100%) rename packages/scouting_types/rebuilt/{ => scouting_form}/Serde.ts (100%) rename packages/scouting_types/rebuilt/{ => scouting_form}/Shift.ts (100%) rename packages/scouting_types/rebuilt/{ => scouting_form}/ShootEvent.ts (100%) rename packages/scouting_types/rebuilt/{ => scouting_form}/index.ts (100%) diff --git a/apps/scouting/backend/src/fuel/fuel-averaging.ts b/apps/scouting/backend/src/fuel/fuel-averaging.ts index ee0e334..a424e7d 100644 --- a/apps/scouting/backend/src/fuel/fuel-averaging.ts +++ b/apps/scouting/backend/src/fuel/fuel-averaging.ts @@ -1,6 +1,5 @@ // בס"ד -import type { Match, ShootEvent } from "@repo/scouting_types"; -import type { BPS, FuelObject } from "./fuel-object"; +import type { BPS, FuelObject, Match, ShootEvent } from "@repo/scouting_types"; import { calculateSum, firstElement, lastElement } from "@repo/array-functions"; const EMPTY_INTERVAL_DURATION = 0; diff --git a/apps/scouting/backend/src/fuel/fuel-general.ts b/apps/scouting/backend/src/fuel/fuel-general.ts index c0ffe33..173db03 100644 --- a/apps/scouting/backend/src/fuel/fuel-general.ts +++ b/apps/scouting/backend/src/fuel/fuel-general.ts @@ -1,13 +1,8 @@ // בס"ד -import type { BPS, FuelObject } from "./fuel-object"; import { createFuelObject } from "./fuel-object"; -import type { ScoutingForm, ShiftsArray } from "@repo/scouting_types"; +import type { BPS, FuelObject, GeneralFuelData, ScoutingForm, ShiftsArray } from "@repo/scouting_types"; + -export interface GeneralFuelData { - fullGame:FuelObject; - auto:FuelObject; - tele:FuelObject; -} const calculateFuelStatisticsOfShift = ( match: ScoutingForm["match"], diff --git a/apps/scouting/backend/src/fuel/fuel-object.ts b/apps/scouting/backend/src/fuel/fuel-object.ts index 41f5578..c4562a9 100644 --- a/apps/scouting/backend/src/fuel/fuel-object.ts +++ b/apps/scouting/backend/src/fuel/fuel-object.ts @@ -1,21 +1,8 @@ // בס"ד -import type { GameObject } from "../game-object"; -import type { Match, Point, ShootEvent } from "@repo/scouting_types"; +import type { BPS, FuelObject, Match, Point, ShootEvent } from "@repo/scouting_types"; import { calculateFuelByAveraging } from "./fuel-averaging"; import { calculateFuelByMatch } from "./fuel-match"; -export interface BPS { - events: { shoot: number[]; score: number[] }[]; - match: Match; -} - -type FuelEvents = "scored" | "shot" | "missed"; -export type FuelObject = GameObject< - FuelEvents, - { - positions: Point[]; - } ->; export const createFuelObject = ( shot: ShootEvent, diff --git a/apps/scouting/backend/src/game-object.ts b/apps/scouting/backend/src/game-object.ts index 89d0398..f3be8bb 100644 --- a/apps/scouting/backend/src/game-object.ts +++ b/apps/scouting/backend/src/game-object.ts @@ -1,17 +1,2 @@ // בס"ד -export type GameObject = Record & - AdditionalInfo; - -export const addGameEvent = ( - gameObject: GameObject, - event: T, -): void => { - gameObject[event]++; -}; - -export interface GameObjectWithPoints { - gameObject: GameObject; - calculatePoints: (gameObject: GameObject) => number; - calculateRP: (gameObject: GameObject) => number; -} diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index cb51621..d12eb33 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -6,12 +6,11 @@ import { getCollection } from "./forms-router"; import { pipe } from "fp-ts/lib/function"; import { flatMap, fold, map, tryCatch } from "fp-ts/lib/TaskEither"; import { mongofyQuery } from "../middleware/query"; -import type { GeneralFuelData } from "../fuel/fuel-general"; import { generalCalculateFuel } from "../fuel/fuel-general"; -import type { BPS, FuelObject } from "../fuel/fuel-object"; import { StatusCodes } from "http-status-codes"; import { first } from "fp-ts/lib/Semigroup"; import { reduce } from "fp-ts/lib/Foldable"; +import type { BPS, FuelObject, GeneralFuelData } from "@repo/scouting_types"; export const generalRouter = Router(); @@ -34,7 +33,7 @@ const EXAMPLE_BPS: BPS[] = [ }, ]; -interface TeamNumberAndFuelData { +export interface TeamNumberAndFuelData { teamNumber: number; generalFuelData: GeneralFuelData; } diff --git a/apps/scouting/backend/src/routes/index.ts b/apps/scouting/backend/src/routes/index.ts index 153f0df..c37dd00 100644 --- a/apps/scouting/backend/src/routes/index.ts +++ b/apps/scouting/backend/src/routes/index.ts @@ -4,13 +4,15 @@ import { StatusCodes } from "http-status-codes"; import { tbaRouter } from "./tba"; import { gameRouter } from "./game-router"; import { formsRouter } from "./forms-router"; +import { generalRouter } from "./general-router"; export const apiRouter = Router(); -apiRouter.use("/forms",formsRouter); +apiRouter.use("/forms", formsRouter); apiRouter.use("/tba", tbaRouter); apiRouter.use("/game", gameRouter); +apiRouter.use("/general", generalRouter); apiRouter.get("/health", (req, res) => { res.status(StatusCodes.OK).send({ message: "Healthy!" }); -}); \ No newline at end of file +}); diff --git a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx new file mode 100644 index 0000000..c5d1234 --- /dev/null +++ b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx @@ -0,0 +1,32 @@ +//בס"ד + +import type React from "react"; + +const fetchFuelData = async (filters = {}) => { + const queryString = new URLSearchParams(filters).toString(); + const url = `/api/v1/general/${queryString ? `?${queryString}` : ""}`; + + try { + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Server Error: ${errorText}`); + } + + const data = await response.json(); + + return data.calculatedFuel; + } catch (err) { + console.error("Fetch failed:", err); + throw err; + } +}; +const GeneralDataTable: React.FC = () => { + return <>; +}; diff --git a/package.json b/package.json index d47b46b..d547449 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "dependencies": { "@radix-ui/react-slider": "^1.3.6", "@tailwindcss/vite": "^4.1.17", + "@tanstack/react-table": "^8.21.3", "axios": "^1.13.2", "dotenv": "^17.2.3", "dotenv-cli": "^11.0.0", diff --git a/packages/scouting_types/index.ts b/packages/scouting_types/index.ts index e28d763..587396e 100644 --- a/packages/scouting_types/index.ts +++ b/packages/scouting_types/index.ts @@ -1,7 +1,7 @@ // בס"ד -export * from "./rebuilt"; -export * from "./tba"; +export * from "./rebuilt/scouting_form"; +export * from "./rebuilt/fuel/FuelTypes"; +export * from "./tba"; export type Alliance = "red" | "blue"; - diff --git a/packages/scouting_types/rebuilt/fuel/FuelTypes.ts b/packages/scouting_types/rebuilt/fuel/FuelTypes.ts new file mode 100644 index 0000000..6e09286 --- /dev/null +++ b/packages/scouting_types/rebuilt/fuel/FuelTypes.ts @@ -0,0 +1,39 @@ +//בס"ד + +import type { Match, Point } from "../scouting_form"; + +export interface GeneralFuelData { + fullGame: FuelObject; + auto: FuelObject; + tele: FuelObject; +} + +export interface BPS { + events: { shoot: number[]; score: number[] }[]; + match: Match; +} + +type FuelEvents = "scored" | "shot" | "missed"; +export type FuelObject = GameObject< + FuelEvents, + { + positions: Point[]; + } +>; + + +export type GameObject = Record & + AdditionalInfo; + +export const addGameEvent = ( + gameObject: GameObject, + event: T, +): void => { + gameObject[event]++; +}; + +export interface GameObjectWithPoints { + gameObject: GameObject; + calculatePoints: (gameObject: GameObject) => number; + calculateRP: (gameObject: GameObject) => number; +} diff --git a/packages/scouting_types/rebuilt/GameData.ts b/packages/scouting_types/rebuilt/scouting_form/GameData.ts similarity index 100% rename from packages/scouting_types/rebuilt/GameData.ts rename to packages/scouting_types/rebuilt/scouting_form/GameData.ts diff --git a/packages/scouting_types/rebuilt/Interval.ts b/packages/scouting_types/rebuilt/scouting_form/Interval.ts similarity index 100% rename from packages/scouting_types/rebuilt/Interval.ts rename to packages/scouting_types/rebuilt/scouting_form/Interval.ts diff --git a/packages/scouting_types/rebuilt/Movement.ts b/packages/scouting_types/rebuilt/scouting_form/Movement.ts similarity index 100% rename from packages/scouting_types/rebuilt/Movement.ts rename to packages/scouting_types/rebuilt/scouting_form/Movement.ts diff --git a/packages/scouting_types/rebuilt/ScoutingForm.ts b/packages/scouting_types/rebuilt/scouting_form/ScoutingForm.ts similarity index 100% rename from packages/scouting_types/rebuilt/ScoutingForm.ts rename to packages/scouting_types/rebuilt/scouting_form/ScoutingForm.ts diff --git a/packages/scouting_types/rebuilt/Segments.ts b/packages/scouting_types/rebuilt/scouting_form/Segments.ts similarity index 100% rename from packages/scouting_types/rebuilt/Segments.ts rename to packages/scouting_types/rebuilt/scouting_form/Segments.ts diff --git a/packages/scouting_types/rebuilt/Serde.ts b/packages/scouting_types/rebuilt/scouting_form/Serde.ts similarity index 100% rename from packages/scouting_types/rebuilt/Serde.ts rename to packages/scouting_types/rebuilt/scouting_form/Serde.ts diff --git a/packages/scouting_types/rebuilt/Shift.ts b/packages/scouting_types/rebuilt/scouting_form/Shift.ts similarity index 100% rename from packages/scouting_types/rebuilt/Shift.ts rename to packages/scouting_types/rebuilt/scouting_form/Shift.ts diff --git a/packages/scouting_types/rebuilt/ShootEvent.ts b/packages/scouting_types/rebuilt/scouting_form/ShootEvent.ts similarity index 100% rename from packages/scouting_types/rebuilt/ShootEvent.ts rename to packages/scouting_types/rebuilt/scouting_form/ShootEvent.ts diff --git a/packages/scouting_types/rebuilt/index.ts b/packages/scouting_types/rebuilt/scouting_form/index.ts similarity index 100% rename from packages/scouting_types/rebuilt/index.ts rename to packages/scouting_types/rebuilt/scouting_form/index.ts From f1043636e613ef792ce316fc3ea3a67a6223fa6b Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Wed, 4 Feb 2026 20:33:56 +0200 Subject: [PATCH 05/18] karni- no magic numbers --- .../backend/src/routes/general-router.ts | 26 +++++++++++-------- .../scouter/components/GeneralDataTable.tsx | 2 +- .../scouting_types/rebuilt/fuel/FuelTypes.ts | 6 ++++- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index d12eb33..82f0021 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -8,9 +8,13 @@ import { flatMap, fold, map, tryCatch } from "fp-ts/lib/TaskEither"; import { mongofyQuery } from "../middleware/query"; import { generalCalculateFuel } from "../fuel/fuel-general"; import { StatusCodes } from "http-status-codes"; -import { first } from "fp-ts/lib/Semigroup"; -import { reduce } from "fp-ts/lib/Foldable"; -import type { BPS, FuelObject, GeneralFuelData } from "@repo/scouting_types"; + +import type { + BPS, + FuelObject, + GeneralFuelData, + TeamNumberAndFuelData, +} from "@repo/scouting_types"; export const generalRouter = Router(); @@ -33,13 +37,13 @@ const EXAMPLE_BPS: BPS[] = [ }, ]; -export interface TeamNumberAndFuelData { - teamNumber: number; - generalFuelData: GeneralFuelData; -} +const DIVIDE_BY_TO_GET_AVERAGE = 2; +const ONE_ITEM_ARRAY = 1; +const EMPTY_ARRAY = 0; +const FIRST_ARRAY_ITEM = 0; const calcAverage = (num1: number, num2: number) => { - return (num1 + num2) / 2; + return (num1 + num2) / DIVIDE_BY_TO_GET_AVERAGE; }; const calcAverageFuelObject = ( @@ -56,8 +60,8 @@ const calcAverageFuelObject = ( }; const calcAverageGeneralFuelData = (fuelData: GeneralFuelData[]) => { - if (fuelData.length === 1 || fuelData.length === 0) { - return fuelData[0]; + if (fuelData.length === ONE_ITEM_ARRAY || fuelData.length === EMPTY_ARRAY) { + return fuelData[FIRST_ARRAY_ITEM]; } return fuelData.reduce((accumulatedFuelData, currentFuelData) => { const newFuelData: GeneralFuelData = { @@ -75,7 +79,7 @@ const calcAverageGeneralFuelData = (fuelData: GeneralFuelData[]) => { ), }; return newFuelData; - }, fuelData[0]); + }, fuelData[FIRST_ARRAY_ITEM]); }; generalRouter.get("/", async (req, res) => { diff --git a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx index c5d1234..312fe98 100644 --- a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx +++ b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx @@ -21,7 +21,7 @@ const fetchFuelData = async (filters = {}) => { const data = await response.json(); - return data.calculatedFuel; + return data.calculatedFuel as ; } catch (err) { console.error("Fetch failed:", err); throw err; diff --git a/packages/scouting_types/rebuilt/fuel/FuelTypes.ts b/packages/scouting_types/rebuilt/fuel/FuelTypes.ts index 6e09286..173778d 100644 --- a/packages/scouting_types/rebuilt/fuel/FuelTypes.ts +++ b/packages/scouting_types/rebuilt/fuel/FuelTypes.ts @@ -21,7 +21,6 @@ export type FuelObject = GameObject< } >; - export type GameObject = Record & AdditionalInfo; @@ -37,3 +36,8 @@ export interface GameObjectWithPoints { calculatePoints: (gameObject: GameObject) => number; calculateRP: (gameObject: GameObject) => number; } + +export interface TeamNumberAndFuelData { + teamNumber: number; + generalFuelData: GeneralFuelData; +} From 9c7483b93f86c2079890cce773fc6ec3dd45ac76 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Wed, 4 Feb 2026 20:55:06 +0200 Subject: [PATCH 06/18] karni- started working on the table component --- .../src/scouter/components/GeneralDataTable.tsx | 16 +++++++++++++--- .../scouting_types/rebuilt/fuel/FuelTypes.ts | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx index 312fe98..943b1cd 100644 --- a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx +++ b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx @@ -1,6 +1,8 @@ //בס"ד - +import { createColumnHelper } from "@tanstack/react-table"; +import type { GameTime, TeamNumberAndFuelData } from "@repo/scouting_types"; import type React from "react"; +import { useState } from "react"; const fetchFuelData = async (filters = {}) => { const queryString = new URLSearchParams(filters).toString(); @@ -21,12 +23,20 @@ const fetchFuelData = async (filters = {}) => { const data = await response.json(); - return data.calculatedFuel as ; + return data.calculatedFuel as TeamNumberAndFuelData[]; } catch (err) { console.error("Fetch failed:", err); throw err; } }; -const GeneralDataTable: React.FC = () => { + +interface GeneralDataTableProps { + filters: string[]; +} + +const GeneralDataTable: React.FC = ({ filters }) => { + const [gameTime, setGameTime] = useState(); + const columnHelper = createColumnHelper(); + return <>; }; diff --git a/packages/scouting_types/rebuilt/fuel/FuelTypes.ts b/packages/scouting_types/rebuilt/fuel/FuelTypes.ts index 173778d..e4b3139 100644 --- a/packages/scouting_types/rebuilt/fuel/FuelTypes.ts +++ b/packages/scouting_types/rebuilt/fuel/FuelTypes.ts @@ -8,6 +8,9 @@ export interface GeneralFuelData { tele: FuelObject; } +export type GameTime = keyof GeneralFuelData; + + export interface BPS { events: { shoot: number[]; score: number[] }[]; match: Match; From cdea5aabddecb9ca0dda779c3caa173d62cddacb Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Wed, 4 Feb 2026 21:26:24 +0200 Subject: [PATCH 07/18] karni- trying my best --- apps/scouting/frontend/src/App.tsx | 8 +- .../scouter/components/GeneralDataTable.tsx | 145 ++++++++++++++++-- 2 files changed, 137 insertions(+), 16 deletions(-) diff --git a/apps/scouting/frontend/src/App.tsx b/apps/scouting/frontend/src/App.tsx index 5be893b..5e9f063 100644 --- a/apps/scouting/frontend/src/App.tsx +++ b/apps/scouting/frontend/src/App.tsx @@ -3,13 +3,13 @@ import type { FC } from "react"; import { ScoutMatch } from "./scouter/pages/ScoutMatch"; import { Route, Routes } from "react-router-dom"; import { ScoutedMatches } from "./scouter/pages/ScoutedMatches"; +import GeneralDataTable from "./scouter/components/GeneralDataTable"; const App: FC = () => { return ( - - } /> - } /> - + <> + + ); }; export default App; diff --git a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx index 943b1cd..90a8c5f 100644 --- a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx +++ b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx @@ -1,19 +1,24 @@ -//בס"ד -import { createColumnHelper } from "@tanstack/react-table"; +// בס"ד +import { + createColumnHelper, + flexRender, + getCoreRowModel, + getSortedRowModel, + useReactTable, + type SortingState, +} from "@tanstack/react-table"; import type { GameTime, TeamNumberAndFuelData } from "@repo/scouting_types"; import type React from "react"; -import { useState } from "react"; +import { useState, useEffect } from "react"; const fetchFuelData = async (filters = {}) => { - const queryString = new URLSearchParams(filters).toString(); - const url = `/api/v1/general/${queryString ? `?${queryString}` : ""}`; + const params = new URLSearchParams(filters); + const url = `/api/v1/general/?${params.toString()}`; try { const response = await fetch(url, { method: "GET", - headers: { - "Content-Type": "application/json", - }, + headers: { "Content-Type": "application/json" }, }); if (!response.ok) { @@ -22,7 +27,6 @@ const fetchFuelData = async (filters = {}) => { } const data = await response.json(); - return data.calculatedFuel as TeamNumberAndFuelData[]; } catch (err) { console.error("Fetch failed:", err); @@ -31,12 +35,129 @@ const fetchFuelData = async (filters = {}) => { }; interface GeneralDataTableProps { - filters: string[]; + filters: {}; } +const DIGITS_AFTER_DOT = 1; + const GeneralDataTable: React.FC = ({ filters }) => { - const [gameTime, setGameTime] = useState(); + const [data, setData] = useState([]); + const [gameTime, setGameTime] = useState("tele"); + const [sorting, setSorting] = useState([]); + + useEffect(() => { + fetchFuelData(filters).catch(console.error); + }, [filters]); + const columnHelper = createColumnHelper(); - return <>; + const columns = [ + columnHelper.accessor("teamNumber", { + header: "Team Number", + cell: (info) => ( + {info.getValue()} + ), + }), + columnHelper.accessor((row) => row.generalFuelData[gameTime].shot, { + id: "shot", + header: "Shot", + cell: (info) => info.getValue().toFixed(DIGITS_AFTER_DOT), + }), + columnHelper.accessor((row) => row.generalFuelData[gameTime].scored, { + id: "scored", + header: "Scored", + cell: (info) => info.getValue().toFixed(DIGITS_AFTER_DOT), + }), + columnHelper.accessor( + (row) => { + const stats = row.generalFuelData[gameTime]; + return stats.shot - stats.scored; + }, + { + id: "missed", + header: "Missed", + cell: (info) => ( + + {info.getValue().toFixed(DIGITS_AFTER_DOT)} + + ), + }, + ), + ]; + + const table = useReactTable({ + data, + columns, + state: { sorting }, + onSortingChange: setSorting, + getCoreRowModel: getCoreRowModel(), + getSortedRowModel: getSortedRowModel(), + }); + + return ( +
+
+ {(["auto", "tele", "fullGame"] as GameTime[]).map((time) => ( + + ))} +
+ +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + ))} + + ))} + + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} + + ))} + +
+
+ {flexRender( + header.column.columnDef.header, + header.getContext(), + )} + {{ + asc: "ascending", + desc: "descending", + }[header.column.getIsSorted() as string] ?? "sort"} +
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} +
+
+
+ ); }; + +export default GeneralDataTable; From 8cbeb73df48a8707b61e813954cc45e5a0e153e8 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Wed, 4 Feb 2026 21:35:40 +0200 Subject: [PATCH 08/18] karni- code might work, god is real --- apps/scouting/backend/build.ts | 2 +- apps/scouting/frontend/src/App.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/scouting/backend/build.ts b/apps/scouting/backend/build.ts index f49c7c4..78b771e 100644 --- a/apps/scouting/backend/build.ts +++ b/apps/scouting/backend/build.ts @@ -2,7 +2,7 @@ import { build, context } from "esbuild"; import { spawn } from "child_process"; -const isDev = process.env.NODE_ENV === "DEV"; +const isDev = process.env.NODE_ENV !== "DEV"; const bundlePath = "dist/bundle.js"; diff --git a/apps/scouting/frontend/src/App.tsx b/apps/scouting/frontend/src/App.tsx index 5e9f063..b9c492f 100644 --- a/apps/scouting/frontend/src/App.tsx +++ b/apps/scouting/frontend/src/App.tsx @@ -8,7 +8,7 @@ import GeneralDataTable from "./scouter/components/GeneralDataTable"; const App: FC = () => { return ( <> - + ); }; From 58920aace24227132f4c1a39ba579cfe50d8e416 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Wed, 4 Feb 2026 21:49:12 +0200 Subject: [PATCH 09/18] karni- finished the table - ready for pr --- apps/scouting/frontend/src/App.tsx | 2 +- .../scouter/components/GeneralDataTable.tsx | 45 +++++++++++-------- package.json | 1 + 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/scouting/frontend/src/App.tsx b/apps/scouting/frontend/src/App.tsx index b9c492f..029384f 100644 --- a/apps/scouting/frontend/src/App.tsx +++ b/apps/scouting/frontend/src/App.tsx @@ -3,7 +3,7 @@ import type { FC } from "react"; import { ScoutMatch } from "./scouter/pages/ScoutMatch"; import { Route, Routes } from "react-router-dom"; import { ScoutedMatches } from "./scouter/pages/ScoutedMatches"; -import GeneralDataTable from "./scouter/components/GeneralDataTable"; +import { GeneralDataTable } from "./scouter/components/GeneralDataTable"; const App: FC = () => { return ( diff --git a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx index 90a8c5f..41b0ffe 100644 --- a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx +++ b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx @@ -10,6 +10,7 @@ import { import type { GameTime, TeamNumberAndFuelData } from "@repo/scouting_types"; import type React from "react"; import { useState, useEffect } from "react"; +import { ChevronUp, ChevronDown, ChevronsUpDown } from "lucide-react"; const fetchFuelData = async (filters = {}) => { const params = new URLSearchParams(filters); @@ -40,7 +41,9 @@ interface GeneralDataTableProps { const DIGITS_AFTER_DOT = 1; -const GeneralDataTable: React.FC = ({ filters }) => { +export const GeneralDataTable: React.FC = ({ + filters, +}) => { const [data, setData] = useState([]); const [gameTime, setGameTime] = useState("tele"); const [sorting, setSorting] = useState([]); @@ -95,18 +98,19 @@ const GeneralDataTable: React.FC = ({ filters }) => { }); return ( -
-
+
+ {/* Game Time Switcher */} +
{(["auto", "tele", "fullGame"] as GameTime[]).map((time) => (
-
- - + {/* Table Container */} +
+
+ {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( ))} ))} - + {table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( - ))} @@ -159,5 +168,3 @@ const GeneralDataTable: React.FC = ({ filters }) => { ); }; - -export default GeneralDataTable; diff --git a/package.json b/package.json index d547449..a798082 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "http-status-codes": "^2.3.0", "io-ts": "^2.2.22", "is-odd": "^3.0.1", + "lucide-react": "^0.563.0", "mongodb": "^7.0.0", "qrcode.react": "^4.2.0", "react-icons": "^5.5.0", From 36a3a5986ac65dd98c9a5eeda55b0f7f72f15575 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:51:35 +0200 Subject: [PATCH 10/18] karni- fixed the way I process some of the data --- .../backend/src/routes/forms-router.ts | 6 +-- .../backend/src/routes/general-router.ts | 45 ++++++++--------- .../scouter/components/GeneralDataTable.tsx | 48 ++++++++++++++----- .../scouting_types/rebuilt/fuel/FuelTypes.ts | 7 ++- 4 files changed, 61 insertions(+), 45 deletions(-) diff --git a/apps/scouting/backend/src/routes/forms-router.ts b/apps/scouting/backend/src/routes/forms-router.ts index 1719551..ca80aac 100644 --- a/apps/scouting/backend/src/routes/forms-router.ts +++ b/apps/scouting/backend/src/routes/forms-router.ts @@ -12,14 +12,14 @@ import { mongofyQuery } from "../middleware/query"; export const formsRouter = Router(); -export const getCollection = flow( +export const getFormsCollection = flow( getDb, map((db) => db.collection("forms")), ); formsRouter.get("/", async (req, res) => { await pipe( - getCollection(), + getFormsCollection(), map((collection) => collection.find(mongofyQuery(req.query)).toArray()), fold( (error) => () => @@ -32,7 +32,7 @@ formsRouter.get("/", async (req, res) => { formsRouter.post("/single", async (req, res) => { await pipe( - getCollection(), + getFormsCollection(), flatMap((collection) => pipe( right(req), diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index 82f0021..e2a40f1 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-magic-numbers */ //for the example bps import { Router } from "express"; -import { getCollection } from "./forms-router"; +import { getFormsCollection } from "./forms-router"; import { pipe } from "fp-ts/lib/function"; import { flatMap, fold, map, tryCatch } from "fp-ts/lib/TaskEither"; import { mongofyQuery } from "../middleware/query"; @@ -13,7 +13,6 @@ import type { BPS, FuelObject, GeneralFuelData, - TeamNumberAndFuelData, } from "@repo/scouting_types"; export const generalRouter = Router(); @@ -84,7 +83,7 @@ const calcAverageGeneralFuelData = (fuelData: GeneralFuelData[]) => { generalRouter.get("/", async (req, res) => { await pipe( - getCollection(), + getFormsCollection(), flatMap((collection) => tryCatch( () => collection.find(mongofyQuery(req.query)).toArray(), @@ -92,33 +91,29 @@ generalRouter.get("/", async (req, res) => { ), ), map((forms) => - forms.map((form) => { - const newFuelData: TeamNumberAndFuelData = { - teamNumber: form.teamNumber, - generalFuelData: generalCalculateFuel(form, EXAMPLE_BPS), - }; - return newFuelData; - }), + forms.map((form) => ({ + teamNumber: form.teamNumber, + generalFuelData: generalCalculateFuel(form, EXAMPLE_BPS), + })), ), map((generalFuelsData) => { - const teamMap: Map = new Map(); - generalFuelsData.forEach((current) => { - if (teamMap.has(current.teamNumber)) return; + const teamAndAllFuelData: Record = + generalFuelsData.reduce((finalRecord, fuelData) => { + finalRecord[fuelData.teamNumber] + ? finalRecord[fuelData.teamNumber].push(fuelData.generalFuelData) + : (finalRecord[fuelData.teamNumber] = [fuelData.generalFuelData]); - const sameTeamFuelData = generalFuelsData.filter( - (teamAndFuelData) => - teamAndFuelData.teamNumber === current.teamNumber, - ); - const averagedFuelData: TeamNumberAndFuelData = { - teamNumber: current.teamNumber, - generalFuelData: calcAverageGeneralFuelData( - sameTeamFuelData.map((fuelData) => fuelData.generalFuelData), - ), - }; - teamMap.set(current.teamNumber, averagedFuelData); + return finalRecord; + }, {}); + + const teamAndAvaragedFuelData: Record = {}; + Object.entries(teamAndAllFuelData).forEach(([teamNumber, fuelArray]) => { + teamAndAvaragedFuelData[teamNumber] = + calcAverageGeneralFuelData(fuelArray); }); - return Array.from(teamMap.values()); + + return teamAndAvaragedFuelData; }), fold( diff --git a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx index 41b0ffe..36693ab 100644 --- a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx +++ b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx @@ -7,11 +7,20 @@ import { useReactTable, type SortingState, } from "@tanstack/react-table"; -import type { GameTime, TeamNumberAndFuelData } from "@repo/scouting_types"; +import type { + GameTime, + GeneralFuelData, + TeamNumberAndFuelData, +} from "@repo/scouting_types"; import type React from "react"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useMemo } from "react"; import { ChevronUp, ChevronDown, ChevronsUpDown } from "lucide-react"; +interface TableRow { + teamNumber: number; + generalFuelData: GeneralFuelData; +} + const fetchFuelData = async (filters = {}) => { const params = new URLSearchParams(filters); const url = `/api/v1/general/?${params.toString()}`; @@ -28,7 +37,7 @@ const fetchFuelData = async (filters = {}) => { } const data = await response.json(); - return data.calculatedFuel as TeamNumberAndFuelData[]; + return data.calculatedFuel as TeamNumberAndFuelData; } catch (err) { console.error("Fetch failed:", err); throw err; @@ -44,32 +53,47 @@ const DIGITS_AFTER_DOT = 1; export const GeneralDataTable: React.FC = ({ filters, }) => { - const [data, setData] = useState([]); + const [teamNumberAndFuelData, setTeamNumberAndFuelData] = useState({}); const [gameTime, setGameTime] = useState("tele"); const [sorting, setSorting] = useState([]); useEffect(() => { - fetchFuelData(filters).catch(console.error); + fetchFuelData(filters).then(setTeamNumberAndFuelData).catch(console.error); }, [filters]); - const columnHelper = createColumnHelper(); + const tableData = useMemo(() => { + return Object.entries(teamNumberAndFuelData).map(([teamNumber, generalFuelData]) => ({ + teamNumber: Number(teamNumber), + generalFuelData, + })); + }, [teamNumberAndFuelData]); + + const columnHelper = createColumnHelper(); const columns = [ columnHelper.accessor("teamNumber", { header: "Team Number", cell: (info) => ( - {info.getValue()} + {info.getValue()} ), }), columnHelper.accessor((row) => row.generalFuelData[gameTime].shot, { id: "shot", header: "Shot", - cell: (info) => info.getValue().toFixed(DIGITS_AFTER_DOT), + cell: (info) => ( + + {info.getValue().toFixed(DIGITS_AFTER_DOT)} + + ), }), columnHelper.accessor((row) => row.generalFuelData[gameTime].scored, { id: "scored", header: "Scored", - cell: (info) => info.getValue().toFixed(DIGITS_AFTER_DOT), + cell: (info) => ( + + {info.getValue().toFixed(DIGITS_AFTER_DOT)} + + ), }), columnHelper.accessor( (row) => { @@ -80,7 +104,7 @@ export const GeneralDataTable: React.FC = ({ id: "missed", header: "Missed", cell: (info) => ( - + {info.getValue().toFixed(DIGITS_AFTER_DOT)} ), @@ -89,7 +113,7 @@ export const GeneralDataTable: React.FC = ({ ]; const table = useReactTable({ - data, + data: tableData, columns, state: { sorting }, onSortingChange: setSorting, @@ -99,7 +123,6 @@ export const GeneralDataTable: React.FC = ({ return (
- {/* Game Time Switcher */}
{(["auto", "tele", "fullGame"] as GameTime[]).map((time) => (
- {/* Table Container */}
@@ -130,24 +135,28 @@ const GeneralDataTable: React.FC = ({ filters }) => { header.column.columnDef.header, header.getContext(), )} - {{ - asc: "ascending", - desc: "descending", - }[header.column.getIsSorted() as string] ?? "sort"} + + {{ + asc: , + desc: , + }[header.column.getIsSorted() as string] ?? ( + + )} +
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
diff --git a/packages/scouting_types/rebuilt/fuel/FuelTypes.ts b/packages/scouting_types/rebuilt/fuel/FuelTypes.ts index e4b3139..13debb0 100644 --- a/packages/scouting_types/rebuilt/fuel/FuelTypes.ts +++ b/packages/scouting_types/rebuilt/fuel/FuelTypes.ts @@ -40,7 +40,6 @@ export interface GameObjectWithPoints { calculateRP: (gameObject: GameObject) => number; } -export interface TeamNumberAndFuelData { - teamNumber: number; - generalFuelData: GeneralFuelData; -} + + +export type TeamNumberAndFuelData = Record \ No newline at end of file From ae3718ae441d8451467d97d0a66ba9dfa664e031 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Thu, 5 Feb 2026 18:59:21 +0200 Subject: [PATCH 11/18] karni- fixed the averaging --- .../src/fuel/calculations/fuel-averaging.ts | 4 -- .../backend/src/fuel/distance-split.ts | 2 +- .../backend/src/routes/general-router.ts | 72 +++++++++---------- 3 files changed, 33 insertions(+), 45 deletions(-) diff --git a/apps/scouting/backend/src/fuel/calculations/fuel-averaging.ts b/apps/scouting/backend/src/fuel/calculations/fuel-averaging.ts index 28417a4..6ed8b87 100644 --- a/apps/scouting/backend/src/fuel/calculations/fuel-averaging.ts +++ b/apps/scouting/backend/src/fuel/calculations/fuel-averaging.ts @@ -1,10 +1,6 @@ // בס"ד -<<<<<<< HEAD:apps/scouting/backend/src/fuel/fuel-averaging.ts -import type { BPS, FuelObject, Match, ShootEvent } from "@repo/scouting_types"; -======= import type { Match, ShootEvent } from "@repo/scouting_types"; import type { BPS, FuelObject } from "../fuel-object"; ->>>>>>> origin/master:apps/scouting/backend/src/fuel/calculations/fuel-averaging.ts import { calculateSum, firstElement, lastElement } from "@repo/array-functions"; const EMPTY_INTERVAL_DURATION = 0; diff --git a/apps/scouting/backend/src/fuel/distance-split.ts b/apps/scouting/backend/src/fuel/distance-split.ts index 771f0ac..cab7edf 100644 --- a/apps/scouting/backend/src/fuel/distance-split.ts +++ b/apps/scouting/backend/src/fuel/distance-split.ts @@ -3,7 +3,7 @@ import { convertPixelToCentimeters, distanceFromHub } from "@repo/rebuilt_map"; import type { FuelEvents, FuelObject } from "./fuel-object"; import { calculateAverage } from "@repo/array-functions"; -const averageFuel = (fuels: FuelObject[]): FuelObject => { +export const averageFuel = (fuels: FuelObject[]): FuelObject => { const averageOfKey = (key: FuelEvents) => calculateAverage(fuels, (value) => value[key]); return { diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index e2a40f1..fdab6e2 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -9,14 +9,17 @@ import { mongofyQuery } from "../middleware/query"; import { generalCalculateFuel } from "../fuel/fuel-general"; import { StatusCodes } from "http-status-codes"; -import type { - BPS, - FuelObject, - GeneralFuelData, -} from "@repo/scouting_types"; +import type { BPS, FuelObject, GeneralFuelData } from "@repo/scouting_types"; +import { averageFuel } from "../fuel/distance-split"; export const generalRouter = Router(); +interface AccumulatedFuelData { + fullGame: FuelObject[]; + auto: FuelObject[]; + tele: FuelObject[]; +} + const EXAMPLE_BPS: BPS[] = [ { match: { @@ -36,49 +39,38 @@ const EXAMPLE_BPS: BPS[] = [ }, ]; -const DIVIDE_BY_TO_GET_AVERAGE = 2; const ONE_ITEM_ARRAY = 1; const EMPTY_ARRAY = 0; const FIRST_ARRAY_ITEM = 0; -const calcAverage = (num1: number, num2: number) => { - return (num1 + num2) / DIVIDE_BY_TO_GET_AVERAGE; -}; - -const calcAverageFuelObject = ( - firstData: FuelObject, - secondData: FuelObject, -) => { - const newData: FuelObject = { - scored: calcAverage(firstData.scored, secondData.scored), - shot: calcAverage(firstData.shot, secondData.shot), - missed: calcAverage(firstData.missed, secondData.missed), - positions: [...firstData.positions, ...secondData.positions], - }; - return newData; -}; - const calcAverageGeneralFuelData = (fuelData: GeneralFuelData[]) => { if (fuelData.length === ONE_ITEM_ARRAY || fuelData.length === EMPTY_ARRAY) { return fuelData[FIRST_ARRAY_ITEM]; } - return fuelData.reduce((accumulatedFuelData, currentFuelData) => { - const newFuelData: GeneralFuelData = { - fullGame: calcAverageFuelObject( - accumulatedFuelData.fullGame, - currentFuelData.fullGame, - ), - auto: calcAverageFuelObject( - accumulatedFuelData.auto, - currentFuelData.auto, - ), - tele: calcAverageFuelObject( - accumulatedFuelData.tele, - currentFuelData.tele, - ), - }; - return newFuelData; - }, fuelData[FIRST_ARRAY_ITEM]); + + const accumulatedFuelData: AccumulatedFuelData = + fuelData.reduce( + (accumulated, currentFuelData) => { + return { + fullGame: [...accumulated.fullGame, currentFuelData.fullGame], + auto: [...accumulated.auto, currentFuelData.auto], + tele: [...accumulated.tele, currentFuelData.tele], + }; + }, + { + fullGame: [], + auto: [], + tele: [], + }, + ); + + const averagedFuelData: GeneralFuelData = { + fullGame: averageFuel(accumulatedFuelData.fullGame), + auto: averageFuel(accumulatedFuelData.auto), + tele: averageFuel(accumulatedFuelData.tele), + }; + + return averagedFuelData; }; generalRouter.get("/", async (req, res) => { From b310c26ffcaf2b6647d4421c5b5cb8e1f5e03dc6 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:41:35 +0200 Subject: [PATCH 12/18] karni- changed how I accumulate the records idk --- .../backend/src/routes/general-router.ts | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index fdab6e2..f4e849f 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -9,8 +9,14 @@ import { mongofyQuery } from "../middleware/query"; import { generalCalculateFuel } from "../fuel/fuel-general"; import { StatusCodes } from "http-status-codes"; -import type { BPS, FuelObject, GeneralFuelData } from "@repo/scouting_types"; +import type { + BPS, + FuelObject, + GeneralFuelData, + TeamNumberAndFuelData, +} from "@repo/scouting_types"; import { averageFuel } from "../fuel/distance-split"; +import { firstElement, isEmpty } from "@repo/array-functions"; export const generalRouter = Router(); @@ -40,23 +46,19 @@ const EXAMPLE_BPS: BPS[] = [ ]; const ONE_ITEM_ARRAY = 1; -const EMPTY_ARRAY = 0; -const FIRST_ARRAY_ITEM = 0; const calcAverageGeneralFuelData = (fuelData: GeneralFuelData[]) => { - if (fuelData.length === ONE_ITEM_ARRAY || fuelData.length === EMPTY_ARRAY) { - return fuelData[FIRST_ARRAY_ITEM]; + if (fuelData.length === ONE_ITEM_ARRAY || isEmpty(fuelData)) { + return firstElement(fuelData); } const accumulatedFuelData: AccumulatedFuelData = fuelData.reduce( - (accumulated, currentFuelData) => { - return { - fullGame: [...accumulated.fullGame, currentFuelData.fullGame], - auto: [...accumulated.auto, currentFuelData.auto], - tele: [...accumulated.tele, currentFuelData.tele], - }; - }, + (accumulated, currentFuelData) => ({ + fullGame: [...accumulated.fullGame, currentFuelData.fullGame], + auto: [...accumulated.auto, currentFuelData.auto], + tele: [...accumulated.tele, currentFuelData.tele], + }), { fullGame: [], auto: [], @@ -90,15 +92,21 @@ generalRouter.get("/", async (req, res) => { ), map((generalFuelsData) => { - const teamAndAllFuelData: Record = - generalFuelsData.reduce((finalRecord, fuelData) => { - finalRecord[fuelData.teamNumber] - ? finalRecord[fuelData.teamNumber].push(fuelData.generalFuelData) - : (finalRecord[fuelData.teamNumber] = [fuelData.generalFuelData]); - - return finalRecord; - }, {}); + return generalFuelsData.reduce>( + (accumulatorRecord, fuelData) => { + return { + ...accumulatorRecord, + [fuelData.teamNumber]: [ + ...accumulatorRecord[fuelData.teamNumber], + fuelData.generalFuelData, + ], + }; + }, + {}, + ); + }), + map((teamAndAllFuelData) => { const teamAndAvaragedFuelData: Record = {}; Object.entries(teamAndAllFuelData).forEach(([teamNumber, fuelArray]) => { teamAndAvaragedFuelData[teamNumber] = From 15aba544aeb9a5e7f61c36283d13421c0a62907a Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:44:03 +0200 Subject: [PATCH 13/18] karni- added an index for fuel --- packages/scouting_types/index.ts | 2 +- packages/scouting_types/rebuilt/fuel/index.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 packages/scouting_types/rebuilt/fuel/index.ts diff --git a/packages/scouting_types/index.ts b/packages/scouting_types/index.ts index 587396e..416a698 100644 --- a/packages/scouting_types/index.ts +++ b/packages/scouting_types/index.ts @@ -1,6 +1,6 @@ // בס"ד export * from "./rebuilt/scouting_form"; -export * from "./rebuilt/fuel/FuelTypes"; +export * from "./rebuilt/fuel"; export * from "./tba"; diff --git a/packages/scouting_types/rebuilt/fuel/index.ts b/packages/scouting_types/rebuilt/fuel/index.ts new file mode 100644 index 0000000..b898a75 --- /dev/null +++ b/packages/scouting_types/rebuilt/fuel/index.ts @@ -0,0 +1,3 @@ +//בס"ד + +export * from "./FuelTypes"; From 5b1c65378a05fc88023a697a67249a4841864a35 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:46:03 +0200 Subject: [PATCH 14/18] karni- no return no no (Hara al return) --- .../scouter/components/GeneralDataTable.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx index 36693ab..1f31ac8 100644 --- a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx +++ b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx @@ -53,7 +53,8 @@ const DIGITS_AFTER_DOT = 1; export const GeneralDataTable: React.FC = ({ filters, }) => { - const [teamNumberAndFuelData, setTeamNumberAndFuelData] = useState({}); + const [teamNumberAndFuelData, setTeamNumberAndFuelData] = + useState({}); const [gameTime, setGameTime] = useState("tele"); const [sorting, setSorting] = useState([]); @@ -61,12 +62,16 @@ export const GeneralDataTable: React.FC = ({ fetchFuelData(filters).then(setTeamNumberAndFuelData).catch(console.error); }, [filters]); - const tableData = useMemo(() => { - return Object.entries(teamNumberAndFuelData).map(([teamNumber, generalFuelData]) => ({ - teamNumber: Number(teamNumber), - generalFuelData, - })); - }, [teamNumberAndFuelData]); + const tableData = useMemo( + () => + Object.entries(teamNumberAndFuelData).map( + ([teamNumber, generalFuelData]) => ({ + teamNumber: Number(teamNumber), + generalFuelData, + }), + ), + [teamNumberAndFuelData], + ); const columnHelper = createColumnHelper(); From 08be5c8badd891015b147561ff4d8579df4c81d6 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:46:44 +0200 Subject: [PATCH 15/18] karni- StatusCodes.INTERNAL_SERVER_ERROR --- apps/scouting/backend/src/routes/general-router.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index f4e849f..bec679f 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -81,7 +81,10 @@ generalRouter.get("/", async (req, res) => { flatMap((collection) => tryCatch( () => collection.find(mongofyQuery(req.query)).toArray(), - (error) => ({ status: 500, reason: `DB Error: ${error}` }), + (error) => ({ + status: StatusCodes.INTERNAL_SERVER_ERROR, + reason: `DB Error: ${error}`, + }), ), ), map((forms) => From e3bfaedb0d5940407a6ecd30e69f77af485b04f2 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Thu, 5 Feb 2026 20:11:43 +0200 Subject: [PATCH 16/18] karni- fixed final things --- .../backend/src/routes/general-router.ts | 24 +++++++++---------- .../scouter/components/GeneralDataTable.tsx | 10 ++++---- packages/scouting_types/index.ts | 3 +-- packages/scouting_types/rebuilt/index.ts | 4 ++++ 4 files changed, 22 insertions(+), 19 deletions(-) create mode 100644 packages/scouting_types/rebuilt/index.ts diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index bec679f..f14aa2b 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -94,20 +94,18 @@ generalRouter.get("/", async (req, res) => { })), ), - map((generalFuelsData) => { - return generalFuelsData.reduce>( - (accumulatorRecord, fuelData) => { - return { - ...accumulatorRecord, - [fuelData.teamNumber]: [ - ...accumulatorRecord[fuelData.teamNumber], - fuelData.generalFuelData, - ], - }; - }, + map((generalFuelsData) => + generalFuelsData.reduce>( + (accumulatorRecord, fuelData) => ({ + ...accumulatorRecord, + [fuelData.teamNumber]: [ + ...accumulatorRecord[fuelData.teamNumber], + fuelData.generalFuelData, + ], + }), {}, - ); - }), + ), + ), map((teamAndAllFuelData) => { const teamAndAvaragedFuelData: Record = {}; diff --git a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx index 1f31ac8..e4c816f 100644 --- a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx +++ b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx @@ -5,6 +5,7 @@ import { getCoreRowModel, getSortedRowModel, useReactTable, + type Header, type SortingState, } from "@tanstack/react-table"; import type { @@ -163,10 +164,11 @@ export const GeneralDataTable: React.FC = ({ header.getContext(), )} - {{ - asc: , - desc: , - }[header.column.getIsSorted() as string] ?? ( + {header.column.getIsSorted() === "asc" ? ( + + ) : header.column.getIsSorted() === "desc" ? ( + + ) : ( )} diff --git a/packages/scouting_types/index.ts b/packages/scouting_types/index.ts index 416a698..1926a23 100644 --- a/packages/scouting_types/index.ts +++ b/packages/scouting_types/index.ts @@ -1,6 +1,5 @@ // בס"ד -export * from "./rebuilt/scouting_form"; -export * from "./rebuilt/fuel"; +export * from "./rebuilt"; export * from "./tba"; diff --git a/packages/scouting_types/rebuilt/index.ts b/packages/scouting_types/rebuilt/index.ts new file mode 100644 index 0000000..37840ce --- /dev/null +++ b/packages/scouting_types/rebuilt/index.ts @@ -0,0 +1,4 @@ +//בס"ד + +export * from "./fuel" +export * from "./scouting_form" \ No newline at end of file From 2c0e0e8834ab553563d4677b10e68a6a9bbc3692 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Thu, 5 Feb 2026 20:14:58 +0200 Subject: [PATCH 17/18] karni- removed unused --- apps/scouting/backend/src/routes/general-router.ts | 1 - .../frontend/src/scouter/components/GeneralDataTable.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index f14aa2b..9d40cac 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -13,7 +13,6 @@ import type { BPS, FuelObject, GeneralFuelData, - TeamNumberAndFuelData, } from "@repo/scouting_types"; import { averageFuel } from "../fuel/distance-split"; import { firstElement, isEmpty } from "@repo/array-functions"; diff --git a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx index e4c816f..e1d5fd1 100644 --- a/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx +++ b/apps/scouting/frontend/src/scouter/components/GeneralDataTable.tsx @@ -5,7 +5,6 @@ import { getCoreRowModel, getSortedRowModel, useReactTable, - type Header, type SortingState, } from "@tanstack/react-table"; import type { From 2c8b5b9ec4c72c8a03dd60f377db053e77c08d11 Mon Sep 17 00:00:00 2001 From: karnishein <214869392+karnishein@users.noreply.github.com> Date: Thu, 5 Feb 2026 20:31:30 +0200 Subject: [PATCH 18/18] karni- something idk anymore --- apps/scouting/backend/src/game-object.ts | 2 -- .../backend/src/routes/general-router.ts | 29 ++++--------------- 2 files changed, 5 insertions(+), 26 deletions(-) delete mode 100644 apps/scouting/backend/src/game-object.ts diff --git a/apps/scouting/backend/src/game-object.ts b/apps/scouting/backend/src/game-object.ts deleted file mode 100644 index f3be8bb..0000000 --- a/apps/scouting/backend/src/game-object.ts +++ /dev/null @@ -1,2 +0,0 @@ -// בס"ד - diff --git a/apps/scouting/backend/src/routes/general-router.ts b/apps/scouting/backend/src/routes/general-router.ts index 9d40cac..8bfb4e6 100644 --- a/apps/scouting/backend/src/routes/general-router.ts +++ b/apps/scouting/backend/src/routes/general-router.ts @@ -9,11 +9,7 @@ import { mongofyQuery } from "../middleware/query"; import { generalCalculateFuel } from "../fuel/fuel-general"; import { StatusCodes } from "http-status-codes"; -import type { - BPS, - FuelObject, - GeneralFuelData, -} from "@repo/scouting_types"; +import type { BPS, FuelObject, GeneralFuelData } from "@repo/scouting_types"; import { averageFuel } from "../fuel/distance-split"; import { firstElement, isEmpty } from "@repo/array-functions"; @@ -25,24 +21,9 @@ interface AccumulatedFuelData { tele: FuelObject[]; } -const EXAMPLE_BPS: BPS[] = [ - { - match: { - number: 42, - type: "qualification", - }, - events: [ - { - shoot: [12, 45, 88, 110], - score: [12, 88], - }, - { - shoot: [135, 140], - score: [135, 140], - }, - ], - }, -]; +const getBPS = () => { + return []; +}; const ONE_ITEM_ARRAY = 1; @@ -89,7 +70,7 @@ generalRouter.get("/", async (req, res) => { map((forms) => forms.map((form) => ({ teamNumber: form.teamNumber, - generalFuelData: generalCalculateFuel(form, EXAMPLE_BPS), + generalFuelData: generalCalculateFuel(form, getBPS()), })), ),