Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/scouting/frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { ScoutMatch } from "./scouter/pages/ScoutMatch";
import { Route, Routes } from "react-router-dom";
import { ScoutedMatches } from "./scouter/pages/ScoutedMatches";
import { TeamTab } from "./strategy/components/TeamTab";
import { MatchForecast } from "./strategy/components/forecast/MatchForecast";
import { GeneralDataTable } from "./strategy/GeneralDataTable";
import { CompareTwo } from "./strategy/CompareTwo";

const App: FC = () => {
return (
<Routes>
<Route path="*" element={<ScoutedMatches />} />
<Route path="/scout" element={<ScoutMatch />} />
<Route path="/team" element={<TeamTab />} />
<Route path="/general" element={<GeneralDataTable filters={{}} />} />
<Route path="*" element={<ScoutedMatches />} />
<Route path="/forecast" element={<MatchForecast />} />
<Route path="/compare" element={<CompareTwo />} />
</Routes>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// בס"ד

import type { FC } from "react";

interface CenterStatProps {
label: string;
red: number;
blue: number;
}

const DECIMAL_DIGIT_AMOUNT = 0;

export const CenterStat: FC<CenterStatProps> = ({
label,
red,
blue,
}) => (
<div className="grid grid-cols-[1fr_auto_1fr] items-center gap-4">
{/* Red Value */}
<div className="text-right">
<span className="text-lg font-bold text-red-400 tabular-nums">
{red.toFixed(DECIMAL_DIGIT_AMOUNT)}
</span>
</div>

{/* Center Label Pill */}
<div className="w-24 py-1 bg-slate-900/60 border border-white/5 rounded-lg text-center shadow-inner">
<span className="font-bold text-slate-300/90 tracking-tight">
{label}
</span>
</div>

{/* Blue Value */}
<div className="text-left">
<span className="text-lg font-bold text-blue-400 tabular-nums">
{blue.toFixed(DECIMAL_DIGIT_AMOUNT)}
</span>
</div>
</div>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// בס"ד
import { useEffect, useState, type FC } from "react";
import type { Forecast } from "@repo/scouting_types";
import { CenterStat } from "./CenterStat";
import { StatRow } from "./StatRow";

interface Alliances {
redAlliance: [number, number, number];
blueAlliance: [number, number, number];
}

const querifyAlliances = (alliances: Alliances) => {
const params = new URLSearchParams();
alliances.redAlliance.forEach((team) => {
params.append("redAlliance", team.toString());
});
alliances.blueAlliance.forEach((team) => {
params.append("blueAlliance", team.toString());
});
return params;
};

export const MatchForecast: FC = () => {
const [forecast, setForecast] = useState<Forecast>();
const [alliances, _setAlliances] = useState<Alliances | undefined>();

const updateForecast = async () => {
if (!alliances) {
return;
}

const query = querifyAlliances(alliances);
try {
const response = await fetch(`/api/v1/forecast?${query.toString()}`);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Bad Response: ${errorText}`);
}
const fetchedForecast: Forecast = await response.json();
setForecast(fetchedForecast);
} catch (error: unknown) {
alert(error);
}
};
useEffect(() => {
void updateForecast();
}, [alliances]);

const redData = forecast?.allianceData.redAlliance;
const blueData = forecast?.allianceData.blueAlliance;

return (
<div className="w-full max-w-4xl mx-auto space-y-4 p-4">
<div className="flex justify-between items-center px-6 py-4 bg-slate-900/60 backdrop-blur-md border border-white/10 rounded-3xl shadow-xl">
<div className="text-center">
<span className="text-red-500 font-black text-2xl tracking-tighter uppercase">
{alliances?.redAlliance.join(", ")}
</span>
</div>
<div className="flex flex-col items-center">
<div className="bg-white/10 px-4 py-1 rounded-full text-xs font-bold text-slate-400 uppercase tracking-widest">
Prediction
</div>
<span className="text-slate-100 font-black text-3xl">VS</span>
</div>
<div className="text-center">
<span className="text-blue-500 font-black text-2xl tracking-tighter uppercase">
{alliances?.blueAlliance.join(", ")}
</span>
</div>
</div>

{/* Stats Grid */}
{redData && blueData && (
<div className="grid grid-cols-1 gap-4">
{/* Fuel Section */}
<StatRow red={redData.fuel.fullGame} blue={blueData.fuel.fullGame} />

{/* Detailed Breakdown */}
<div className="bg-slate-900/60 border border-white/10 rounded-3xl p-6 space-y-4">
<div className="flex items-center justify-center gap-4 mb-2">
<div className="h-px flex-1 bg-linear-to-r from-transparent to-red-500/40" />
<h4 className="text-slate-500 text-[10px] font-black uppercase tracking-[0.2em]">
Details
</h4>
<div className="h-px flex-1 bg-linear-to-l from-transparent to-blue-500/40" />
</div>

<div className="space-y-4">
<div className="flex items-center gap-4 py-2">
<div className="h-px flex-1 bg-slate-800" />
<div
className={`px-4 py-1 rounded-full border font-black uppercase tracking-[0.15em]`}
>
Auto
</div>
<div className="h-px flex-1 bg-slate-800" />
</div>
<CenterStat
label="Fuel"
red={redData.fuel.auto}
blue={blueData.fuel.auto}
/>
<CenterStat
label="Climb"
red={redData.climb.auto}
blue={blueData.climb.auto}
/>

<div className="flex items-center gap-4 py-2">
<div className="h-px flex-1 bg-slate-800" />
<div
className={`px-4 py-1 rounded-full border font-black uppercase tracking-[0.15em]`}
>
Tele
</div>
<div className="h-px flex-1 bg-slate-800" />
</div>

<CenterStat
label="Fuel"
red={redData.fuel.tele}
blue={blueData.fuel.tele}
/>
<CenterStat
label="Climb"
red={redData.climb.tele}
blue={blueData.climb.tele}
/>
</div>
</div>
</div>
)}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// בס"ד

import type { FC } from "react";

interface StatRowProps {
red: number;
blue: number;
}

export const StatRow: FC<StatRowProps> = ({ red, blue }) => {
const isRedLeading = red > blue;
return (
<div className="bg-slate-900/60 backdrop-blur-md border border-white/10 rounded-3xl p-6 relative overflow-hidden">
<div className="flex justify-between items-center relative z-10">
<div
className={`font-black text-red-500 ${isRedLeading ? "text-3xl" : "text-2xl"}`}
>
{red}
</div>
<div
className={`font-black text-3xl ${isRedLeading ? "text-red-500" : "text-blue-500"}`}
>
{`${isRedLeading ? "Red" : "Blue"} Wins`}
</div>
<div
className={`font-black text-blue-500 ${!isRedLeading ? "text-3xl" : "text-2xl"}`}
>
{blue}
</div>
</div>
</div>
);
};
Loading