Skip to content

Commit

Permalink
feat: implement averages table
Browse files Browse the repository at this point in the history
  • Loading branch information
thraizz committed Dec 14, 2023
1 parent 61e7e46 commit 563e7e4
Show file tree
Hide file tree
Showing 11 changed files with 12,081 additions and 82 deletions.
Binary file modified bun.lockb
Binary file not shown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"postcss": "^8.4.32",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.49.2"
"react-hook-form": "^7.49.2",
"vitest": "^1.0.4"
},
"devDependencies": {
"@types/react": "^18.2.43",
Expand Down
205 changes: 171 additions & 34 deletions src/AveragesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,187 @@
import { Disclosure } from "@headlessui/react";
import { ChevronUpIcon } from "@heroicons/react/20/solid";
import { ColDef } from "ag-grid-community";
import { AgGridReact } from "ag-grid-react";
import { useContext } from "react";
import { Label } from "./Label";
import { SessionContext } from "./SessionContext";
import { AveragedSwing, calculateAverages } from "./calculateAverages";

export const AveragesTable = () => {
const { sessions } = useContext(SessionContext);

// {
// "Abflugrichtung": 1.926966573132409,
// "Abflugwinkel": 15.135783533917532,
// "Anstellwinkel": -1.1857004306382604,
// "Backspin": 4621.155019802517,
// "Ballgeschwindigkeit": 134.76729867597945,
// "Carry-Abweichungsdistanz": -0.16316428648100958,
// "Carry-Abweichungswinkel": 1.0715296745300293,
// "Carry-Distanz": 82.54763145446778,
// "Drehachse": -2.0749586704704495,
// "Drehrate": 4693.218630642361,
// "Gesamtabweichungsdistanz": 0.2135619772805108,
// "Gesamtabweichungswinkel": 0.9892588668399387,
// "Gesamtstrecke": 97.3018485599094,
// "Höhe des Scheitelpunkts": 10.057312718696064,
// "Luftdichte": 1.2390065688888887,
// "Luftdruck": 100.30643711111111,
// "Relative Luftfeuchtigkeit": 81.57777777777778,
// "Schl.gsch.": 117.50878274523454,
// "Schlagfläche": 1.2794463779156406,
// "Schlagflächenstellung": 1.850954035255644,
// "Schwungbahn": 0.18552126677499878,
// "Sidespin": 227.9454793718126,
// "Smash Factor": 1.146739124703454,
// "Temperatur": 7.962963055555558,
// "count": 45,
// "name": "Eisen 7",
// }
// Column Definitions: Defines & controls grid columns.
const columnDefs = [
{ field: "Schlägerart" },
{ field: "Carry-Distanz" },
{ field: "Abflugrichtung" },
{ field: "Backspin" },
{ field: "Ballgeschwindigkeit" },
{ field: "Carry-Abweichungsdistanz" },
{ field: "Carry-Abweichungswinkel" },
{ field: "Abflugwinkel" },
{ field: "Anstellwinkel" },
{ field: "Sidespin" },
{ field: "Gesamtabweichungsdistanz" },
{ field: "Gesamtabweichungswinkel" },
{ field: "Gesamtstrecke" },
const columnDefs: ColDef<AveragedSwing>[] = [
{ field: "name", headerName: "Club", sortable: true, filter: true },
{ field: "count", headerName: "Count", sortable: true, filter: true },
{
field: "Ballgeschwindigkeit",
headerName: "Ball Speed",
sortable: true,
filter: true,
},
{
field: "Carry-Distanz",
headerName: "Carry Distance",
sortable: true,
filter: true,
},
{
field: "Carry-Abweichungsdistanz",
headerName: "Carry Distance Deviation",
sortable: true,
filter: true,
},
{
field: "Carry-Abweichungswinkel",
headerName: "Carry Angle Deviation",
sortable: true,
filter: true,
},
{
field: "Gesamtstrecke",
headerName: "Total Distance",
sortable: true,
filter: true,
},
{
field: "Gesamtabweichungsdistanz",
headerName: "Total Distance Deviation",
sortable: true,
filter: true,
},
{
field: "Gesamtabweichungswinkel",
headerName: "Total Angle Deviation",
sortable: true,
filter: true,
},
{
field: "Abflugrichtung",
headerName: "Launch Direction",
sortable: true,
filter: true,
},
{
field: "Abflugwinkel",
headerName: "Launch Angle",
sortable: true,
filter: true,
},
{
field: "Anstellwinkel",
headerName: "Attack Angle",
sortable: true,
filter: true,
},
{ field: "Backspin", headerName: "Backspin", sortable: true, filter: true },
{
field: "Drehachse",
headerName: "Spin Axis",
sortable: true,
filter: true,
},
{
field: "Drehrate",
headerName: "Spin Rate",
sortable: true,
filter: true,
},
{
field: "Höhe des Scheitelpunkts",
headerName: "Apex Height",
sortable: true,
filter: true,
},
{
field: "Luftdichte",
headerName: "Air Density",
sortable: true,
filter: true,
},
{
field: "Luftdruck",
headerName: "Air Pressure",
sortable: true,
filter: true,
},
{
field: "Relative Luftfeuchtigkeit",
headerName: "Humidity",
sortable: true,
filter: true,
},
{
field: "Schlagfläche",
headerName: "Face Angle",
sortable: true,
filter: true,
},
{
field: "Schlagflächenstellung",
headerName: "Face to Path",
sortable: true,
filter: true,
},
{
field: "Schwungbahn",
headerName: "Swing Path",
sortable: true,
filter: true,
},
{ field: "Sidespin", headerName: "Sidespin", sortable: true, filter: true },
{
field: "Smash Factor",
headerName: "Smash Factor",
sortable: true,
filter: true,
},
{
field: "Temperatur",
headerName: "Temperature",
sortable: true,
filter: true,
},
];

// Calculate averages for each column on all sessions
const dataAverages = columnDefs.map((columnDef) => {
if (sessions) {
const { field } = columnDef;
const values = Object.values(sessions).map((session) => {
return session?.results.map(
(result: { [x: string]: string }) => result[field],
);
});
const average =
values.flat().reduce((a, b) => a + b, 0) / values.flat().length;
return { [field]: average };
}
});
if (!sessions) {
return (
<p className="text-md text-sky-900">
Select a session to display data here.
</p>
);
}

return sessions ? (
const averages = calculateAverages(sessions);
return (
<Disclosure defaultOpen={true} as="div" className="mt-2">
{({ open }) => (
<>
Expand All @@ -57,15 +198,11 @@ export const AveragesTable = () => {
<Label className="px-4">
Averages for all sessions selected in the Session Picker.
</Label>
<AgGridReact rowData={dataAverages} columnDefs={columnDefs} />
<AgGridReact rowData={averages} columnDefs={columnDefs} />
</div>
</Disclosure.Panel>
</>
)}
</Disclosure>
) : (
<p className="text-md text-sky-900">
Select a session to display data here.
</p>
);
};
28 changes: 13 additions & 15 deletions src/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { Disclosure } from "@headlessui/react";
import { ChevronUpIcon } from "@heroicons/react/20/solid";
import { ColDef } from "ag-grid-community";
import "ag-grid-community/styles/ag-grid.css"; // Core CSS
import "ag-grid-community/styles/ag-theme-quartz.css"; // Theme
import { AgGridReact } from "ag-grid-react/lib/agGridReact";
import { useContext, useState } from "react";
import { SessionContext } from "./SessionContext";
import { useContext } from "react";
import { GolfSwingData, SessionContext } from "./SessionContext";

export const DataTable = () => {
const { sessions } = useContext(SessionContext);

// Column Definitions: Defines & controls grid columns.
const [columnDefs] = useState([
const columnDefs: ColDef<GolfSwingData>[] = [
{ field: "Spieler" },
{ field: "Schlägerart" },
{ field: "Carry-Distanz" },
Expand Down Expand Up @@ -42,27 +43,24 @@ export const DataTable = () => {
// { field: "Schwungbahn" },
// { field: "Smash Factor" },
// { field: "Temperatur" },
]);
];

// Get the session where selected is true
const jsonFileWithoutEmptyRows = sessions
? (Object.values(sessions)
? Object.values(sessions)
.filter((session) => session.selected)
?.reduce(
(acc, curr) => {
if (curr.results.length > 0) {
acc.push(...curr.results);
}
return acc;
},
[] as Array<Record<string, string>>,
) as Array<Record<string, string>>)
?.reduce((acc, curr) => {
if (curr.results.length > 0) {
acc.push(...curr.results);
}
return acc;
}, [] as GolfSwingData[])
: [];

return (
<div>
{jsonFileWithoutEmptyRows ? (
<Disclosure defaultOpen={true} as="div" className="mt-2">
<Disclosure defaultOpen={false} as="div" className="mt-2">
{({ open }) => (
<>
<Disclosure.Button className="flex w-full justify-between rounded-lg bg-sky-100 px-4 py-2 text-left text-sm font-medium text-sky-900 hover:bg-sky-200 focus:outline-none focus-visible:ring focus-visible:ring-sky-500/75">
Expand Down
48 changes: 43 additions & 5 deletions src/SessionContext.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,54 @@
import { DocumentData } from "firebase/firestore";
import React, {
PropsWithChildren,
createContext,
useMemo,
useState,
} from "react";

export type SessionType = Record<string, DocumentData> | null;
export type GolfSwingData = {
Schlagflächenstellung: null | number | undefined;
Luftdruck: number | null | undefined;
Schlagfläche: null | number;
Datum: string | null;
Temperatur: number | null;
Markierung: null | string;
Luftdichte: number | null;
Schwungbahn: null | number;
Drehrate: number | null;
"Smash Factor": number | null;
Drehratentyp: string | null;
Ballgeschwindigkeit: number | null;
Gesamtabweichungswinkel: number | null;
"Höhe des Scheitelpunkts": number | null;
Gesamtabweichungsdistanz: number | null;
Drehachse: number | null;
"Carry-Abweichungsdistanz": number | null;
Abflugrichtung: number | null;
Backspin: number | null;
Schlägername: null | string;
"Carry-Abweichungswinkel": number | null;
Sidespin: number | null;
Gesamtstrecke: number | null;
Spieler: string | null;
Abflugwinkel: number | null;
"Relative Luftfeuchtigkeit": number | null;
"Schl.gsch.": number | null;
Notiz: null | string;
Schlägerart: string | null;
Anstellwinkel: null | number;
"Carry-Distanz": number | null;
};

export type Sessions = {
[key: string]: {
results: GolfSwingData[];
selected: boolean;
};
};

export interface SessionContextInterface {
sessions: SessionType;
setSession: (sessions: SessionType) => void;
sessions: Sessions | null;
setSession: (sessions: Sessions) => void;
}

const SessionContext = createContext<SessionContextInterface>({
Expand All @@ -19,7 +57,7 @@ const SessionContext = createContext<SessionContextInterface>({
});

const SessionProvider: React.FC<PropsWithChildren> = ({ children }) => {
const [sessions, setSession] = useState<SessionType>(null);
const [sessions, setSession] = useState<Sessions | null>(null);
const memoizedValue = useMemo(
() => ({
sessions,
Expand Down
Loading

0 comments on commit 563e7e4

Please sign in to comment.