diff --git a/frontend/peerprep/app/error.tsx b/frontend/peerprep/app/(default)/error.tsx similarity index 100% rename from frontend/peerprep/app/error.tsx rename to frontend/peerprep/app/(default)/error.tsx diff --git a/frontend/peerprep/app/leaderboard/layout.tsx b/frontend/peerprep/app/(default)/home/layout.tsx similarity index 56% rename from frontend/peerprep/app/leaderboard/layout.tsx rename to frontend/peerprep/app/(default)/home/layout.tsx index e4697e5b71..b28d2b3636 100644 --- a/frontend/peerprep/app/leaderboard/layout.tsx +++ b/frontend/peerprep/app/(default)/home/layout.tsx @@ -1,11 +1,11 @@ -export default function LeaderboardLayout({ +export default function HomeLayout({ children, }: { children: React.ReactNode; }) { return ( -
-
+
+
{children}
diff --git a/frontend/peerprep/app/(default)/home/page.tsx b/frontend/peerprep/app/(default)/home/page.tsx new file mode 100644 index 0000000000..8bc95e37e8 --- /dev/null +++ b/frontend/peerprep/app/(default)/home/page.tsx @@ -0,0 +1,142 @@ +"use client"; + +import { + Progress, + Button, + Avatar, + Badge, + Spacer, + Divider, +} from "@nextui-org/react"; + +import { Card, CardHeader, CardBody, CardFooter } from "@nextui-org/card"; + +export default function Home() { + const friends = [ + { name: "s_name", status: "online" }, + { name: "thisisalongusername", status: "online" }, + { name: "Friend3", status: "hidden" }, + { name: "Friend4", status: "offline" }, + ]; + + return ( +
+

+ Hey there! Ready for some coding challenges? 🧑‍💻 +

+ + {/* Layout container */} +
+ {/* Left Column */} +
+ {/* Start a new session */} +
+ + +

+ Are you ready? +

+
+ + + +
+ + +

+ Current Score +

+

1600

+ + 75% +
+
+
+ + + + {/* Activity Heatmap */} + + +

+ Activities in the last year +

+
+ {/* Placeholder for heatmap */} +
+
+
+
+ + {/* Right Column (Friends List) */} +
+ + +

Friends

+
    + {friends.map((friend, idx) => ( +
  • + +
    +

    {friend.name}

    + + {friend.status} + +
    +
  • + ))} +
+
+
+
+
+ + {/* Activity Feed */} +
+ + +

Activity Feed

+ +
+ {/* Mock activity feed */} +
+

+ JayCee completed 'Split Linked List in Parts' +

+

+ With jweng5551 | Linked List - Medium | +200 points +

+
+
+

+ jweng5551 completed 'Split Linked List in Parts' +

+

+ With JayCee | Linked List - Medium | +200 points +

+
+
+

+ DelilShad completed 'Regular Expression Matching' +

+

+ With You | Dynamic Programming - Hard | +500 points +

+
+
+
+
+
+ + +
+ ); +} diff --git a/frontend/peerprep/app/layout.tsx b/frontend/peerprep/app/(default)/layout.tsx similarity index 98% rename from frontend/peerprep/app/layout.tsx rename to frontend/peerprep/app/(default)/layout.tsx index cb2f705479..5f8e46b4a4 100644 --- a/frontend/peerprep/app/layout.tsx +++ b/frontend/peerprep/app/(default)/layout.tsx @@ -45,7 +45,7 @@ export default function RootLayout({ diff --git a/frontend/peerprep/app/providers.tsx b/frontend/peerprep/app/(default)/providers.tsx similarity index 100% rename from frontend/peerprep/app/providers.tsx rename to frontend/peerprep/app/(default)/providers.tsx diff --git a/frontend/peerprep/app/questions-management/add/layout.tsx b/frontend/peerprep/app/(default)/questions-management/add/layout.tsx similarity index 100% rename from frontend/peerprep/app/questions-management/add/layout.tsx rename to frontend/peerprep/app/(default)/questions-management/add/layout.tsx diff --git a/frontend/peerprep/app/questions-management/add/page.tsx b/frontend/peerprep/app/(default)/questions-management/add/page.tsx similarity index 100% rename from frontend/peerprep/app/questions-management/add/page.tsx rename to frontend/peerprep/app/(default)/questions-management/add/page.tsx diff --git a/frontend/peerprep/app/questions-management/list/columns.tsx b/frontend/peerprep/app/(default)/questions-management/columns.tsx similarity index 100% rename from frontend/peerprep/app/questions-management/list/columns.tsx rename to frontend/peerprep/app/(default)/questions-management/columns.tsx diff --git a/frontend/peerprep/app/questions-management/edit/[id]/layout.tsx b/frontend/peerprep/app/(default)/questions-management/edit/[id]/layout.tsx similarity index 100% rename from frontend/peerprep/app/questions-management/edit/[id]/layout.tsx rename to frontend/peerprep/app/(default)/questions-management/edit/[id]/layout.tsx diff --git a/frontend/peerprep/app/questions-management/edit/[id]/page.tsx b/frontend/peerprep/app/(default)/questions-management/edit/[id]/page.tsx similarity index 100% rename from frontend/peerprep/app/questions-management/edit/[id]/page.tsx rename to frontend/peerprep/app/(default)/questions-management/edit/[id]/page.tsx diff --git a/frontend/peerprep/app/questions-management/list/layout.tsx b/frontend/peerprep/app/(default)/questions-management/layout.tsx similarity index 100% rename from frontend/peerprep/app/questions-management/list/layout.tsx rename to frontend/peerprep/app/(default)/questions-management/layout.tsx diff --git a/frontend/peerprep/app/questions-management/mockdata/sample_getAllQuestions.json b/frontend/peerprep/app/(default)/questions-management/mockdata/sample_getAllQuestions.json similarity index 100% rename from frontend/peerprep/app/questions-management/mockdata/sample_getAllQuestions.json rename to frontend/peerprep/app/(default)/questions-management/mockdata/sample_getAllQuestions.json diff --git a/frontend/peerprep/app/questions-management/mockdata/sample_getSingleQuestion.json b/frontend/peerprep/app/(default)/questions-management/mockdata/sample_getSingleQuestion.json similarity index 100% rename from frontend/peerprep/app/questions-management/mockdata/sample_getSingleQuestion.json rename to frontend/peerprep/app/(default)/questions-management/mockdata/sample_getSingleQuestion.json diff --git a/frontend/peerprep/app/questions-management/list/page.tsx b/frontend/peerprep/app/(default)/questions-management/page.tsx similarity index 100% rename from frontend/peerprep/app/questions-management/list/page.tsx rename to frontend/peerprep/app/(default)/questions-management/page.tsx diff --git a/frontend/peerprep/app/settings/layout.tsx b/frontend/peerprep/app/(default)/settings/layout.tsx similarity index 100% rename from frontend/peerprep/app/settings/layout.tsx rename to frontend/peerprep/app/(default)/settings/layout.tsx diff --git a/frontend/peerprep/app/settings/page.tsx b/frontend/peerprep/app/(default)/settings/page.tsx similarity index 100% rename from frontend/peerprep/app/settings/page.tsx rename to frontend/peerprep/app/(default)/settings/page.tsx diff --git a/frontend/peerprep/app/(landing)/layout.tsx b/frontend/peerprep/app/(landing)/layout.tsx new file mode 100644 index 0000000000..fd7cd247e9 --- /dev/null +++ b/frontend/peerprep/app/(landing)/layout.tsx @@ -0,0 +1,13 @@ +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + +
{children}
; + + + ); +} diff --git a/frontend/peerprep/app/(landing)/login/layout.tsx b/frontend/peerprep/app/(landing)/login/layout.tsx new file mode 100644 index 0000000000..c6adee81b3 --- /dev/null +++ b/frontend/peerprep/app/(landing)/login/layout.tsx @@ -0,0 +1,7 @@ +export default function LoginLayout({ + children, +}: { + children: React.ReactNode; +}) { + return
{children}
; +} diff --git a/frontend/peerprep/app/(landing)/login/page.tsx b/frontend/peerprep/app/(landing)/login/page.tsx new file mode 100644 index 0000000000..5e6cdf384a --- /dev/null +++ b/frontend/peerprep/app/(landing)/login/page.tsx @@ -0,0 +1,9 @@ +"use client"; + +export default function Home() { + return ( +
+

Placeholder login page

+
+ ); +} diff --git a/frontend/peerprep/app/(landing)/page.tsx b/frontend/peerprep/app/(landing)/page.tsx new file mode 100644 index 0000000000..20db970014 --- /dev/null +++ b/frontend/peerprep/app/(landing)/page.tsx @@ -0,0 +1,11 @@ +"use client"; + +export default function Landing() { + return ( +
+

+ Placeholder Landing page +

+
+ ); +} diff --git a/frontend/peerprep/app/leaderboard/page.tsx b/frontend/peerprep/app/leaderboard/page.tsx deleted file mode 100644 index da889a4e0c..0000000000 --- a/frontend/peerprep/app/leaderboard/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { title } from "@/components/primitives"; - -export default function LeaderboardPage() { - return ( -
-

Leaderboard

-
- ); -} diff --git a/frontend/peerprep/app/page.tsx b/frontend/peerprep/app/page.tsx deleted file mode 100644 index 87fcb86fd0..0000000000 --- a/frontend/peerprep/app/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -"use client"; - -import QuestionsTable from "@/components/questionstable"; - -export default function Home() { - return ( -
- -
- ); -} diff --git a/frontend/peerprep/components/addquestionform.tsx b/frontend/peerprep/components/addquestionform.tsx index 07ef51d88d..b304a558db 100644 --- a/frontend/peerprep/components/addquestionform.tsx +++ b/frontend/peerprep/components/addquestionform.tsx @@ -21,7 +21,7 @@ import { WysiMarkEditor } from "./wysimarkeditor"; import BoxIcon from "./boxicons"; import { capitalize, languages } from "@/utils/utils"; -import { complexityColorMap } from "@/app/questions-management/list/columns"; +import { complexityColorMap } from "@/app/(default)/questions-management/columns"; interface AddQuestionFormProps { initialTitle?: string; @@ -43,7 +43,7 @@ export default function AddQuestionForm({ initialTestCases = [{ input: "", output: "" }], }: AddQuestionFormProps) { const NEXT_PUBLIC_QUESTION_SERVICE_URL = env( - "NEXT_PUBLIC_QUESTION_SERVICE_URL", + "NEXT_PUBLIC_QUESTION_SERVICE_URL" ); const router = useRouter(); const { theme } = useTheme(); @@ -67,7 +67,7 @@ export default function AddQuestionForm({ const { data: categoryData, isLoading: categoryLoading } = useSWR( `${NEXT_PUBLIC_QUESTION_SERVICE_URL}/api/questions/categories/unique`, - fetcher, + fetcher ); const uniqueCategories = React.useMemo(() => { @@ -88,7 +88,7 @@ export default function AddQuestionForm({ // Handle removing a category const removeCategory = (category: string) => { setCategories((prevCategories) => - prevCategories.filter((cat) => cat !== category), + prevCategories.filter((cat) => cat !== category) ); }; @@ -117,7 +117,7 @@ export default function AddQuestionForm({ // Handle input change for test case const handleInputChange = ( index: number, - event: React.ChangeEvent, + event: React.ChangeEvent ) => { const updatedTestCases = [...testCases]; @@ -160,11 +160,11 @@ export default function AddQuestionForm({ !templateCode.trim() || !testCases.every( (testCase) => - testCase.input.trim() !== "" && testCase.output.trim() !== "", + testCase.input.trim() !== "" && testCase.output.trim() !== "" ) ) { setErrorMessage( - "Please fill in all the required fields before submitting.", + "Please fill in all the required fields before submitting." ); setErrorModalOpen(true); // Show error modal with the validation message @@ -179,7 +179,7 @@ export default function AddQuestionForm({ complexity: selectedTab, templateCode, testCases: testCases.map( - (testCase) => `${testCase.input} -> ${testCase.output}`, + (testCase) => `${testCase.input} -> ${testCase.output}` ), }; @@ -195,7 +195,7 @@ export default function AddQuestionForm({ "Content-Type": "application/json", }, body: JSON.stringify(formData), // Convert data to JSON - }, + } ); if (response.ok) { @@ -207,21 +207,21 @@ export default function AddQuestionForm({ const errorData = await response.json(); setErrorMessage( - errorData.error || "Failed to submit the question. Please try again.", + errorData.error || "Failed to submit the question. Please try again." ); setErrorModalOpen(true); } } catch (error) { // Show error modal with generic error message setErrorMessage( - "An error occurred while submitting the question. Please try again later", + "An error occurred while submitting the question. Please try again later" ); setErrorModalOpen(true); } }; const handleCancel = () => { - router.push("/"); + router.push("/questions-management"); }; return ( @@ -427,11 +427,11 @@ export default function AddQuestionForm({ message={successMessage} onConfirm={() => { setSuccessModalOpen(false); - router.push("/"); + router.push("/questions-management"); }} onOpenChange={() => { setSuccessModalOpen; - router.push("/"); + router.push("/questions-management"); }} /> (initialTestCases); const [questionToDelete, setQuestionToDelete] = useState( - null, + null ); const [question, setQuestion] = useState(null); const { data: categoryData, isLoading: categoryLoading } = useSWR( `${NEXT_PUBLIC_QUESTION_SERVICE_URL}/api/questions/categories/unique`, - fetcher, + fetcher ); const { data: questionData, isLoading: questionLoading } = useSWR( `${NEXT_PUBLIC_QUESTION_SERVICE_URL}/api/questions/${params.id ? params.id : ""}`, - fetcher, + fetcher ); useEffect(() => { @@ -101,8 +101,8 @@ export default function EditQuestionForm({ .map((str) => str.trim()); return { input, output }; - }), - ) || [], + }) + ) || [] ); setQuestion(questionData?.question); } @@ -146,7 +146,7 @@ export default function EditQuestionForm({ // Handle removing a category const removeCategory = (category: string) => { setCategories((prevCategories) => - prevCategories.filter((cat) => cat !== category), + prevCategories.filter((cat) => cat !== category) ); }; @@ -175,7 +175,7 @@ export default function EditQuestionForm({ // Handle input change for test case const handleInputChange = ( index: number, - event: React.ChangeEvent, + event: React.ChangeEvent ) => { const updatedTestCases = [...testCases]; const { name, value } = event.target; @@ -220,11 +220,11 @@ export default function EditQuestionForm({ !templateCode.trim() || !testCases.every( (testCase) => - testCase.input.trim() !== "" && testCase.output.trim() !== "", + testCase.input.trim() !== "" && testCase.output.trim() !== "" ) ) { setErrorMessage( - "Please fill in all the required fields before submitting.", + "Please fill in all the required fields before submitting." ); setErrorModalOpen(true); // Show error modal with the validation message @@ -238,7 +238,7 @@ export default function EditQuestionForm({ complexity: selectedTab, templateCode, testCases: testCases.map( - (testCase) => `${testCase.input} -> ${testCase.output}`, + (testCase) => `${testCase.input} -> ${testCase.output}` ), }; @@ -251,7 +251,7 @@ export default function EditQuestionForm({ "Content-Type": "application/json", }, body: JSON.stringify(formData), - }, + } ); if (response.ok) { @@ -261,7 +261,7 @@ export default function EditQuestionForm({ const errorData = await response.json(); setErrorMessage( - errorData.error || "Failed to update the question. Please try again.", + errorData.error || "Failed to update the question. Please try again." ); setErrorModalOpen(true); } @@ -278,7 +278,7 @@ export default function EditQuestionForm({ `${NEXT_PUBLIC_QUESTION_SERVICE_URL}/api/questions/${params.id}`, { method: "DELETE", - }, + } ); if (response.ok) { @@ -296,7 +296,7 @@ export default function EditQuestionForm({ }; const handleCancel = () => { - router.push("/"); + router.push("/questions-management"); }; return ( @@ -498,7 +498,7 @@ export default function EditQuestionForm({ router.push("/")} // Redirect to list after confirmation + onConfirm={() => router.push("/questions-management")} // Redirect to list after confirmation onOpenChange={setSuccessModalOpen} /> fetch(url).then((res) => res.json()); export default function QuestionsTable() { const NEXT_PUBLIC_QUESTION_SERVICE_URL = env( - "NEXT_PUBLIC_QUESTION_SERVICE_URL", + "NEXT_PUBLIC_QUESTION_SERVICE_URL" ); const router = useRouter(); const { isOpen, onOpen, onOpenChange } = useDisclosure(); const [questionToDelete, setQuestionToDelete] = useState( - null, + null ); const handleDelete = (question: Question) => { @@ -58,7 +58,7 @@ export default function QuestionsTable() { `${NEXT_PUBLIC_QUESTION_SERVICE_URL}/api/questions/${questionToDelete.question_id}`, { method: "DELETE", - }, + } ); onOpenChange(); location.reload(); @@ -88,12 +88,12 @@ export default function QuestionsTable() { .join("&") + "&" : "" }${`sort=${sortDescriptor.direction === "descending" ? "-" : ""}${sortDescriptor.column}&`}page=${page}`, - fetcher, + fetcher ); const { data: categoryData, isLoading: categoryLoading } = useSWR( `${NEXT_PUBLIC_QUESTION_SERVICE_URL}/api/questions/categories/unique`, - fetcher, + fetcher ); const uniqueCategories = React.useMemo(() => { diff --git a/frontend/peerprep/components/sidebar.tsx b/frontend/peerprep/components/sidebar.tsx index 7ce728e77d..712cfc49dc 100644 --- a/frontend/peerprep/components/sidebar.tsx +++ b/frontend/peerprep/components/sidebar.tsx @@ -1,57 +1,56 @@ "use client"; import { useTheme } from "next-themes"; -import { Listbox, ListboxItem } from "@nextui-org/listbox"; -import { Button } from "@nextui-org/react"; +import { Listbox, ListboxItem, ListboxSection } from "@nextui-org/listbox"; import BoxIcon from "./boxicons"; - +import { Button, Divider } from "@nextui-org/react"; import { siteConfig } from "@/config/site"; +import { usePathname } from "next/navigation"; export const Sidebar = () => { const { theme } = useTheme(); + const currentPath = usePathname(); return (
- {siteConfig.navItems - .map((item: any) => ( - - } - > - - {item.label} - - - )) - .concat( - + {siteConfig.navItems.map((item) => ( + + } + className="py-3 my-1" + href={item.href} + > + - Question Management - , - )} + {item.label} + + + ))} diff --git a/frontend/peerprep/config/site.ts b/frontend/peerprep/config/site.ts index d36b8ac0b7..56b4d01418 100644 --- a/frontend/peerprep/config/site.ts +++ b/frontend/peerprep/config/site.ts @@ -3,5 +3,16 @@ export type SiteConfig = typeof siteConfig; export const siteConfig = { name: "Next.js + NextUI", description: "Make beautiful websites regardless of your design experience.", - navItems: [], + navItems: [ + { + label: "Home", + href: "/home", + icon: "bxs-home", + }, + { + label: "Question Management", + href: "/questions-management", + icon: "bxs-message-square-edit" + }, + ], };