Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# ignoring any env files and node_modules in each microservice, will be helpful for local development
**/.env*
**/node_modules/**
3 changes: 3 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
},
"dependencies": {
"@nextui-org/react": "^2.2.9",
"@tanstack/react-query": "^5.24.1",
"axios": "^1.6.7",
"classnames": "^2.5.1",
"framer-motion": "^11.0.5",
"html-react-parser": "^5.1.8",
"next": "14.1.0",
"react": "^18",
"react-dom": "^18",
Expand Down
33 changes: 33 additions & 0 deletions frontend/public/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion frontend/public/next.svg

This file was deleted.

1 change: 0 additions & 1 deletion frontend/public/vercel.svg

This file was deleted.

29 changes: 29 additions & 0 deletions frontend/src/app/(pages)/assignments/[id]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import AssignmentService from "@/helpers/assignment-service/api-wrapper";
import { Metadata } from "next";

type Props = {
params: {
id: string;
};
};

export default function AssignmentPageLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return <div>{children}</div>;
}

export async function generateMetadata({ params }: Props) {
const assignmentTitle = (
await AssignmentService.getAssignmentById({
assignmentId: params.id,
})
).title;

const metadata: Metadata = {
title: assignmentTitle,
description: `Assignment page for ${assignmentTitle}`,
};

return metadata;
}
40 changes: 40 additions & 0 deletions frontend/src/app/(pages)/assignments/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use client";

import AssignmentPage from "@/components/assignment/AssignmentPage";
import LogoLoading from "@/components/common/LogoLoading";
import AssignmentService from "@/helpers/assignment-service/api-wrapper";
import { useQuery } from "@tanstack/react-query";
import { notFound } from "next/navigation";

interface Props {
id: string;
}

const page = ({ id }: Props) => {
const {
data: assignment,
isLoading,
isError,
} = useQuery({
queryKey: ["get-assignment", id],
queryFn: async () => {
const assignment = await AssignmentService.getAssignmentById({
assignmentId: id,
});

return assignment;
},
});

if (isError) {
return notFound();
}

return (
<div>
{isLoading ? <LogoLoading /> : <AssignmentPage assignment={assignment} />}
</div>
);
};

export default page;
4 changes: 2 additions & 2 deletions frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en" className="dark">
<html lang="en" className="bg-white">
<body className={inter.className + " min-h-screen"}>
<Providers>
<div className="h-screen flex flex-row justify-start">
<div className="flex flex-row justify-start">
<SideBar />
<div className="bg-white flex-1 p-4 text-black border border-dashed">
{children}
Expand Down
54 changes: 54 additions & 0 deletions frontend/src/components/assignment/AssignmentPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { notFound } from "next/navigation";
import AssignmentQuestion from "./AssignmentQuestion";
import DateUtils from "../../utils/dateUtils";
import { Button } from "@nextui-org/react";

interface Props {
assignment?: Assignment;
}

const AssignmentPage = ({ assignment }: Props) => {
if (!assignment) {
return notFound();
}

return (
<div className="ml-[12%] mt-[5%] mr-[8%]">
{/* Assignment Header */}
<div className="flex gap-2">
<div>
<h1 className="text-3xl font-semibold ">{assignment.title}</h1>

<div className="flex flex-col ml-4 my-4 gap-2">
<p className="text-lg font-semibold">
Due on:{" "}
<span className="italic font-medium">
{DateUtils.parseTimestampToDate(assignment.deadline)}
</span>
</p>
<p className="text-lg font-semibold">
Number of questions:{" "}
<span className="italic font-medium">
{assignment.numberOfQuestions}
</span>
</p>
</div>
</div>

{/* Button for submission */}
<div className="ml-auto mr-4 my-2">
<Button className="px-6" color="primary">
Submit
</Button>
</div>
</div>

{/* Assignment questions */}
{assignment.questions.map((question) => {
return <AssignmentQuestion question={question} key={question.id} />;
})}
</div>
);
};

export default AssignmentPage;
32 changes: 32 additions & 0 deletions frontend/src/components/assignment/AssignmentQuestion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Divider } from "@nextui-org/react";
import parse from "html-react-parser";

interface Props {
question: Question;
}

const AssignmentQuestion = ({ question }: Props) => {
return (
<div className="flex px-0 py-4 mb-6">
<div className="w-full px-5">
{/* Question title */}
<div className="flex space-x-4">
<div className="flex-1 mr-2 text-xl font-semibold">
{question.title}
</div>
</div>

<Divider className="mt-4 mb-2" />

{/* Question description */}
<div className="flex mt-3">
<div className="text-md text-justify">
{parse(question.description)}
</div>
</div>
</div>
</div>
);
};

export default AssignmentQuestion;
19 changes: 19 additions & 0 deletions frontend/src/components/common/ITSLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Image } from "@nextui-org/react";

interface Props {
width?: string;
height?: string;
}

const ITSLogo = ({ width = "100%", height = "100%" }: Props) => {
return (
<Image
src="/logo.svg"
className="bg-logo mx-auto -mb-4 z-0"
width={width}
height={height}
/>
);
};

export default ITSLogo;
25 changes: 25 additions & 0 deletions frontend/src/components/common/LogoLoading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import ITSLogo from "./ITSLogo";

interface Props {
minHeight?: number;
}

const LogoLoading = ({ minHeight }: Props) => {
return (
<div
style={{ height: minHeight ? `${minHeight}px` : `100vh` }}
className="flex flex-col items-center justify-center"
>
<div className="flex items-center justify-center object-cover">
<ITSLogo />
</div>

<div className="mx-2 -mt-2 z-20">
<div className="flex items-center justify-center">Loading...</div>
<div className="relative w-64 space-y-3 overflow-hidden rounded-md bg-logo p-3 shadow before:absolute before:inset-0 before:-translate-x-full before:bg-gradient-to-r before:from-transparent before:via-slate-200 hover:shadow-lg before:animate-[shimmer_1.5s_infinite]"></div>
</div>
</div>
);
};

export default LogoLoading;
9 changes: 8 additions & 1 deletion frontend/src/components/common/Providers.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
"use client";

import { NextUIProvider } from "@nextui-org/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactNode } from "react";

const Providers = ({ children }: { children: ReactNode }) => {
return <NextUIProvider>{children}</NextUIProvider>;
const queryClient = new QueryClient();

return (
<QueryClientProvider client={queryClient}>
<NextUIProvider>{children}</NextUIProvider>
</QueryClientProvider>
);
};

export default Providers;
3 changes: 1 addition & 2 deletions frontend/src/components/common/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { useState } from "react";
import { Avatar, Button, User } from "@nextui-org/react";
import { TbLayoutSidebarLeftCollapse } from "react-icons/tb";
import { HiOutlineChevronDoubleLeft, HiMenu } from "react-icons/hi";
import classNames from "classnames";

Expand All @@ -13,7 +12,7 @@ const SideBar = () => {
const [isCollapsible, setIsCollapsible] = useState(false);

const wrapperClasses = classNames(
"h-screen px-4 pt-8 pb-4 bg-gray-200 text-black flex justify-between flex-col border border-dashed",
"px-4 pt-8 pb-4 bg-gray-200 text-black flex justify-between flex-col border border-dashed",
{
["w-60"]: !isCollapsed,
["w-20"]: isCollapsed,
Expand Down
Loading