diff --git a/frontend/src/hooks/useHistory.tsx b/frontend/src/hooks/useHistory.tsx index cdb92498..1d5a7d37 100644 --- a/frontend/src/hooks/useHistory.tsx +++ b/frontend/src/hooks/useHistory.tsx @@ -3,7 +3,8 @@ import { AuthContext } from "@/contexts/AuthContext"; import { getAttemptsOfUser, createAttemptOfUser, -} from "./../pages/api/historyHandler"; + getAttemptById, +} from "@/pages/api/historyHandler"; type AttemptData = { uid: string; @@ -27,5 +28,11 @@ export const useHistory = () => { } }; - return { fetchAttempts, postAttempt }; + const fetchAttempt = async (attemptId: string) => { + if (authIsReady) { + return getAttemptById(currentUser, attemptId); + } + } +; + return { fetchAttempts, fetchAttempt, postAttempt }; }; diff --git a/frontend/src/pages/api/historyHandler.ts b/frontend/src/pages/api/historyHandler.ts index 075908dc..0ddc1a73 100644 --- a/frontend/src/pages/api/historyHandler.ts +++ b/frontend/src/pages/api/historyHandler.ts @@ -1,4 +1,5 @@ import { userApiPathAddress } from "@/gateway-address/gateway-address"; +import { Attempt } from "@/types/UserTypes"; export const getAttemptsOfUser = async (user: any, uid: string) => { try { @@ -30,9 +31,37 @@ export const getAttemptsOfUser = async (user: any, uid: string) => { } }; +export const getAttemptById = async (user: any, attemptId: string) => { + try { + const url = `${userApiPathAddress}attempt/${attemptId}`; + const idToken = await user.getIdToken(true); + + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + "User-Id-Token": idToken, + }, + }); + + if (!response.ok) { + throw new Error(`Unable to get attempt: ${await response.text()}`); + } + return response.json().then(val => { + val["time_saved_at"] = new Date(val["time_saved_at"]); + val["time_updated"] = new Date(val["time_updated"]); + val["time_created"] = new Date(val["time_created"]); + return val + }); + } catch (error) { + console.error("There was an error fetching the attempt", error); + throw error; + } +}; + export const createAttemptOfUser = async (user: any, data: any) => { try { - const url = `${userApiPathAddress}api/attempt`; + const url = `${userApiPathAddress}attempt`; const idToken = await user.getIdToken(true); const response = await fetch(url, { diff --git a/frontend/src/pages/attempt/[id]/index.tsx b/frontend/src/pages/attempt/[id]/index.tsx index f6b4dd65..7d90c88b 100644 --- a/frontend/src/pages/attempt/[id]/index.tsx +++ b/frontend/src/pages/attempt/[id]/index.tsx @@ -4,9 +4,50 @@ import { Textarea } from "@/components/ui/textarea"; import { TypographyBody, TypographyCode, TypographyH2 } from "@/components/ui/typography"; import { ArrowLeft } from "lucide-react"; import { useRouter } from "next/router"; +import { useEffect, useState } from "react"; +import { Attempt } from "@/types/UserTypes"; +import { useHistory } from "@/hooks/useHistory"; +import { useQuestions } from "@/hooks/useQuestions"; +import { Question } from "@/types/QuestionTypes"; +import { DotWave } from "@uiball/loaders"; export default function Page() { const router = useRouter(); + const attemptId = router.query.id; + const { fetchAttempt } = useHistory(); + const { fetchQuestion } = useQuestions(); + const [attempt, setAttempt] = useState(); + const [question, setQuestion] = useState(); + const [loadingState, setLoadingState] = useState<"loading" | "error" | "success">("loading"); + + useEffect(() => { + if (attemptId === undefined || Array.isArray(attemptId)) { + router.push("/profile"); + return; + } + fetchAttempt(attemptId).then((attempt) => { + if (attempt) { + setAttempt(attempt); + return fetchQuestion(attempt.question_id); + } else { + throw new Error("Attempt not found"); + } + }).then((question) => { + if (question) { + setQuestion(question); + setLoadingState("success"); + } else { + throw new Error("Question not found"); + } + }).catch((err: any) => { + setLoadingState("error"); + console.log(err); + }); + }, [attemptId]); + + if (attemptId === undefined || Array.isArray(attemptId)) { + return null; + } return (
@@ -17,27 +58,33 @@ export default function Page() { Attempt
+ { loadingState === "loading" ?
+
: loadingState === "error" ? Error : <>
- Two Sum + {question?.title}
- 23/10/2023 15:00 + {attempt?.time_updated.toLocaleString()}
- Interview • with Chun Wei + {attempt?.room_id ? "Interview" : "Solo"}
- Solved - -
+ } ) } diff --git a/frontend/src/pages/profile/index.tsx b/frontend/src/pages/profile/index.tsx index ca96f704..9e5c9253 100644 --- a/frontend/src/pages/profile/index.tsx +++ b/frontend/src/pages/profile/index.tsx @@ -18,7 +18,7 @@ export default function Page() { setAttempts(attempts); setLoadingState("success"); } - }).catch(err => { + }).catch((err: any) => { setLoadingState("error"); console.log(err); }); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 00ef3a01..6c082575 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -22,7 +22,6 @@ model Match { chosenProgrammingLanguage String questionId String? createdAt DateTime @default(now()) - questionId String? } model AppUser { diff --git a/services/user-service/src/db/functions.ts b/services/user-service/src/db/functions.ts index bf151203..7eaf01fe 100644 --- a/services/user-service/src/db/functions.ts +++ b/services/user-service/src/db/functions.ts @@ -75,6 +75,20 @@ const userDatabaseFunctions = { } }, + async getAttemptById(attemptId: string) { + try { + const attempt = await prismaClient.attempt.findUnique({ + where: { + id: attemptId, + }, + }); + return attempt; + } catch (error: any) { + console.error(`Error retrieving attempt: ${error.message}`); + throw error; + } + }, + async createAttemptOfUser(data: { uid: string; question_id: string; diff --git a/services/user-service/src/routes/index.ts b/services/user-service/src/routes/index.ts index 17571890..16eb45b1 100644 --- a/services/user-service/src/routes/index.ts +++ b/services/user-service/src/routes/index.ts @@ -130,6 +130,25 @@ indexRouter.get( } ); +indexRouter.get( + "/attempt/:attempt_id", + function (req: express.Request, res: express.Response) { + userDatabaseFunctions + .getAttemptById(req.params.attempt_id) + .then((result) => { + if (result === null) { + res.status(404).end(); + } else { + res.status(200).json(result); + } + }) + .catch(() => { + // Server side error such as database not being available + res.status(500).end(); + }); + } +); + indexRouter.post( "/attempt", function (req: express.Request, res: express.Response) {