From 32b211c9b2baca7f7b4b1136eac999d957d6e405 Mon Sep 17 00:00:00 2001 From: Alex Mickelson Date: Fri, 20 Sep 2024 13:36:01 -0600 Subject: [PATCH] working with canvas datetime format --- .../app/course/[courseName]/calendar/Day.tsx | 65 +++++++++++++++---- .../src/models/local/tests/timeUtils.test.ts | 9 +++ nextjs/src/models/local/timeUtils.ts | 14 ++-- 3 files changed, 69 insertions(+), 19 deletions(-) diff --git a/nextjs/src/app/course/[courseName]/calendar/Day.tsx b/nextjs/src/app/course/[courseName]/calendar/Day.tsx index a8b295a..8500a5b 100644 --- a/nextjs/src/app/course/[courseName]/calendar/Day.tsx +++ b/nextjs/src/app/course/[courseName]/calendar/Day.tsx @@ -18,6 +18,10 @@ 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"; export default function Day({ day, month }: { day: string; month: number }) { const dayAsDate = getDateFromStringOrThrow( @@ -110,7 +114,7 @@ function useTodaysItems(day: string) { const todaysAssignments: { moduleName: string; assignment: LocalAssignment; - status: "localOnly" | "unPublished" | "published"; + status: "localOnly" | "incomplete" | "published"; }[] = todaysModules ? Object.keys(todaysModules).flatMap((moduleName) => todaysModules[moduleName].assignments.map((assignment) => { @@ -120,11 +124,11 @@ function useTodaysItems(day: string) { return { moduleName, assignment, - status: canvasAssignment - ? canvasAssignment.published - ? "published" - : "unPublished" - : "localOnly", + status: getStatus({ + item: assignment, + canvasItem: canvasAssignment, + type: "assignment", + }), }; }) ) @@ -133,7 +137,7 @@ function useTodaysItems(day: string) { const todaysQuizzes: { moduleName: string; quiz: LocalQuiz; - status: "localOnly" | "unPublished" | "published"; + status: "localOnly" | "incomplete" | "published"; }[] = todaysModules ? Object.keys(todaysModules).flatMap((moduleName) => todaysModules[moduleName].quizzes.map((quiz) => { @@ -144,7 +148,7 @@ function useTodaysItems(day: string) { status: canvasQuiz ? canvasQuiz.published ? "published" - : "unPublished" + : "incomplete" : "localOnly", }; }) @@ -154,7 +158,7 @@ function useTodaysItems(day: string) { const todaysPages: { moduleName: string; page: LocalCoursePage; - status: "localOnly" | "unPublished" | "published"; + status: "localOnly" | "incomplete" | "published"; }[] = todaysModules ? Object.keys(todaysModules).flatMap((moduleName) => todaysModules[moduleName].pages.map((page) => { @@ -165,7 +169,7 @@ function useTodaysItems(day: string) { status: canvasPage ? canvasPage.published ? "published" - : "unPublished" + : "incomplete" : "localOnly", }; }) @@ -181,7 +185,7 @@ function DraggableListItem({ item, }: { type: "assignment" | "page" | "quiz"; - status: "localOnly" | "unPublished" | "published"; + status: "localOnly" | "incomplete" | "published"; moduleName: string; item: IModuleItem; }) { @@ -196,7 +200,7 @@ function DraggableListItem({ " bg-slate-800 " + " block " + (status === "localOnly" && " text-slate-500 border-slate-600 ") + - (status === "unPublished" && " border-rose-900 ") + + (status === "incomplete" && " border-rose-900 ") + (status === "published" && " border-green-800 ") } role="button" @@ -215,3 +219,40 @@ function DraggableListItem({ ); } + +const getStatus = ({ + item, + canvasItem, + type, +}: { + item: LocalQuiz | LocalAssignment | LocalCoursePage; + canvasItem?: CanvasQuiz | CanvasAssignment | CanvasPage; + type: "assignment" | "page" | "quiz"; +}): "localOnly" | "incomplete" | "published" => { + if (!canvasItem) return "localOnly"; + + if (!canvasItem.published) return "incomplete"; + + if (type === "assignment") { + const assignment = item as LocalAssignment; + const canvasAssignment = canvasItem as CanvasAssignment; + if (!canvasAssignment.due_at) return "incomplete"; + + if (assignment.lockAt && !canvasAssignment.lock_at) return "incomplete"; + + if ( + getDateFromStringOrThrow( + assignment.dueAt, + "comparing due dates for day" + ).toISOString() !== + getDateFromStringOrThrow( + canvasAssignment.due_at, + "comparing canvas due date for day" + ).toISOString() + ) { + return "incomplete"; + } + } + + return "published"; +}; diff --git a/nextjs/src/models/local/tests/timeUtils.test.ts b/nextjs/src/models/local/tests/timeUtils.test.ts index d9422bc..0b0e501 100644 --- a/nextjs/src/models/local/tests/timeUtils.test.ts +++ b/nextjs/src/models/local/tests/timeUtils.test.ts @@ -52,4 +52,13 @@ describe("Can properly handle expected date formats", () => { const updatedString = dateToMarkdownString(dateObject!) expect(updatedString).toBe(dateString) }); + it("can handle canvas time format", () => { + const dateString = "8/29/2024, 5:00:00 PM"; + const dateObject = getDateFromString(dateString); + + expect(dateObject).not.toBeUndefined() + const updatedString = dateToMarkdownString(dateObject!) + expect(updatedString).toBe("08/29/2024 17:00:00") + + }) }); diff --git a/nextjs/src/models/local/timeUtils.ts b/nextjs/src/models/local/timeUtils.ts index 0c51d8b..6da28a3 100644 --- a/nextjs/src/models/local/timeUtils.ts +++ b/nextjs/src/models/local/timeUtils.ts @@ -1,14 +1,14 @@ const _getDateFromAMPM = ( datePart: string, - timePartWithMeridian: string + timePart: string, + amPmPart: string ): Date | undefined => { const [month, day, year] = datePart.split("/").map(Number); - const [timePart, meridian] = timePartWithMeridian.split(" "); const [hours, minutes, seconds] = timePart.split(":").map(Number); let adjustedHours = hours; - if (meridian) { - const upperMeridian = meridian.toUpperCase(); + if (amPmPart) { + const upperMeridian = amPmPart.toUpperCase(); if (upperMeridian === "PM" && hours < 12) { adjustedHours += 12; } else if (upperMeridian === "AM" && hours === 12) { @@ -38,15 +38,15 @@ const _getDateFromISO = (value: string): Date | undefined => { export const getDateFromString = (value: string): Date | undefined => { const ampmDateRegex = - /^\d{1,2}\/\d{1,2}\/\d{4} \d{1,2}:\d{2}:\d{2}\s{1}[APap][Mm]$/; //"M/D/YYYY h:mm:ss AM/PM" + /^\d{1,2}\/\d{1,2}\/\d{4},? \d{1,2}:\d{2}:\d{2}\s{1}[APap][Mm]$/; //"M/D/YYYY h:mm:ss AM/PM" or "M/D/YYYY, h:mm:ss AM/PM" const militaryDateRegex = /^\d{1,2}\/\d{1,2}\/\d{4} \d{1,2}:\d{2}:\d{2}$/; //"MM/DD/YYYY HH:mm:ss" const isoDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}((.\d+)|(Z))$/; //"2024-08-26T00:00:00.0000000" if (isoDateRegex.test(value)) { return _getDateFromISO(value); } else if (ampmDateRegex.test(value)) { - const [datePart, timePartWithMeridian] = value.split(/[\s\u202F]+/); - return _getDateFromAMPM(datePart, timePartWithMeridian); + const [datePart, timePart, amPmPart] = value.split(/,?[\s\u202F]+/); + return _getDateFromAMPM(datePart, timePart, amPmPart); } else if (militaryDateRegex.test(value)) { const [datePart, timePart] = value.split(" "); return _getDateFromMilitary(datePart, timePart);