diff --git a/package-lock.json b/package-lock.json index 0eb62c56..c4fa183d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -99,6 +99,7 @@ "qrcode.react": "^3.1.0", "query-string": "^8.1.0", "react": "18.3.1", + "react-barcode": "^1.5.3", "react-cookie": "^7.1.0", "react-day-picker": "^8.10.1", "react-dom": "18.3.1", @@ -13333,6 +13334,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbarcode": { + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.11.6.tgz", + "integrity": "sha512-G5TKGyKY1zJo0ZQKFM1IIMfy0nF2rs92BLlCz+cU4/TazIc4ZH+X1GYeDRt7TKjrYqmPfTjwTBkU/QnQlsYiuA==", + "license": "MIT" + }, "node_modules/jsdom": { "version": "24.1.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.0.tgz", @@ -15716,6 +15723,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-barcode": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/react-barcode/-/react-barcode-1.5.3.tgz", + "integrity": "sha512-EJPUwuERKpApcQ9qXzdVZzddFYRT7+3R/jJ3OrTfW6m2iq+WT+CBaVB7DsQazhPRXDfMcx9+dmMmzjsmveOViQ==", + "license": "ISC", + "dependencies": { + "jsbarcode": "^3.8.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-cookie": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-7.1.4.tgz", diff --git a/package.json b/package.json index 66f80b09..ae465310 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,7 @@ "qrcode.react": "^3.1.0", "query-string": "^8.1.0", "react": "18.3.1", + "react-barcode": "^1.5.3", "react-cookie": "^7.1.0", "react-day-picker": "^8.10.1", "react-dom": "18.3.1", diff --git a/src/app/[lang]/(mods-pages)/student/id/page.tsx b/src/app/[lang]/(mods-pages)/student/id/page.tsx new file mode 100644 index 00000000..2080ac7a --- /dev/null +++ b/src/app/[lang]/(mods-pages)/student/id/page.tsx @@ -0,0 +1,167 @@ +"use client"; +import { Badge } from "@/components/ui/badge"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { useHeadlessAIS } from "@/hooks/contexts/useHeadlessAIS"; +import { + getDoorAccessQR, + getOSAAccessToken, + getOSACode, + getParcelInformation, +} from "@/lib/headless_ais/inthu"; +import { useQuery } from "@tanstack/react-query"; +import { useState } from "react"; +import { Skeleton } from "@/components/ui/skeleton"; +import { QRCodeSVG } from "qrcode.react"; +import Barcode from "react-barcode"; + +const StudentIDPage = () => { + const [tab, setTab] = useState("door"); + const { ais, getACIXSTORE, user } = useHeadlessAIS(); + + const { + data: refresh, + error: refreshError, + isLoading: refreshLoading, + } = useQuery({ + queryKey: ["osa_refreshtoken", user?.studentid], + queryFn: async () => { + const ACIXSTORE = await getACIXSTORE(); + if (!ACIXSTORE) { + throw new Error("Failed to get token"); + } + const res = await getOSACode(ACIXSTORE); + if (!res) { + throw new Error("Failed to get token"); + } + return res; + }, + // expire after 1 day + staleTime: 86400000, + // don't retry on error + retry: false, + }); + const { + data: token, + error: tokenError, + isLoading: tokenLoading, + } = useQuery({ + queryKey: ["osa_accesstoken", refresh?.user_id], + queryFn: async () => { + if (!refresh) { + throw new Error("Refresh token not found"); + } + const access = await getOSAAccessToken( + refresh.user_id, + refresh.refreshToken, + ); + if (!access) { + throw new Error("Failed to get token"); + } + return { ...access, user_id: refresh.user_id }; + }, + // refresh every 1 hour + refetchInterval: 3600000, + enabled: !!refresh, + // don't retry on error + retry: false, + }); + + const { + data: qrString, + error, + isLoading, + } = useQuery({ + queryKey: ["parcels", token?.user_id], + queryFn: async () => { + if (!token) { + throw new Error("Token not found"); + } + const data = await getDoorAccessQR( + token.authToken, + token.deviceId, + token.session_id, + ); + return data; + }, + enabled: !!token && tab === "door", + // refresh only every 10 sec + refetchInterval: 10000, + // don't retry on error + retry: false, + }); + + const isLoadingStuff = refreshLoading || tokenLoading || isLoading; + + return ( +