Skip to content

Commit

Permalink
Revert "Merge branch 'main' into whoopies"
Browse files Browse the repository at this point in the history
This reverts commit f03868e, reversing
changes made to fd70c4d.
  • Loading branch information
koro committed Sep 27, 2024
1 parent f03868e commit e9b0df9
Show file tree
Hide file tree
Showing 40 changed files with 4,777 additions and 26 deletions.
46 changes: 46 additions & 0 deletions client/src/apps/admin/AdminApp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { MaterialSymbol } from 'react-material-symbols';
import LinkButton from '../../components/LinkButton';
import { useStatusRecieve } from '../../lib/useStatus';
import { ScouterTable } from './components/ScouterTable';
import { MatchTable } from './components/MatchTable';
//import { useFetchJson } from "../../lib/useFetch";

function AdminApp() {
const status = useStatusRecieve();

// const [schedule] = useFetchJson<MatchSchedule>('/matchSchedule.json');

return (
<main className='flex h-screen w-screen select-none flex-col items-center text-center'>
<h1 className='col-span-4 my-8 text-3xl'>Admin Interface</h1>

<div className='fixed left-4 top-4 z-20 flex gap-2 rounded-md p-2'>
<LinkButton link='/' className='snap-none'>
<MaterialSymbol
icon='home'
size={60}
fill
grade={200}
color='green'
className='snap-none'
/>
</LinkButton>
</div>

<div className='grid grid-cols-2 items-center justify-center gap-4'>
<div>
<ScouterTable scouters={status.scouters} />
<p className='my-6'>Connected Tablets</p>
</div>
<div>
<p>Match Display</p>
<div className='table-container'>
<MatchTable matches={status.matches}></MatchTable>
</div>
</div>
</div>
</main>
);
}

export default AdminApp;
27 changes: 27 additions & 0 deletions client/src/apps/admin/components/MatchRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { RobotPosition, SuperPosition } from 'requests';
import PositionCell from './PositionCell';

function MatchRow({
matchNumber,
scouters,
}: {
matchNumber: string;
scouters: Record<RobotPosition, { schedule: number; real: number[] }> &
Record<SuperPosition, boolean>;
}) {
return (
<tr>
<th>{matchNumber}</th>
<PositionCell scouter={scouters.red_1} />
<PositionCell scouter={scouters.red_2} />
<PositionCell scouter={scouters.red_3} />
<PositionCell scouter={scouters.red_ss} />
<PositionCell scouter={scouters.blue_1} />
<PositionCell scouter={scouters.blue_2} />
<PositionCell scouter={scouters.blue_3} />
<PositionCell scouter={scouters.blue_ss} />
</tr>
);
}

export default MatchRow;
29 changes: 29 additions & 0 deletions client/src/apps/admin/components/MatchTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { StatusRecieve } from 'requests';
import MatchRow from './MatchRow';

function MatchTable({ matches }: { matches: StatusRecieve['matches'] }) {
return (
<table className='match-status h-72 overflow-auto'>
<thead>
<tr>
<th>Match</th>
<th className='status-red col-span-1'>Red 1</th>
<th className='status-red col-span-1'>Red 2</th>
<th className='status-red col-span-1'>Red 3</th>
<th className='status-red col-span-1'>Red SS</th>
<th className='status-blue col-span-1'>Blue 1</th>
<th className='status-blue col-span-1'>Blue 2</th>
<th className='status-blue col-span-1'>Blue 3</th>
<th className='status-blue col-span-1'>Blue SS</th>
</tr>
</thead>
<tbody>
{Object.entries(matches).map(([matchNumber, scouters]) => (
<MatchRow matchNumber={matchNumber} scouters={scouters} />
))}
</tbody>
</table>
);
}

export { MatchTable };
24 changes: 24 additions & 0 deletions client/src/apps/admin/components/PositionCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { MaterialSymbol } from 'react-material-symbols';

function PositionCell({
scouter,
}: {
scouter: { schedule: number; real: number[] } | boolean;
}) {
const isBoolean = typeof scouter === 'boolean';
return (
<td
className={`w-auto border-2 border-slate-700 text-center ${(isBoolean ? scouter : scouter.real.length > 0) ? 'bg-amber-400' : ''}`}>
{isBoolean ? (
scouter && <MaterialSymbol icon='check' />
) : scouter.real.length === 0 ? (
scouter.schedule
) : scouter.real.length === 1 ? (
scouter.real[0]
) : (
<MaterialSymbol icon='warning' />
)}
</td>
);
}
export default PositionCell;
60 changes: 60 additions & 0 deletions client/src/apps/admin/components/ScouterCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { MaterialSymbol } from 'react-material-symbols';
import { StatusReport } from 'requests';

function BatteryLevelIcon(batteryLevel: number) {
if (batteryLevel > 75) {
return <MaterialSymbol icon='battery_full' className='mb-4 mr-3' />;
} else if (batteryLevel > 50) {
return <MaterialSymbol icon='battery_3_bar' className='mb-4 mr-3' />;
} else if (batteryLevel > 25) {
return <MaterialSymbol icon='battery_1_bar' className='mb-4 mr-3' />;
} else {
return <MaterialSymbol icon='battery_alert' className='mb-4 mr-3' />;
}
}
function ScouterCard({
scouter,
title,
red = false,
}: {
scouter: StatusReport[];
title: string;
red?: boolean;
}) {
return (
<div
className={`${red ? 'border-red-900 bg-red-500' : 'border-blue-900 bg-blue-500'} content-center items-center rounded-md border-2 px-4 text-center text-lg text-white`}>
<div className='mb-2 mt-4 font-semibold'>{title}</div>
{scouter.length === 0 ? (
<MaterialSymbol icon='wifi_off' size={32} />
) : scouter.length === 1 ? (
<>
<div className=''>{scouter[0].matchNumber}</div>
<div>{scouter[0].scouterName}</div>
<div>
{BatteryLevelIcon(
Math.floor((scouter[0].battery ?? 0) * 100)
)}
{Math.floor((scouter[0].battery ?? 0) * 100)}%
</div>
</>
) : (
<>
<div>
{' '}
<MaterialSymbol
icon='warning'
size={32}
className='text-yellow-300'
/>
</div>
{scouter.map(e => (
<div>{e.scouterName}</div>
))}
</>
)}
</div>
);
}

export { ScouterCard };
37 changes: 37 additions & 0 deletions client/src/apps/admin/components/ScouterTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { RobotPosition, StatusReport, SuperPosition } from 'requests';
import { ScouterCard } from './ScouterCard';

function ScouterTable({ scouters }: { scouters: StatusReport[] }) {
const sortedScouter = Object.fromEntries(
(
[
'red_1',
'red_2',
'red_3',
'blue_1',
'blue_2',
'blue_3',
'red_ss',
'blue_ss',
] satisfies (RobotPosition | SuperPosition)[]
).map(robotPosition => [
robotPosition,
scouters.filter(scouter => scouter.robotPosition === robotPosition),
])
) as Record<RobotPosition | SuperPosition, StatusReport[]>;

return (
<div className='grid grid-cols-4 gap-2'>
<ScouterCard scouter={sortedScouter.red_1} title='Red 1' red />
<ScouterCard scouter={sortedScouter.red_2} title='Red 2' red />
<ScouterCard scouter={sortedScouter.red_3} title='Red 3' red />
<ScouterCard scouter={sortedScouter.red_ss} title='Red SS' red />
<ScouterCard scouter={sortedScouter.blue_1} title='Blue 1' />
<ScouterCard scouter={sortedScouter.blue_2} title='Blue 2' />
<ScouterCard scouter={sortedScouter.blue_3} title='Blue 3' />
<ScouterCard scouter={sortedScouter.blue_ss} title='Blue SS' />
</div>
);
}

export { ScouterTable };
Loading

0 comments on commit e9b0df9

Please sign in to comment.