Skip to content

Commit

Permalink
vinvoor: show a scan overview
Browse files Browse the repository at this point in the history
  • Loading branch information
Topvennie committed Jul 17, 2024
1 parent 21cf2e5 commit 9a208e3
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 9 deletions.
4 changes: 2 additions & 2 deletions vinvoor/src/cards/CardsTableBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import { useConfirm } from "material-ui-confirm";
import { useSnackbar } from "notistack";
import { ChangeEvent, FC, MouseEvent, useContext } from "react";
import { Card, CardsHeadCells, convertCardJSON } from "../types/cards";
import { Card, cardsHeadCells, convertCardJSON } from "../types/cards";
import { getApi, patchApi } from "../util/fetch";
import { CardContext } from "./Cards";

Expand Down Expand Up @@ -95,7 +95,7 @@ export const CardsTableBody: FC<CardsTableBodyProps> = ({
>
<Checkbox checked={isSelected} />
</TableCell>
{CardsHeadCells.map((headCell) => (
{cardsHeadCells.map((headCell) => (
<TableCell
key={headCell.id}
align={headCell.align}
Expand Down
4 changes: 2 additions & 2 deletions vinvoor/src/cards/CardsTableHead.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Typography,
} from "@mui/material";
import { ChangeEvent, FC, MouseEvent } from "react";
import { Card, CardsHeadCells } from "../types/cards";
import { Card, cardsHeadCells } from "../types/cards";
import { TableOrder } from "../types/general";

interface CardTableHeadProps {
Expand Down Expand Up @@ -46,7 +46,7 @@ export const CardsTableHead: FC<CardTableHeadProps> = ({
onChange={onSelectAllClick}
/>
</TableCell>
{CardsHeadCells.map((headCell) => (
{cardsHeadCells.map((headCell) => (
<TableCell
key={headCell.id}
align={headCell.align}
Expand Down
5 changes: 5 additions & 0 deletions vinvoor/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { App } from "./App.tsx";
import { Cards } from "./cards/Cards.tsx";
import { ErrorPage } from "./errors/ErrorPage.tsx";
import { Leaderboard } from "./leaderboard/Leaderboard.tsx";
import { Scans } from "./scans/Scans.tsx";
import { ThemeProvider } from "./theme/ThemeProvider";
import { Login } from "./user/Login.tsx";
import { Logout } from "./user/Logout.tsx";
Expand All @@ -32,6 +33,10 @@ const router = createBrowserRouter([
path: "logout",
element: <Logout />,
},
{
path: "scans",
element: <Scans />,
},
{
path: "cards",
element: <Cards />,
Expand Down
6 changes: 5 additions & 1 deletion vinvoor/src/navbar/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import LeaderboardIcon from "@mui/icons-material/Leaderboard";
import { AppBar, Box, Container, Toolbar } from "@mui/material";
import { CreditCardMultipleOutline } from "mdi-material-ui";
import {
CreditCardMultipleOutline,
CreditCardScanOutline,
} from "mdi-material-ui";
import { useContext } from "react";
import { DarkModeToggle } from "../components/DarkModeToggle";
import { UserContext } from "../user/UserProvider";
Expand All @@ -15,6 +18,7 @@ export interface PageIcon {
}

const navBarPages: PageIcon[] = [
{ page: "Scans", icon: <CreditCardScanOutline sx={{ mr: ".3rem" }} /> },
{ page: "Cards", icon: <CreditCardMultipleOutline sx={{ mr: ".3rem" }} /> },
{ page: "Leaderboard", icon: <LeaderboardIcon sx={{ mr: ".3rem" }} /> },
];
Expand Down
36 changes: 36 additions & 0 deletions vinvoor/src/scans/Scans.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Paper, Table, TableContainer } from "@mui/material";
import { useState } from "react";
import { LoadingSkeleton } from "../components/LoadingSkeleton";
import { useFetch } from "../hooks/useFetch";
import { Card, convertCardJSON } from "../types/cards";
import { convertScanJSON, Scan } from "../types/scans";
import { ScansTableBody } from "./ScansBody";
import { ScansTableHead } from "./ScansTableHead";

export const Scans = () => {
const [scans, setScans] = useState<readonly Scan[]>([]);
const [cards, setCards] = useState<readonly Card[]>([]);
const { loading: loadingScans } = useFetch<readonly Scan[]>(
"scans",
setScans,
convertScanJSON
);
const { loading: loadingCards } = useFetch<readonly Card[]>(
"cards",
setCards,
convertCardJSON
);

return (
<LoadingSkeleton loading={loadingScans && loadingCards}>
<Paper elevation={4}>
<TableContainer>
<Table>
<ScansTableHead />
<ScansTableBody scans={scans} cards={cards} />
</Table>
</TableContainer>
</Paper>
</LoadingSkeleton>
);
};
44 changes: 44 additions & 0 deletions vinvoor/src/scans/ScansBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { TableBody, TableCell, Typography } from "@mui/material";
import { TableRow } from "mdi-material-ui";
import { FC, useEffect, useState } from "react";
import { Card } from "../types/cards";
import {
mergeScansCards,
Scan,
ScanCard,
scanCardHeadCells,
} from "../types/scans";

interface ScansTableBodyProps {
scans: readonly Scan[];
cards: readonly Card[];
}

export const ScansTableBody: FC<ScansTableBodyProps> = ({ scans, cards }) => {
const [scanCards, setScanCards] = useState<readonly ScanCard[]>([]);

useEffect(() => {
setScanCards(mergeScansCards(scans, cards));
}, [scans, cards]);

return (
<TableBody>
{scanCards.map((scanCard) => (
<TableRow key={scanCard.scanTime.toString()}>
{scanCardHeadCells.map((headCell) => (
<TableCell
key={headCell.id}
align={headCell.align}
padding={headCell.padding}
>
<Typography>
{headCell.convert &&
headCell.convert(scanCard[headCell.id])}
</Typography>
</TableCell>
))}
</TableRow>
))}
</TableBody>
);
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { TableCell, TableHead, TableRow, Typography } from "@mui/material";
import { leaderboardHeadCells } from "../types/leaderboard";
import { scanCardHeadCells } from "../types/scans";

export const LeaderboardTableHead = () => {
export const ScansTableHead = () => {
return (
<TableHead>
<TableRow>
{leaderboardHeadCells.map((headCell) => (
{scanCardHeadCells.map((headCell) => (
<TableCell key={headCell.id} align={headCell.align}>
<Typography>{headCell.label}</Typography>
</TableCell>
Expand Down
2 changes: 1 addition & 1 deletion vinvoor/src/types/cards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const convertCardJSON = (cardsJSON: CardJSON[]): Card[] =>
createdAt: new Date(CardJSON.createdAt),
}));

export const CardsHeadCells: readonly TableHeadCell<Card>[] = [
export const cardsHeadCells: readonly TableHeadCell<Card>[] = [
{
id: "name",
label: "Name",
Expand Down
35 changes: 35 additions & 0 deletions vinvoor/src/types/scans.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { Card } from "./cards";
import { TableHeadCell } from "./general";

interface ScanJSON {
scanTime: string;
card: string;
Expand All @@ -8,10 +11,42 @@ export interface Scan {
card: string;
}

export interface ScanCard {
scanTime: Date;
card?: Card;
}

export const convertScanJSON = (scansJSON: ScanJSON[]): Scan[] =>
scansJSON
.map((scanJSON) => ({
scanTime: new Date(scanJSON.scanTime),
card: scanJSON.card,
}))
.sort((a, b) => a.scanTime.getTime() - b.scanTime.getTime());

export const mergeScansCards = (
scans: readonly Scan[],
cards: readonly Card[]
): readonly ScanCard[] =>
scans.map((scan) => ({
scanTime: scan.scanTime,
card: cards.find((card) => card.serial === scan.card),
}));

export const scanCardHeadCells: readonly TableHeadCell<ScanCard>[] = [
{
id: "card",
label: "Card",
align: "left",
padding: "normal",
convert: (value: Card | undefined) =>
value?.name ?? value?.serial ?? "Unknown",
},
{
id: "scanTime",
label: "Scan time",
align: "right",
padding: "normal",
convert: (value: Date) => value.toDateString(),
},
];

0 comments on commit 9a208e3

Please sign in to comment.