Skip to content

Commit

Permalink
fetch user less often
Browse files Browse the repository at this point in the history
  • Loading branch information
squi-ddy committed Oct 24, 2024
1 parent 7641d20 commit 468d2e9
Show file tree
Hide file tree
Showing 17 changed files with 247 additions and 169 deletions.
Binary file modified backend/bun.lockb
Binary file not shown.
2 changes: 0 additions & 2 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/express-session": "^1.18.0",
"@types/objects-to-csv": "^1.3.3",
"@types/passport-azure-ad": "^4.3.6",
"@types/passport-local": "^1.0.38",
"eslint": "^9.12.0",
Expand All @@ -39,7 +38,6 @@
"express": "^4.21.1",
"express-session": "^1.18.1",
"helmet": "^7.2.0",
"objects-to-csv": "^1.3.6",
"passport": "^0.7.0",
"passport-azure-ad": "^4.3.5",
"passport-local": "^1.0.0",
Expand Down
9 changes: 5 additions & 4 deletions backend/src/api/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { TransactionTable } from "types/transaction"
import { UserTable, UserType } from "types/user"
import Archiver from "archiver"
import ObjectsToCsv from "objects-to-csv"
import { objectsToCsv } from "utils"

const router = Router()
router.use((req, res, next) => {
Expand Down Expand Up @@ -110,7 +111,7 @@ router.post("/addMoney", async (req, res) => {
})
})

router.get("/dump", async (req, res) => {
router.get("/dump", async (_, res) => {
const topups = await sql<TopupTable[]>`
SELECT * FROM Topup
`
Expand All @@ -130,13 +131,13 @@ router.get("/dump", async (req, res) => {
archive.pipe(res)

await archive
.append(await new ObjectsToCsv(topups).toString(true, true), {
.append(objectsToCsv(topups), {
name: "topups.csv",
})
.append(await new ObjectsToCsv(transactions).toString(true, true), {
.append(objectsToCsv(transactions), {
name: "transactions.csv",
})
.append(await new ObjectsToCsv(users).toString(true, true), {
.append(objectsToCsv(users), {
name: "users.csv",
})
.finalize()
Expand Down
2 changes: 1 addition & 1 deletion backend/src/types/topup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface TopupTable {
export type TopupTable = {
topup_id: string // CHAR(36)
student_uid: string // CHAR(36),
student_name: string // VARCHAR(255),
Expand Down
2 changes: 1 addition & 1 deletion backend/src/types/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface TransactionTable {
export type TransactionTable = {
transaction_id: string // CHAR(36)
start_timestamp: Date // TIMESTAMP
completed_timestamp: Date | null // TIMESTAMP
Expand Down
2 changes: 1 addition & 1 deletion backend/src/types/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export enum UserType {
ADMIN = "admin",
}

export interface UserTable {
export type UserTable = {
uid: string // CHAR(36)
username: string // VARCHAR(255)
name: string // VARCHAR(255)
Expand Down
11 changes: 11 additions & 0 deletions backend/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,14 @@ export async function getUser(id: string): Promise<UserDetails> {
: UserType.STUDENT,
}
}

export function objectsToCsv(data: Record<string, unknown>[]): string {
const keys = Object.keys(data[0])
const csv = [keys.join(",")]

for (const row of data) {
csv.push(keys.map((key) => row[key]).join(","))
}

return csv.join("\n")
}
53 changes: 53 additions & 0 deletions frontend/src/UserProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { createContext, useCallback, useEffect, useState } from "react";
import { UserDetails } from "./types/user";
import { getUser } from "./api";

export const UserContext = createContext<{
user: UserDetails | null | undefined;
updateUser: () => Promise<void>;
}>({
user: null,
updateUser: async () => {},
});

function usersEqual(
oldUser: UserDetails | null | undefined,
newUser: UserDetails | null,
) {
if (oldUser === undefined) {
return false;
}
if (oldUser === newUser) {
return true; // both are null
}
if (oldUser === null || newUser === null) {
return false; // one is null, the other is not
}

return (
oldUser.username === newUser.username &&
oldUser.type === newUser.type &&
oldUser.balance === newUser.balance
);
}

function UserProvider(props: { children: React.ReactNode }) {
const [user, setUser] = useState<UserDetails | null | undefined>(undefined);
useEffect(() => {
getUser().then(setUser);
}, []);
const updateUser = useCallback(async () => {
const newUser = await getUser();
if (usersEqual(user, newUser)) {
return;
}
setUser(newUser);
}, [user]);
return (
<UserContext.Provider value={{ user, updateUser }}>
{props.children}
</UserContext.Provider>
);
}

export default UserProvider;
4 changes: 4 additions & 0 deletions frontend/src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Button, Stack, Typography } from "@mui/material";
import { useNavigate } from "react-router-dom";
import { logout } from "../api";
import { useContext } from "react";
import { UserContext } from "../UserProvider";

export default function Header() {
const navigate = useNavigate();
const { updateUser } = useContext(UserContext);

return (
<Stack
Expand All @@ -20,6 +23,7 @@ export default function Header() {
if (!resp) {
alert("Failed to log out");
}
await updateUser();
navigate("/");
}}
>
Expand Down
64 changes: 38 additions & 26 deletions frontend/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { createBrowserRouter, Outlet, RouterProvider } from "react-router-dom";

import { ThemeProvider } from "@mui/material/styles";
import { CssBaseline } from "@mui/material";
Expand All @@ -20,35 +20,47 @@ import StudentPaymentPage from "./routes/student_payment_view";
import BoothMainPage from "./routes/booth_main_view";
import BoothConfirmPaymentPage from "./routes/booth_confirm_payment_view";
import AdminPage from "./routes/admin_view";
import UserProvider from "./UserProvider";

const router = createBrowserRouter([
{
path: "/",
element: <LoginPage />,
},
{
path: "/student",
element: <StudentMainPage />,
},
{
path: "/student/topup",
element: <StudentTopupPage />,
},
{
path: "/student/payment",
element: <StudentPaymentPage />,
},
{
path: "/booth",
element: <BoothMainPage />,
},
{
path: "/booth/payment",
element: <BoothConfirmPaymentPage />,
},
{
path: "/admin",
element: <AdminPage />,
element: (
<UserProvider>
<Outlet />
</UserProvider>
),
children: [
{
path: "/",
element: <LoginPage />,
index: true,
},
{
path: "/student",
element: <StudentMainPage />,
},
{
path: "/student/topup",
element: <StudentTopupPage />,
},
{
path: "/student/payment",
element: <StudentPaymentPage />,
},
{
path: "/booth",
element: <BoothMainPage />,
},
{
path: "/booth/payment",
element: <BoothConfirmPaymentPage />,
},
{
path: "/admin",
element: <AdminPage />,
},
],
},
]);

Expand Down
33 changes: 17 additions & 16 deletions frontend/src/routes/admin_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import {
} from "@mui/material";
import Header from "../components/header";
import QrCodeScannerIcon from "@mui/icons-material/QrCodeScanner";
import { useEffect, useRef, useState } from "react";
import { useContext, useEffect, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import { addMoney, getTopup, getUser } from "../api";
import { addMoney, getTopup } from "../api";
import { UserType } from "../types/user";
import { Scanner } from "@yudiel/react-qr-scanner";
import { TopupDetails } from "../types/topup";
import Decimal from "decimal.js";
import { UserContext } from "../UserProvider";

export default function AdminPage() {
const [topup, setTopup] = useState<TopupDetails | null>(null);
Expand All @@ -25,21 +26,21 @@ export default function AdminPage() {
const navigate = useNavigate();
const amount = useRef("");

const { user } = useContext(UserContext);

useEffect(() => {
(async () => {
const user = await getUser();
if (user === null) {
return navigate("/");
}
if (user.type === UserType.STUDENT) {
navigate("/student");
} else if (user.type === UserType.ADMIN) {
return;
} else if (user.type === UserType.BOOTH) {
navigate("/booth");
}
})();
}, []);
if (user === undefined) {
return;
} else if (user === null) {
return navigate("/");
} else if (user.type === UserType.STUDENT) {
navigate("/student");
} else if (user.type === UserType.ADMIN) {
return;
} else if (user.type === UserType.BOOTH) {
navigate("/booth");
}
}, [user]);

return (
<Container maxWidth="sm">
Expand Down
40 changes: 20 additions & 20 deletions frontend/src/routes/booth_confirm_payment_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,48 @@ import {
} from "@mui/material";
import { Link, useLocation, useNavigate } from "react-router-dom";
import Header from "../components/header";
import { useState, useEffect } from "react";
import { collectTransaction, getTransactionDetails, getUser } from "../api";
import { UserDetails, UserType } from "../types/user";
import { useState, useEffect, useContext } from "react";
import { collectTransaction, getTransactionDetails } from "../api";
import { UserType } from "../types/user";
import { TransactionDetails } from "../types/transaction";
import { UserContext } from "../UserProvider";

export default function BoothConfirmPaymentPage() {
const navigate = useNavigate();
const [user, setUser] = useState<UserDetails | null>(null);
const [transaction, setTransaction] = useState<TransactionDetails | null>(
null,
);
const location = useLocation();
const transId: string | undefined = location.state.transId;
const { user } = useContext(UserContext);

useEffect(() => {
if (!transId) {
navigate("/booth");
return;
}
(async () => {
const user = await getUser();
if (user === null) {
return navigate("/");
}
if (user.type === UserType.STUDENT) {
navigate("/student");
} else if (user.type === UserType.ADMIN) {
navigate("/admin");
} else if (user.type === UserType.BOOTH) {
setUser(user);
if (user === undefined) {
return;
} else if (user === null) {
return navigate("/");
} else if (user.type === UserType.STUDENT) {
navigate("/student");
} else if (user.type === UserType.ADMIN) {
navigate("/admin");
} else if (user.type === UserType.BOOTH) {
(async () => {
const transaction = await getTransactionDetails(transId);
if (transaction === null) {
navigate("/booth");
return;
}
setTransaction(transaction);
return;
}
})();
}, []);
})();
return;
}
}, [user]);

if (user === null || !transId || transaction === null) {
if (!user || !transId || transaction === null) {
return <></>;
}

Expand Down
Loading

0 comments on commit 468d2e9

Please sign in to comment.