diff --git a/app/organisation/page.tsx b/app/organisation/page.tsx index ec9c8db..64f169d 100644 --- a/app/organisation/page.tsx +++ b/app/organisation/page.tsx @@ -1,8 +1,31 @@ +"use client"; + +import { useAuth } from "@/context/AuthContext"; +import ManageTags from "@/components/organisation/settings/ManageTags"; + export default function OrganisationsPage() { + const { user } = useAuth(); + if (!user || !user.hasCompletedOnboarding) { + return null; + } + + const isAdmin = user?.organisation?.role === "admin"; + + if (!isAdmin) { + return ( +
+

My Organisation

+

You do not have permission to access this page.

+
+ ); + } + return (
-

Organisations

-

List of organisations will be displayed here.

+

+ My Organisation +

+
); } diff --git a/app/reports/page.tsx b/app/reports/page.tsx index 8fc852e..1e47814 100644 --- a/app/reports/page.tsx +++ b/app/reports/page.tsx @@ -1,8 +1,30 @@ +"use client"; + +import BasicReport from "@/components/reports/BasicReport"; +import { useAuth } from "@/context/AuthContext"; +import AdminBasicReport from "@/components/reports/AdminBasicReport"; + export default function ReportsPage() { + const { user } = useAuth(); + if (!user || !user.hasCompletedOnboarding) { + return null; + } + + const isAdmin = user?.organisation?.role === "admin"; + + if (isAdmin) { + return ( +
+

Reports

+ +
+ ); + } + return ( -
-

Reports

-

List of reports will be displayed here.

+
+

Reports

+
); } diff --git a/components/organisation/courses/CourseCard.tsx b/components/organisation/courses/CourseCard.tsx index 9d47288..ba75070 100644 --- a/components/organisation/courses/CourseCard.tsx +++ b/components/organisation/courses/CourseCard.tsx @@ -2,12 +2,18 @@ import Link from "next/link"; +export interface Tag { + id: number; + name: string; +} + export interface Course { id: number; name: string; description?: string; total_modules?: number; completed_modules?: number; + tags?: Tag[]; } interface Props { @@ -112,6 +118,19 @@ export default function CourseCard({

{course.name}

{course.description?.slice(0, 100)}

+ {course.tags && course.tags.length > 0 && ( +
+ {course.tags.map((t) => ( + + {t.name} + + ))} +
+ )} + {!isAdmin && isEnrolled && (

Progress:{" "} diff --git a/components/organisation/courses/CourseForm.tsx b/components/organisation/courses/CourseForm.tsx index b3353c2..19a9525 100644 --- a/components/organisation/courses/CourseForm.tsx +++ b/components/organisation/courses/CourseForm.tsx @@ -1,14 +1,23 @@ // components/organisation/courses/CourseForm.tsx "use client"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; -import { useEffect } from "react"; +import Select from "react-select"; export interface Course { id: number; name: string; description?: string; + tags?: { id: number; name: string }[]; +} +interface Tag { + id: number; + name: string; +} +interface Option { + value: number; + label: string; } interface Props { @@ -19,121 +28,88 @@ interface Props { export default function CourseForm({ mode, courseId }: Props) { const [name, setName] = useState(""); const [description, setDescription] = useState(""); + const [allTags, setAllTags] = useState([]); + const [options, setOptions] = useState([]); + const [selected, setSelected] = useState([]); const router = useRouter(); useEffect(() => { - async function fetchCourse() { - const response = await fetch( - `http://localhost:4000/api/courses/get-course`, - { - credentials: "include", - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ courseId }), - } - ).then((res) => { - if (!res.ok) { - throw new Error("Failed to fetch course"); - } - return res.json(); - }); - setName(response.name); - setDescription(response.description || ""); - } + fetch("/api/courses/tags", { credentials: "include" }) + .then((r) => r.json()) + .then((tags: Tag[]) => { + setAllTags(tags); + setOptions(tags.map((t) => ({ value: t.id, label: t.name }))); + }) + .catch(console.error); + if (mode === "edit" && courseId) { - // Fetch course details if in edit mode - fetchCourse().catch((error) => { - console.error("Error fetching course:", error); - alert("Failed to load course data. Please try again."); - router.push("/courses"); - }); + fetch("/api/courses/get-course", { + method: "POST", + credentials: "include", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ courseId }), + }) + .then((r) => { + if (!r.ok) throw new Error(); + return r.json(); + }) + .then((course: Course) => { + setName(course.name); + setDescription(course.description || ""); + const pre = (course.tags || []).map((t) => ({ + value: t.id, + label: t.name, + })); + setSelected(pre); + }) + .catch((_) => { + alert("Failed to load course"); + router.push("/courses"); + }); } - }, []); + }, [mode, courseId, router]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - const payload = { courseName: name, description }; - - if (mode === "create") { - try { - const res = await fetch("/api/courses", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - credentials: "include", - body: JSON.stringify(payload), - }); - if (!res.ok) { - throw new Error("Failed to create course"); - } - const data = await res.json(); - console.log("Course created:", data); - router.push("/courses"); - } catch (error) { - console.error("Error creating course:", error); - alert("Failed to create course. Please try again."); - return; - } - } else { - try { - const res = await fetch("/api/courses", { - method: "PUT", - headers: { - "Content-Type": "application/json", - }, - credentials: "include", - body: JSON.stringify({ courseId: courseId, ...payload }), - }); - if (!res.ok) { - throw new Error("Failed to update course"); - } - const data = await res.json(); - console.log("Course updated:", data); - router.push("/courses"); - } catch (error) { - console.error("Error creating course:", error); - alert("Failed to update course. Please try again."); - return; - } - } - }; + const tags = selected.map((o) => o.value); + const payload = { + courseName: name, + description, + tags, + updateTags: mode === "edit", + }; - const handleDelete = async (e: React.FormEvent) => { - e.preventDefault(); + const url = "/api/courses"; + const method = mode === "create" ? "POST" : "PUT"; + const body = mode === "create" ? payload : { courseId, ...payload }; - const confirmed = window.confirm( - "Are you sure you want to delete this course? This action cannot be undone." - ); - if (!confirmed) { - return; - } - if (!courseId) { - alert("Please provide a course name to delete."); + const res = await fetch(url, { + method, + credentials: "include", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + }); + if (!res.ok) { + alert(`${mode === "create" ? "Create" : "Update"} failed`); return; } - try { - const res = await fetch(`/api/courses`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - credentials: "include", - body: JSON.stringify({ courseId: courseId }), - }); - if (!res.ok) { - throw new Error("Failed to delete course"); - } - const data = await res.json(); - console.log("Course deleted:", data); - router.push("/courses"); - } catch (error) { - console.error("Error deleting course:", error); - alert("Failed to delete course. Please try again."); + router.push("/courses"); + }; + + const handleDelete = async () => { + if (!confirm("Are you sure?")) return; + if (!courseId) return; + const res = await fetch("/api/courses", { + method: "DELETE", + credentials: "include", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ courseId }), + }); + if (!res.ok) { + alert("Delete failed"); return; } + router.push("/courses"); }; return ( @@ -154,10 +130,21 @@ export default function CourseForm({ mode, courseId }: Props) {