Skip to content
Open
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
336 changes: 137 additions & 199 deletions apps/web/src/app/[lang]/(mods-pages)/(side-pages)/proxy-login/page.tsx

Large diffs are not rendered by default.

37 changes: 20 additions & 17 deletions apps/web/src/app/[lang]/(mods-pages)/student/grades/page.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import { useQuery } from "@tanstack/react-query";
import { AISNotLoggedIn } from "@/components/Pages/AISNotLoggedIn";
import { AISLoading } from "@/components/Pages/AISLoading";
import { GradesViewer } from "./GradesViewer";
import { useHeadlessAIS } from "@/hooks/useHeadlessAIS";
import { fetchGrades } from "@/lib/headless-ais-api";
import type { GradeObject } from "@/types/grades";

const StudentGradesPage = () => {
// const { initializing, getACIXSTORE, ais, loading } = useHeadlessAIS();
const { ais, getACIXSTORE } = useHeadlessAIS();

// const {
// data: grades,
// isLoading,
// error,
// } = useQuery({
// queryKey: ["grades", initializing],
// queryFn: async () => {
// if (initializing) return null;
// const token = await getACIXSTORE();
// return (await getStudentGrades(token!)) as GradeObject;
// },
// });
// if (!ais.enabled) return <AISNotLoggedIn />;
// if (isLoading || !grades) return <AISLoading />;
// return <GradesViewer grades={grades!} />;
return <AISNotLoggedIn />;
const { data: grades, isLoading } = useQuery({
queryKey: ["grades", ais.enabled],
queryFn: async () => {
const token = await getACIXSTORE();
return (await fetchGrades(token)) as GradeObject;
},
enabled: ais.enabled,
retry: false,
});

if (!ais.enabled) return <AISNotLoggedIn />;
if (isLoading || !grades) return <AISLoading />;
return <GradesViewer grades={grades} />;
};

export default StudentGradesPage;
272 changes: 128 additions & 144 deletions apps/web/src/app/[lang]/(mods-pages)/student/id/page.tsx
Original file line number Diff line number Diff line change
@@ -1,154 +1,138 @@
import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { QRCodeSVG } from "qrcode.react";
import { Skeleton } from "@courseweb/ui";

Check warning on line 4 in apps/web/src/app/[lang]/(mods-pages)/student/id/page.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'@courseweb/ui' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=nthumodifications_courseweb&issues=AZ051RgBmfd6IM4Tp1VJ&open=AZ051RgBmfd6IM4Tp1VJ&pullRequest=793
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@courseweb/ui";

Check warning on line 5 in apps/web/src/app/[lang]/(mods-pages)/student/id/page.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'@courseweb/ui' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=nthumodifications_courseweb&issues=AZ051RgBmfd6IM4Tp1VK&open=AZ051RgBmfd6IM4Tp1VK&pullRequest=793
import { AISNotLoggedIn } from "@/components/Pages/AISNotLoggedIn";
import { useHeadlessAIS } from "@/hooks/useHeadlessAIS";
import {
fetchOSACode,
fetchOSAToken,
fetchDoorQR,
} from "@/lib/headless-ais-api";

const StudentIDPage = () => {
// const [tab, setTab] = useState("door");
// const { ais, getACIXSTORE, user } = useHeadlessAIS();
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: refresh, isLoading: refreshLoading } = useQuery({
queryKey: ["osa_refreshtoken", user?.studentid],
queryFn: async () => {
const ACIXSTORE = await getACIXSTORE();
return fetchOSACode(ACIXSTORE) as Promise<{
user_id: string;
refreshToken: string;
}>;
},
enabled: ais.enabled,
staleTime: 86400000,
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 { data: token, isLoading: tokenLoading } = useQuery({
queryKey: ["osa_accesstoken", refresh?.user_id],
queryFn: async () => {
if (!refresh) throw new Error("Refresh token not found");
const access = (await fetchOSAToken(
refresh.user_id,
refresh.refreshToken,
)) as {
authToken: string;
deviceId: string;
session_id: string;
};
return { ...access, user_id: refresh.user_id };
},
refetchInterval: 3600000,
enabled: !!refresh,
retry: false,
});

// const isLoadingStuff = refreshLoading || tokenLoading || isLoading;
const { data: qrString, isLoading: qrLoading } = useQuery({
queryKey: ["door_qr", token?.user_id],
queryFn: async () => {
if (!token) throw new Error("Token not found");
return fetchDoorQR(
token.authToken,
token.deviceId,
token.session_id,
) as Promise<string>;
},
enabled: !!token && tab === "door",
refetchInterval: 10000,
retry: false,
});

// return (
// <div className="flex flex-col px-4">
// <div className="flex flex-col gap-2">
// <div className="">
// <h1 className="text-xl font-bold">國立清華大學</h1>
// </div>
// <Tabs defaultValue="door" value={tab} onValueChange={setTab}>
// <div className="flex flex-col gap-2">
// <TabsContent value="door">
// <div className="flex flex-col items-center">
// {isLoadingStuff || !qrString ? (
// <Skeleton className="h-60 w-60"></Skeleton>
// ) : (
// <img
// src={qrString}
// alt="door access qr"
// className="w-60 h-60"
// />
// )}
// </div>
// </TabsContent>
// <TabsContent value="studentid">
// {user?.studentid ? (
// <div className="flex flex-col items-center gap-4">
// <Barcode
// width={2}
// height={44}
// value={user.studentid}
// displayValue={false}
// />
// <QRCodeSVG className="h-40 w-40" value={user.studentid} />
// </div>
// ) : (
// <div className="flex flex-col items-center gap-4">
// <Skeleton className="h-16 w-60"></Skeleton>
// <Skeleton className="h-40 w-40"></Skeleton>
// </div>
// )}
// </TabsContent>
// <TabsList className="w-full justify-evenly mb-4 fixed md:relative bottom-16 md:bottom-auto left-0 md:left-auto">
// <TabsTrigger value="door" className="flex-1">
// 門禁
// </TabsTrigger>
// <TabsTrigger value="studentid" className="flex-1">
// 學號
// </TabsTrigger>
// </TabsList>
// </div>
// </Tabs>
// <div className="flex flex-col gap-2">
// <div>
// <h1 className="text-lg font-bold">{user?.name_zh}</h1>
// <h1>{user?.name_en}</h1>
// </div>
// <div className="flex gap-2">
// <div className="text-sm font-thin">科系</div>
// <h2 className="text-sm">{user?.department}</h2>
// </div>
// <div className="flex gap-2">
// <div className="text-sm font-thin">學號</div>
// <h2 className="text-sm">{user?.studentid}</h2>
// </div>
// <div className="flex gap-2">
// <div className="text-sm font-thin">年級</div>
// <h2 className="text-sm">{user?.grade}</h2>
// </div>
// </div>
// </div>
// </div>
// );
return <AISNotLoggedIn />;
if (!ais.enabled) return <AISNotLoggedIn />;

const isLoadingStuff = refreshLoading || tokenLoading || qrLoading;

return (
<div className="flex flex-col px-4">
<div className="flex flex-col gap-2">
<div>
<h1 className="text-xl font-bold">國立清華大學</h1>
</div>
<Tabs defaultValue="door" value={tab} onValueChange={setTab}>
<div className="flex flex-col gap-2">
<TabsContent value="door">
<div className="flex flex-col items-center">
{isLoadingStuff || !qrString ? (
<Skeleton className="h-60 w-60" />
) : (
<img
src={qrString}
alt="door access qr"
className="w-60 h-60"
/>
)}
</div>
</TabsContent>
<TabsContent value="studentid">
{user?.studentid ? (
<div className="flex flex-col items-center gap-4">
<QRCodeSVG className="h-40 w-40" value={user.studentid} />
<p className="text-lg font-mono font-semibold">
{user.studentid}
</p>
</div>
) : (
<div className="flex flex-col items-center gap-4">
<Skeleton className="h-40 w-40" />
</div>
)}
</TabsContent>
<TabsList className="w-full justify-evenly mb-4 fixed md:relative bottom-16 md:bottom-auto left-0 md:left-auto">
<TabsTrigger value="door" className="flex-1">
門禁
</TabsTrigger>
<TabsTrigger value="studentid" className="flex-1">
學號
</TabsTrigger>
</TabsList>
</div>
</Tabs>
<div className="flex flex-col gap-2">
<div>
<h1 className="text-lg font-bold">{user?.name_zh}</h1>
<h1>{user?.name_en}</h1>
</div>
<div className="flex gap-2">
<div className="text-sm font-thin">科系</div>
<h2 className="text-sm">{user?.department}</h2>
</div>
<div className="flex gap-2">
<div className="text-sm font-thin">學號</div>
<h2 className="text-sm">{user?.studentid}</h2>
</div>
<div className="flex gap-2">
<div className="text-sm font-thin">年級</div>
<h2 className="text-sm">{user?.grade}</h2>
</div>
</div>
</div>
</div>
);
};

export default StudentIDPage;
Loading