"use client"; import { ReactNode, useCallback, DragEvent, useEffect } from "react"; import { DraggableItem, DraggingContext } from "./draggingContext"; import { useUpdateQuizMutation } from "@/hooks/localCourse/quizHooks"; import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks"; import { LocalQuiz } from "@/models/local/quiz/localQuiz"; import { getDateFromStringOrThrow, dateToMarkdownString, } from "@/models/local/timeUtils"; import { LocalAssignment } from "@/models/local/assignment/localAssignment"; import { useUpdateAssignmentMutation } from "@/hooks/localCourse/assignmentHooks"; import { useUpdatePageMutation } from "@/hooks/localCourse/pageHooks"; import { LocalCoursePage } from "@/models/local/page/localCoursePage"; import { useDragStyleContext } from "./dragStyleContext"; export default function DraggingContextProvider({ children, }: { children: ReactNode; }) { const { setIsDragging } = useDragStyleContext(); const updateQuizMutation = useUpdateQuizMutation(); const updateAssignmentMutation = useUpdateAssignmentMutation(); const updatePageMutation = useUpdatePageMutation(); const { data: settings } = useLocalCourseSettingsQuery(); useEffect(() => { const handleDrop = () => { console.log("drop on window"); setIsDragging(false); }; const preventDefault = (e: globalThis.DragEvent) => e.preventDefault(); if (typeof window !== "undefined") { window.addEventListener("drop", handleDrop); window.addEventListener("dragover", preventDefault); } return () => { window.removeEventListener("drop", handleDrop); window.addEventListener("dragover", preventDefault); }; }, [setIsDragging]); const itemDropOnModule = useCallback( (e: DragEvent, dropModuleName: string) => { console.log("dropping on module"); const rawData = e.dataTransfer.getData("draggableItem"); if (!rawData) return; const itemBeingDragged: DraggableItem = JSON.parse(rawData); if (itemBeingDragged) { if (itemBeingDragged.type === "quiz") { updateQuiz(); } else if (itemBeingDragged.type === "assignment") { updateAssignment(); } else if (itemBeingDragged.type === "page") { updatePage(); } } setIsDragging(false); function updateQuiz() { const quiz = itemBeingDragged.item as LocalQuiz; updateQuizMutation.mutate({ item: quiz, itemName: quiz.name, moduleName: dropModuleName, previousModuleName: itemBeingDragged.sourceModuleName, previousItemName: quiz.name, }); } function updateAssignment() { const assignment = itemBeingDragged.item as LocalAssignment; updateAssignmentMutation.mutate({ item: assignment, previousModuleName: itemBeingDragged.sourceModuleName, moduleName: dropModuleName, itemName: assignment.name, previousItemName: assignment.name, }); } function updatePage() { const page = itemBeingDragged.item as LocalCoursePage; updatePageMutation.mutate({ item: page, moduleName: dropModuleName, itemName: page.name, previousItemName: page.name, previousModuleName: itemBeingDragged.sourceModuleName, }); } }, [ setIsDragging, updateAssignmentMutation, updatePageMutation, updateQuizMutation, ] ); const itemDropOnDay = useCallback( (e: DragEvent, day: string) => { const rawData = e.dataTransfer.getData("draggableItem"); if (!rawData) return; const itemBeingDragged: DraggableItem = JSON.parse(rawData); if (itemBeingDragged) { const dayAsDate = getDateWithDefaultDueTime(); if (itemBeingDragged.type === "quiz") { updateQuiz(dayAsDate); } else if (itemBeingDragged.type === "assignment") { updateAssignment(dayAsDate); } else if (itemBeingDragged.type === "page") { updatePage(dayAsDate); } } setIsDragging(false); function getDateWithDefaultDueTime() { const dayAsDate = getDateFromStringOrThrow(day, "in drop callback"); dayAsDate.setHours(settings.defaultDueTime.hour); dayAsDate.setMinutes(settings.defaultDueTime.minute); dayAsDate.setSeconds(0); return dayAsDate; } function updateQuiz(dayAsDate: Date) { const previousQuiz = itemBeingDragged.item as LocalQuiz; const quiz: LocalQuiz = { ...previousQuiz, dueAt: dateToMarkdownString(dayAsDate), lockAt: getNewLockDate( previousQuiz.dueAt, previousQuiz.lockAt, dayAsDate ), }; updateQuizMutation.mutate({ item: quiz, itemName: quiz.name, moduleName: itemBeingDragged.sourceModuleName, previousModuleName: itemBeingDragged.sourceModuleName, previousItemName: quiz.name, }); } function updatePage(dayAsDate: Date) { const previousPage = itemBeingDragged.item as LocalCoursePage; const page: LocalCoursePage = { ...previousPage, dueAt: dateToMarkdownString(dayAsDate), }; updatePageMutation.mutate({ item: page, moduleName: itemBeingDragged.sourceModuleName, itemName: page.name, previousItemName: page.name, previousModuleName: itemBeingDragged.sourceModuleName, }); } function updateAssignment(dayAsDate: Date) { const previousAssignment = itemBeingDragged.item as LocalAssignment; const assignment: LocalAssignment = { ...previousAssignment, dueAt: dateToMarkdownString(dayAsDate), lockAt: previousAssignment.lockAt && (getDateFromStringOrThrow( previousAssignment.lockAt, "lockAt date" ) > dayAsDate ? previousAssignment.lockAt : dateToMarkdownString(dayAsDate)), }; updateAssignmentMutation.mutate({ item: assignment, previousModuleName: itemBeingDragged.sourceModuleName, moduleName: itemBeingDragged.sourceModuleName, itemName: assignment.name, previousItemName: assignment.name, }); } }, [ setIsDragging, settings.defaultDueTime.hour, settings.defaultDueTime.minute, updateAssignmentMutation, updatePageMutation, updateQuizMutation, ] ); return ( {children} ); } function getNewLockDate( originalDueDate: string, originalLockDate: string | undefined, dayAsDate: Date ): string | undefined { // todo: preserve previous due date / lock date offset const dueDate = getDateFromStringOrThrow(originalDueDate, "dueat date"); const lockDate = originalLockDate === undefined ? undefined : getDateFromStringOrThrow(originalLockDate, "lockAt date"); const originalOffset = lockDate === undefined ? undefined : lockDate.getTime() - dueDate.getTime(); const newLockDate = originalOffset === undefined ? undefined : new Date(dayAsDate.getTime() + originalOffset); return newLockDate === undefined ? undefined : dateToMarkdownString(newLockDate); }