diff --git a/nextjs/src/app/api/courses/[courseName]/route.ts b/nextjs/src/app/api/courses/[courseName]/route.ts
new file mode 100644
index 0000000..66d0ab6
--- /dev/null
+++ b/nextjs/src/app/api/courses/[courseName]/route.ts
@@ -0,0 +1,14 @@
+import { fileStorageService } from "@/services/fileStorage/fileStorageService";
+
+export async function PUT(
+ request: Request,
+ { params: { courseName } }: { params: { courseName: string } }
+) {
+ const { updatedCourse, previousCourse } = await request.json();
+
+ console.log(updatedCourse);
+ console.log(courseName);
+
+ await fileStorageService.saveCourseAsync(updatedCourse, previousCourse);
+ return Response.json({});
+}
diff --git a/nextjs/src/app/course/[courseName]/calendar/Day.tsx b/nextjs/src/app/course/[courseName]/calendar/Day.tsx
index a7dff0e..e640758 100644
--- a/nextjs/src/app/course/[courseName]/calendar/Day.tsx
+++ b/nextjs/src/app/course/[courseName]/calendar/Day.tsx
@@ -4,12 +4,17 @@ import { getDateFromStringOrThrow } from "@/models/local/timeUtils";
import { useCourseContext } from "../context/courseContext";
export default function Day({ day, month }: { day: Date; month: number }) {
- const context = useCourseContext();
+ const {
+ localCourse: { modules },
+ startItemDrag,
+ endItemDrag,
+ itemDrop,
+ } = useCourseContext();
const isInSameMonth = day.getMonth() + 1 != month;
const backgroundClass = isInSameMonth ? "" : "bg-slate-900";
- const todaysAssignments = context.localCourse.modules
+ const todaysAssignments = modules
.flatMap((m) => m.assignments)
.filter((a) => {
const dueDate = getDateFromStringOrThrow(
@@ -22,7 +27,7 @@ export default function Day({ day, month }: { day: Date; month: number }) {
dueDate.getDate() === day.getDate()
);
});
- const todaysQuizzes = context.localCourse.modules
+ const todaysQuizzes = modules
.flatMap((m) => m.quizzes)
.filter((q) => {
const dueDate = getDateFromStringOrThrow(
@@ -35,7 +40,7 @@ export default function Day({ day, month }: { day: Date; month: number }) {
dueDate.getDate() === day.getDate()
);
});
- const todaysPages = context.localCourse.modules
+ const todaysPages = modules
.flatMap((m) => m.pages)
.filter((p) => {
const dueDate = getDateFromStringOrThrow(
@@ -53,17 +58,34 @@ export default function Day({ day, month }: { day: Date; month: number }) {
className={
"border border-slate-600 rounded-lg p-2 pb-4 m-1 " + backgroundClass
}
+ onDrop={() => itemDrop(day)}
+ onDragOver={(e) => e.preventDefault()}
>
{day.getDate()}
{todaysAssignments.map((a) => (
- - {a.name}
+ - {a.name}
))}
{todaysQuizzes.map((q) => (
- - {q.name}
+ - startItemDrag({ type: "quiz", item: q })}
+ onDragEnd={endItemDrag}
+ >
+ {q.name}
+
))}
{todaysPages.map((p) => (
- - {p.name}
+ - startItemDrag({ type: "page", item: p })}
+ >
+ {p.name}
+
))}
diff --git a/nextjs/src/app/course/[courseName]/context/CourseContextProvider.tsx b/nextjs/src/app/course/[courseName]/context/CourseContextProvider.tsx
index 17e3481..c3ebe64 100644
--- a/nextjs/src/app/course/[courseName]/context/CourseContextProvider.tsx
+++ b/nextjs/src/app/course/[courseName]/context/CourseContextProvider.tsx
@@ -1,7 +1,13 @@
"use client";
import { ReactNode, useState } from "react";
import { CourseContext, DraggableItem } from "./courseContext";
-import { useLocalCourseDetailsQuery } from "@/hooks/localCoursesHooks";
+import {
+ useLocalCourseDetailsQuery,
+ useUpdateCourseMutation,
+} from "@/hooks/localCoursesHooks";
+import { LocalQuiz } from "@/models/local/quiz/localQuiz";
+import { LocalCourse } from "@/models/local/localCourse";
+import { dateToMarkdownString } from "@/models/local/timeUtils";
export default function CourseContextProvider({
localCourseName,
@@ -11,15 +17,59 @@ export default function CourseContextProvider({
localCourseName: string;
}) {
const { data: course } = useLocalCourseDetailsQuery(localCourseName);
+ const updateCourseMutation = useUpdateCourseMutation(course.settings.name);
const [itemBeingDragged, setItemBeingDragged] = useState<
DraggableItem | undefined
>();
+
return (
setItemBeingDragged(d),
- stopModuleDrag: (day) => setItemBeingDragged(undefined),
+ startItemDrag: (d) => {
+ console.log("starting drag");
+ setItemBeingDragged(d);
+ },
+ endItemDrag: () => {
+ console.log("stopping drag");
+ setItemBeingDragged(undefined);
+ },
+ itemDrop: (day) => {
+ console.log("dropping");
+ if (itemBeingDragged && day) {
+ if (itemBeingDragged.type === "quiz") {
+ const updatedQuiz: LocalQuiz = {
+ ...(itemBeingDragged.item as LocalQuiz),
+ dueAt: dateToMarkdownString(day),
+ };
+
+ const localModule = course.modules.find((m) =>
+ m.quizzes.map((q) => q.name).includes(updatedQuiz.name)
+ );
+ if (!localModule)
+ console.log("could not find module for quiz ", updatedQuiz);
+
+ const updatedCourse: LocalCourse = {
+ ...course,
+ modules: course.modules.map((m) =>
+ m.name !== localModule?.name
+ ? m
+ : {
+ ...m,
+ quizzes: m.quizzes.map((q) =>
+ q.name === updatedQuiz.name ? updatedQuiz : q
+ ),
+ }
+ ),
+ };
+ updateCourseMutation.mutate({
+ updatedCourse,
+ previousCourse: course,
+ });
+ }
+ }
+ setItemBeingDragged(undefined);
+ },
}}
>
{children}
diff --git a/nextjs/src/app/course/[courseName]/context/courseContext.ts b/nextjs/src/app/course/[courseName]/context/courseContext.ts
index a353f43..e1383e4 100644
--- a/nextjs/src/app/course/[courseName]/context/courseContext.ts
+++ b/nextjs/src/app/course/[courseName]/context/courseContext.ts
@@ -10,8 +10,9 @@ export interface DraggableItem {
export interface CourseContextInterface {
localCourse: LocalCourse;
- startModuleDrag: (dragging: DraggableItem) => void;
- stopModuleDrag: (droppedOnDay?: Date) => void;
+ startItemDrag: (dragging: DraggableItem) => void;
+ endItemDrag: () => void;
+ itemDrop: (droppedOnDay?: Date) => void;
}
const defaultValue: CourseContextInterface = {
@@ -29,10 +30,9 @@ const defaultValue: CourseContextInterface = {
},
},
},
- startModuleDrag: () => { },
- stopModuleDrag: function (droppedOnDay?: Date): void {
- throw new Error("Function not implemented.");
- }
+ startItemDrag: () => {},
+ endItemDrag: () => {},
+ itemDrop: () => {},
};
export const CourseContext =
diff --git a/nextjs/src/hooks/localCoursesHooks.ts b/nextjs/src/hooks/localCoursesHooks.ts
index 97a54c0..608d1f6 100644
--- a/nextjs/src/hooks/localCoursesHooks.ts
+++ b/nextjs/src/hooks/localCoursesHooks.ts
@@ -1,5 +1,10 @@
import { LocalCourse } from "@/models/local/localCourse";
-import { useSuspenseQuery } from "@tanstack/react-query";
+import {
+ dataTagSymbol,
+ useMutation,
+ useQueryClient,
+ useSuspenseQuery,
+} from "@tanstack/react-query";
import axios from "axios";
export const localCourseKeys = {
@@ -32,3 +37,22 @@ export const useLocalCourseDetailsQuery = (courseName: string) => {
},
});
};
+
+export const useUpdateCourseMutation = (courseName: string) => {
+ const queryClient = useQueryClient();
+ return useMutation({
+ mutationFn: async (body: {
+ updatedCourse: LocalCourse;
+ previousCourse: LocalCourse;
+ }) => {
+ const url = `/api/courses/${courseName}`;
+ await axios.put(url, body);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: localCourseKeys.allCourses }); //optimize?
+ },
+ scope: {
+ id: "update course",
+ },
+ });
+};