diff --git a/Management/Features/Configuration/Synchronization/AssignmentSyncronizationExtensions.cs b/Management/Features/Configuration/Synchronization/AssignmentSyncronizationExtensions.cs
index 3250a7c..7a4b114 100644
--- a/Management/Features/Configuration/Synchronization/AssignmentSyncronizationExtensions.cs
+++ b/Management/Features/Configuration/Synchronization/AssignmentSyncronizationExtensions.cs
@@ -73,6 +73,7 @@ public static partial class AssignmentSyncronizationExtensions
var reason = localAssignment.GetUpdateReason(canvasAssignment, canvasAssignmentGroupId, quiet);
return reason != string.Empty;
}
+
public static string GetUpdateReason(
this LocalAssignment localAssignment,
CanvasAssignment canvasAssignment,
diff --git a/nextjs/src/app/course/[courseName]/calendar/CalendarMonth.tsx b/nextjs/src/app/course/[courseName]/calendar/CalendarMonth.tsx
index ae07bb7..d045ef8 100644
--- a/nextjs/src/app/course/[courseName]/calendar/CalendarMonth.tsx
+++ b/nextjs/src/app/course/[courseName]/calendar/CalendarMonth.tsx
@@ -2,7 +2,7 @@
import { useState } from "react";
import { CalendarMonthModel } from "./calendarMonthUtils";
import { DayOfWeek } from "@/models/local/localCourse";
-import Day from "./Day";
+import Day from "./day/Day";
export const CalendarMonth = ({ month }: { month: CalendarMonthModel }) => {
const weekInMilliseconds = 604_800_000;
diff --git a/nextjs/src/app/course/[courseName]/calendar/Day.tsx b/nextjs/src/app/course/[courseName]/calendar/Day.tsx
deleted file mode 100644
index 7f178da..0000000
--- a/nextjs/src/app/course/[courseName]/calendar/Day.tsx
+++ /dev/null
@@ -1,307 +0,0 @@
-"use client";
-import {
- dateToMarkdownString,
- getDateFromStringOrThrow,
- getDateOnlyMarkdownString,
-} from "@/models/local/timeUtils";
-import { DraggableItem, useDraggingContext } from "../context/draggingContext";
-import { useCalendarItemsContext } from "../context/calendarItemsContext";
-import { useCourseContext } from "../context/courseContext";
-import Link from "next/link";
-import { IModuleItem } from "@/models/local/IModuleItem";
-import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
-import { getDayOfWeek } from "@/models/local/localCourse";
-import { getLectureUrl, getModuleItemUrl } from "@/services/urlUtils";
-import { LocalAssignment } from "@/models/local/assignment/localAssignment";
-import { LocalQuiz } from "@/models/local/quiz/localQuiz";
-import { LocalCoursePage } from "@/models/local/page/localCoursePage";
-import { useCanvasAssignmentsQuery } from "@/hooks/canvas/canvasAssignmentHooks";
-import { useCanvasQuizzesQuery } from "@/hooks/canvas/canvasQuizHooks";
-import { useCanvasPagesQuery } from "@/hooks/canvas/canvasPageHooks";
-import DropTargetStyling from "./DropTargetStyling";
-import { CanvasQuiz } from "@/models/canvas/quizzes/canvasQuizModel";
-import { CanvasAssignment } from "@/models/canvas/assignments/canvasAssignment";
-import { CanvasPage } from "@/models/canvas/pages/canvasPageModel";
-import { canvasService } from "@/services/canvas/canvasService";
-import { ReactNode } from "react";
-
-export default function Day({ day, month }: { day: string; month: number }) {
- const dayAsDate = getDateFromStringOrThrow(
- day,
- "calculating same month in day"
- );
- const isToday =
- getDateOnlyMarkdownString(new Date()) ===
- getDateOnlyMarkdownString(dayAsDate);
-
- const { data: settings } = useLocalCourseSettingsQuery();
- const { itemDropOnDay } = useDraggingContext();
-
- const { todaysAssignments, todaysQuizzes, todaysPages } = useTodaysItems(day);
-
- const isInSameMonth = dayAsDate.getMonth() + 1 == month;
-
- const classOnThisDay = settings.daysOfWeek.includes(getDayOfWeek(dayAsDate));
-
- const meetingClasses = classOnThisDay ? " bg-slate-900 " : " ";
- const monthClass = isInSameMonth
- ? isToday
- ? " border border-blue-700 shadow-[0_0px_10px_0px] shadow-blue-500/50 "
- : " border border-slate-700 "
- : " ";
-
- return (
-
itemDropOnDay(e, day)}
- onDragOver={(e) => e.preventDefault()}
- >
-
-
-
- {todaysAssignments.map(
- ({ assignment, moduleName, status, message }) => (
-
- )
- )}
- {todaysQuizzes.map(({ quiz, moduleName, status, message }) => (
-
- ))}
- {todaysPages.map(({ page, moduleName, status, message }) => (
-
- ))}
-
-
-
- );
-}
-
-function DayTitle({ day, dayAsDate }: { day: string; dayAsDate: Date }) {
- const { courseName } = useCourseContext();
- return (
-
- {dayAsDate.getDate()}
-
- );
-}
-
-function useTodaysItems(day: string) {
- const dayAsDate = getDateFromStringOrThrow(
- day,
- "calculating same month in day items"
- );
- const itemsContext = useCalendarItemsContext();
- const dateKey = getDateOnlyMarkdownString(dayAsDate);
- const todaysModules = itemsContext[dateKey];
-
- const { data: canvasAssignments } = useCanvasAssignmentsQuery();
- const { data: canvasQuizzes } = useCanvasQuizzesQuery();
- const { data: canvasPages } = useCanvasPagesQuery();
- const todaysAssignments: {
- moduleName: string;
- assignment: LocalAssignment;
- status: "localOnly" | "incomplete" | "published";
- message: ReactNode;
- }[] = todaysModules
- ? Object.keys(todaysModules).flatMap((moduleName) =>
- todaysModules[moduleName].assignments.map((assignment) => {
- const canvasAssignment = canvasAssignments.find(
- (c) => c.name === assignment.name
- );
- return {
- moduleName,
- assignment,
- ...getStatus({
- item: assignment,
- canvasItem: canvasAssignment,
- type: "assignment",
- }),
- };
- })
- )
- : [];
-
- const todaysQuizzes: {
- moduleName: string;
- quiz: LocalQuiz;
- status: "localOnly" | "incomplete" | "published";
- message: string;
- }[] = todaysModules
- ? Object.keys(todaysModules).flatMap((moduleName) =>
- todaysModules[moduleName].quizzes.map((quiz) => {
- const canvasQuiz = canvasQuizzes.find((q) => q.title === quiz.name);
- return {
- moduleName,
- quiz,
- status: canvasQuiz
- ? canvasQuiz.published
- ? "published"
- : "incomplete"
- : "localOnly",
- message: "",
- };
- })
- )
- : [];
-
- const todaysPages: {
- moduleName: string;
- page: LocalCoursePage;
- status: "localOnly" | "incomplete" | "published";
- message: string;
- }[] = todaysModules
- ? Object.keys(todaysModules).flatMap((moduleName) =>
- todaysModules[moduleName].pages.map((page) => {
- const canvasPage = canvasPages.find((p) => p.title === page.name);
- return {
- moduleName,
- page,
- status: canvasPage
- ? canvasPage.published
- ? "published"
- : "incomplete"
- : "localOnly",
- message: "",
- };
- })
- )
- : [];
- return { todaysAssignments, todaysQuizzes, todaysPages };
-}
-
-function DraggableListItem({
- type,
- moduleName,
- status,
- item,
- message,
-}: {
- type: "assignment" | "page" | "quiz";
- status: "localOnly" | "incomplete" | "published";
- moduleName: string;
- item: IModuleItem;
- message: ReactNode;
-}) {
- const { courseName } = useCourseContext();
- const { dragStart } = useDraggingContext();
- return (
- {
- const draggableItem: DraggableItem = {
- type,
- item,
- sourceModuleName: moduleName,
- };
- e.dataTransfer.setData("draggableItem", JSON.stringify(draggableItem));
- dragStart();
- }}
- >
- {item.name}
- {status === "incomplete" && (
-
- {message}
-
- )}
-
- );
-}
-
-const getStatus = ({
- item,
- canvasItem,
- type,
-}: {
- item: LocalQuiz | LocalAssignment | LocalCoursePage;
- canvasItem?: CanvasQuiz | CanvasAssignment | CanvasPage;
- type: "assignment" | "page" | "quiz";
-}): {
- status: "localOnly" | "incomplete" | "published";
- message: ReactNode;
-} => {
- if (!canvasItem) return { status: "localOnly", message: "not in canvas" };
-
- if (!canvasItem.published)
- return { status: "incomplete", message: "not published in canvas" };
-
- if (type === "assignment") {
- const assignment = item as LocalAssignment;
- const canvasAssignment = canvasItem as CanvasAssignment;
-
- if(canvasAssignment.name === "Javascript 1")
- console.log('js 1', canvasAssignment.due_at, canvasAssignment);
-
-
- if (!canvasAssignment.due_at)
- return { status: "incomplete", message: "due date not in canvas" };
-
- if (assignment.lockAt && !canvasAssignment.lock_at)
- return { status: "incomplete", message: "lock date not in canvas" };
-
- const localDueDate = dateToMarkdownString(
- getDateFromStringOrThrow(assignment.dueAt, "comparing due dates for day")
- );
- const canvasDueDate = dateToMarkdownString(
- getDateFromStringOrThrow(
- canvasAssignment.due_at,
- "comparing canvas due date for day"
- )
- );
- if (localDueDate !== canvasDueDate) {
- return {
- status: "incomplete",
- message: (
-
- due date different
-
{localDueDate}
-
{canvasDueDate}
-
- ),
- };
- }
- }
-
- return { status: "published", message: "" };
-};
diff --git a/nextjs/src/app/course/[courseName]/calendar/day/Day.tsx b/nextjs/src/app/course/[courseName]/calendar/day/Day.tsx
new file mode 100644
index 0000000..07cea3b
--- /dev/null
+++ b/nextjs/src/app/course/[courseName]/calendar/day/Day.tsx
@@ -0,0 +1,95 @@
+"use client";
+import {
+ getDateFromStringOrThrow,
+ getDateOnlyMarkdownString,
+} from "@/models/local/timeUtils";
+import { useDraggingContext } from "../../context/draggingContext";
+import { useCourseContext } from "../../context/courseContext";
+import Link from "next/link";
+import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
+import { getDayOfWeek } from "@/models/local/localCourse";
+import { getLectureUrl } from "@/services/urlUtils";
+import DropTargetStyling from "../DropTargetStyling";
+import { DraggableListItem } from "./DraggableListItem";
+import { useTodaysItems } from "./useTodaysItems";
+
+export default function Day({ day, month }: { day: string; month: number }) {
+ const dayAsDate = getDateFromStringOrThrow(
+ day,
+ "calculating same month in day"
+ );
+ const isToday =
+ getDateOnlyMarkdownString(new Date()) ===
+ getDateOnlyMarkdownString(dayAsDate);
+
+ const { data: settings } = useLocalCourseSettingsQuery();
+ const { itemDropOnDay } = useDraggingContext();
+
+ const { todaysAssignments, todaysQuizzes, todaysPages } = useTodaysItems(day);
+
+ const isInSameMonth = dayAsDate.getMonth() + 1 == month;
+
+ const classOnThisDay = settings.daysOfWeek.includes(getDayOfWeek(dayAsDate));
+
+ const meetingClasses = classOnThisDay ? " bg-slate-900 " : " ";
+ const monthClass = isInSameMonth
+ ? isToday
+ ? " border border-blue-700 shadow-[0_0px_10px_0px] shadow-blue-500/50 "
+ : " border border-slate-700 "
+ : " ";
+
+ return (
+ itemDropOnDay(e, day)}
+ onDragOver={(e) => e.preventDefault()}
+ >
+
+
+
+ {todaysAssignments.map(
+ ({ assignment, moduleName, status, message }) => (
+
+ )
+ )}
+ {todaysQuizzes.map(({ quiz, moduleName, status, message }) => (
+
+ ))}
+ {todaysPages.map(({ page, moduleName, status, message }) => (
+
+ ))}
+
+
+
+ );
+}
+
+function DayTitle({ day, dayAsDate }: { day: string; dayAsDate: Date }) {
+ const { courseName } = useCourseContext();
+ return (
+
+ {dayAsDate.getDate()}
+
+ );
+}
diff --git a/nextjs/src/app/course/[courseName]/calendar/day/DraggableListItem.tsx b/nextjs/src/app/course/[courseName]/calendar/day/DraggableListItem.tsx
new file mode 100644
index 0000000..daa4b19
--- /dev/null
+++ b/nextjs/src/app/course/[courseName]/calendar/day/DraggableListItem.tsx
@@ -0,0 +1,65 @@
+import { IModuleItem } from "@/models/local/IModuleItem";
+import { getModuleItemUrl } from "@/services/urlUtils";
+import Link from "next/link";
+import { ReactNode } from "react";
+import { useCourseContext } from "../../context/courseContext";
+import { useDraggingContext, DraggableItem } from "../../context/draggingContext";
+
+export function DraggableListItem({
+ type,
+ moduleName,
+ status,
+ item,
+ message,
+}: {
+ type: "assignment" | "page" | "quiz";
+ status: "localOnly" | "incomplete" | "published";
+ moduleName: string;
+ item: IModuleItem;
+ message: ReactNode;
+}) {
+ const { courseName } = useCourseContext();
+ const { dragStart } = useDraggingContext();
+ return (
+ {
+ const draggableItem: DraggableItem = {
+ type,
+ item,
+ sourceModuleName: moduleName,
+ };
+ e.dataTransfer.setData("draggableItem", JSON.stringify(draggableItem));
+ dragStart();
+ }}
+ >
+ {item.name}
+ {status === "incomplete" && (
+
+ {message}
+
+ )}
+
+ );
+}
diff --git a/nextjs/src/app/course/[courseName]/calendar/day/getStatus.tsx b/nextjs/src/app/course/[courseName]/calendar/day/getStatus.tsx
new file mode 100644
index 0000000..86624e7
--- /dev/null
+++ b/nextjs/src/app/course/[courseName]/calendar/day/getStatus.tsx
@@ -0,0 +1,106 @@
+"use client";
+import { CanvasAssignment } from "@/models/canvas/assignments/canvasAssignment";
+import { CanvasPage } from "@/models/canvas/pages/canvasPageModel";
+import { CanvasQuiz } from "@/models/canvas/quizzes/canvasQuizModel";
+import { LocalAssignment } from "@/models/local/assignment/localAssignment";
+import { LocalCoursePage } from "@/models/local/page/localCoursePage";
+import { LocalQuiz } from "@/models/local/quiz/localQuiz";
+import {
+ dateToMarkdownString,
+ getDateFromStringOrThrow,
+} from "@/models/local/timeUtils";
+import { ReactNode } from "react";
+
+export const getStatus = ({
+ item,
+ canvasItem,
+ type,
+}: {
+ item: LocalQuiz | LocalAssignment | LocalCoursePage;
+ canvasItem?: CanvasQuiz | CanvasAssignment | CanvasPage;
+ type: "assignment" | "page" | "quiz";
+}): {
+ status: "localOnly" | "incomplete" | "published";
+ message: ReactNode;
+} => {
+ if (!canvasItem) return { status: "localOnly", message: "not in canvas" };
+
+ if (!canvasItem.published)
+ return { status: "incomplete", message: "not published in canvas" };
+
+ if (type === "page") {
+ const canvasPage = canvasItem as CanvasPage;
+ const page = item as LocalCoursePage;
+
+ if (!canvasPage.published)
+ return { status: "incomplete", message: "canvas page not published" };
+ return { status: "published", message: "" };
+ } else if (type === "quiz") {
+ const quiz = item as LocalQuiz;
+ const canvasQuiz = canvasItem as CanvasQuiz
+
+
+ if (!canvasQuiz.due_at)
+ return { status: "incomplete", message: "due date not in canvas" };
+
+ if (quiz.lockAt && !canvasQuiz.lock_at)
+ return { status: "incomplete", message: "lock date not in canvas" };
+
+ const localDueDate = dateToMarkdownString(
+ getDateFromStringOrThrow(quiz.dueAt, "comparing due dates for day")
+ );
+
+ const canvasDueDate = dateToMarkdownString(
+ getDateFromStringOrThrow(
+ canvasQuiz.due_at,
+ "comparing canvas due date for day"
+ )
+ );
+ if (localDueDate !== canvasDueDate) {
+ return {
+ status: "incomplete",
+ message: (
+
+ due date different
+
{localDueDate}
+
{canvasDueDate}
+
+ ),
+ };
+ }
+
+ } else if (type === "assignment") {
+ const assignment = item as LocalAssignment;
+ const canvasAssignment = canvasItem as CanvasAssignment;
+
+ if (!canvasAssignment.due_at)
+ return { status: "incomplete", message: "due date not in canvas" };
+
+ if (assignment.lockAt && !canvasAssignment.lock_at)
+ return { status: "incomplete", message: "lock date not in canvas" };
+
+ const localDueDate = dateToMarkdownString(
+ getDateFromStringOrThrow(assignment.dueAt, "comparing due dates for day")
+ );
+ const canvasDueDate = dateToMarkdownString(
+ getDateFromStringOrThrow(
+ canvasAssignment.due_at,
+ "comparing canvas due date for day"
+ )
+ );
+ if (localDueDate !== canvasDueDate) {
+ return {
+ status: "incomplete",
+ message: (
+
+ due date different
+
{localDueDate}
+
{canvasDueDate}
+
+ ),
+ };
+ }
+ }
+
+ return { status: "published", message: "" };
+};
diff --git a/nextjs/src/app/course/[courseName]/calendar/day/useTodaysItems.tsx b/nextjs/src/app/course/[courseName]/calendar/day/useTodaysItems.tsx
new file mode 100644
index 0000000..614886a
--- /dev/null
+++ b/nextjs/src/app/course/[courseName]/calendar/day/useTodaysItems.tsx
@@ -0,0 +1,96 @@
+"use client";
+import { useCanvasAssignmentsQuery } from "@/hooks/canvas/canvasAssignmentHooks";
+import { useCanvasPagesQuery } from "@/hooks/canvas/canvasPageHooks";
+import { useCanvasQuizzesQuery } from "@/hooks/canvas/canvasQuizHooks";
+import { LocalAssignment } from "@/models/local/assignment/localAssignment";
+import { LocalCoursePage } from "@/models/local/page/localCoursePage";
+import { LocalQuiz } from "@/models/local/quiz/localQuiz";
+import {
+ getDateFromStringOrThrow,
+ getDateOnlyMarkdownString,
+} from "@/models/local/timeUtils";
+import { ReactNode } from "react";
+import { useCalendarItemsContext } from "../../context/calendarItemsContext";
+import { getStatus } from "./getStatus";
+
+export function useTodaysItems(day: string) {
+ const dayAsDate = getDateFromStringOrThrow(
+ day,
+ "calculating same month in day items"
+ );
+ const itemsContext = useCalendarItemsContext();
+ const dateKey = getDateOnlyMarkdownString(dayAsDate);
+ const todaysModules = itemsContext[dateKey];
+
+ const { data: canvasAssignments } = useCanvasAssignmentsQuery();
+ const { data: canvasQuizzes } = useCanvasQuizzesQuery();
+ const { data: canvasPages } = useCanvasPagesQuery();
+ const todaysAssignments: {
+ moduleName: string;
+ assignment: LocalAssignment;
+ status: "localOnly" | "incomplete" | "published";
+ message: ReactNode;
+ }[] = todaysModules
+ ? Object.keys(todaysModules).flatMap((moduleName) =>
+ todaysModules[moduleName].assignments.map((assignment) => {
+ const canvasAssignment = canvasAssignments.find(
+ (c) => c.name === assignment.name
+ );
+ return {
+ moduleName,
+ assignment,
+ ...getStatus({
+ item: assignment,
+ canvasItem: canvasAssignment,
+ type: "assignment",
+ }),
+ };
+ })
+ )
+ : [];
+
+ const todaysQuizzes: {
+ moduleName: string;
+ quiz: LocalQuiz;
+ status: "localOnly" | "incomplete" | "published";
+ message: ReactNode;
+ }[] = todaysModules
+ ? Object.keys(todaysModules).flatMap((moduleName) =>
+ todaysModules[moduleName].quizzes.map((quiz) => {
+ const canvasQuiz = canvasQuizzes.find((q) => q.title === quiz.name);
+ return {
+ moduleName,
+ quiz,
+ ...getStatus({
+ item: quiz,
+ canvasItem: canvasQuiz,
+ type: "quiz",
+ }),
+ };
+ })
+ )
+ : [];
+
+ const todaysPages: {
+ moduleName: string;
+ page: LocalCoursePage;
+ status: "localOnly" | "incomplete" | "published";
+ message: ReactNode;
+ }[] = todaysModules
+ ? Object.keys(todaysModules).flatMap((moduleName) =>
+ todaysModules[moduleName].pages.map((page) => {
+ const canvasPage = canvasPages.find((p) => p.title === page.name);
+ return {
+ moduleName,
+ page,
+ ...getStatus({
+ item: page,
+ canvasItem: canvasPage,
+ type: "page",
+ }),
+ };
+ })
+ )
+ : [];
+ return { todaysAssignments, todaysQuizzes, todaysPages };
+}