mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
pushing state down with contexts
This commit is contained in:
@@ -2,8 +2,7 @@
|
||||
|
||||
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
|
||||
|
||||
|
||||
export default function CourseSettings({ courseName }: { courseName: string }) {
|
||||
const { data: settings } = useLocalCourseSettingsQuery(courseName);
|
||||
export default function CourseSettings() {
|
||||
const { data: settings } = useLocalCourseSettingsQuery();
|
||||
return <div>{settings.name}</div>;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ function CalendarWeek({
|
||||
week,
|
||||
monthNumber,
|
||||
}: {
|
||||
week: Date[];
|
||||
week: string[]; //date strings
|
||||
monthNumber: number;
|
||||
}) {
|
||||
return (
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
"use client";
|
||||
import { getDateFromStringOrThrow } from "@/models/local/timeUtils";
|
||||
import { useCourseContext } from "../context/courseContext";
|
||||
import { getMonthsBetweenDates } from "./calendarMonthUtils";
|
||||
import { CalendarMonth } from "./CalendarMonth";
|
||||
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
|
||||
import { useMemo } from "react";
|
||||
|
||||
export default function CourseCalendar() {
|
||||
const { courseName } = useCourseContext();
|
||||
const { data: settings } = useLocalCourseSettingsQuery(courseName);
|
||||
const { data: settings } = useLocalCourseSettingsQuery();
|
||||
|
||||
const startDateTime = useMemo(
|
||||
() => getDateFromStringOrThrow(settings.startDate, "course start date"),
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
"use client";
|
||||
import { useCourseContext } from "../context/courseContext";
|
||||
import { useModuleNamesQuery } from "@/hooks/localCourse/localCoursesHooks";
|
||||
import DayItemsInModule from "./DayItemsInModule";
|
||||
import { getDateFromStringOrThrow } from "@/models/local/timeUtils";
|
||||
import { useDraggingContext } from "../context/DraggingContext";
|
||||
|
||||
export default function Day({ day, month }: { day: Date; month: number }) {
|
||||
const { courseName, itemDrop } = useCourseContext();
|
||||
const { data: moduleNames } = useModuleNamesQuery(courseName);
|
||||
const isInSameMonth = day.getMonth() + 1 != month;
|
||||
export default function Day({ day, month }: { day: string; month: number }) {
|
||||
const { data: moduleNames } = useModuleNamesQuery();
|
||||
|
||||
const dayAsDate = getDateFromStringOrThrow(day, "calculating same month in day")
|
||||
const isInSameMonth =
|
||||
dayAsDate.getMonth() + 1 !=
|
||||
month;
|
||||
const backgroundClass = isInSameMonth ? "" : "bg-slate-900";
|
||||
|
||||
return (
|
||||
@@ -15,16 +19,23 @@ export default function Day({ day, month }: { day: Date; month: number }) {
|
||||
"border border-slate-600 rounded-lg p-2 pb-4 m-1 " + backgroundClass
|
||||
}
|
||||
>
|
||||
{day.getDate()}
|
||||
{dayAsDate.getDate()}
|
||||
{moduleNames.map((moduleName) => (
|
||||
<div
|
||||
<ModuleInDay
|
||||
key={"" + day + month + moduleName}
|
||||
onDrop={() => itemDrop(day)}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
>
|
||||
<DayItemsInModule day={day} moduleName={moduleName} />
|
||||
</div>
|
||||
moduleName={moduleName}
|
||||
day={day}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ModuleInDay({ moduleName, day }: { moduleName: string; day: string }) {
|
||||
const { itemDrop } = useDraggingContext();
|
||||
return (
|
||||
<div onDrop={() => itemDrop(day)} onDragOver={(e) => e.preventDefault()}>
|
||||
<DayItemsInModule day={day} moduleName={moduleName} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,20 +7,20 @@ import Link from "next/link";
|
||||
import { LocalAssignment } from "@/models/local/assignmnet/localAssignment";
|
||||
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
|
||||
import { LocalCoursePage } from "@/models/local/page/localCoursePage";
|
||||
import { useDraggingContext } from "../context/DraggingContext";
|
||||
|
||||
export default function DayItemsInModule({
|
||||
day,
|
||||
moduleName,
|
||||
}: {
|
||||
day: Date;
|
||||
day: string;
|
||||
moduleName: string;
|
||||
}) {
|
||||
const { courseName, endItemDrag, startItemDrag } = useCourseContext();
|
||||
const { courseName } = useCourseContext();
|
||||
const { endItemDrag, startItemDrag } = useDraggingContext();
|
||||
const { assignments, quizzes, pages } = useModuleDataQuery(
|
||||
courseName,
|
||||
moduleName
|
||||
);
|
||||
|
||||
const todaysAssignments = useMemo(
|
||||
() =>
|
||||
assignments.filter((a) => {
|
||||
@@ -28,10 +28,14 @@ export default function DayItemsInModule({
|
||||
a.dueAt,
|
||||
"due at for assignment in day"
|
||||
);
|
||||
const dayAsDate = getDateFromStringOrThrow(
|
||||
day,
|
||||
"in assignment in DayItemsInModule"
|
||||
);
|
||||
return (
|
||||
dueDate.getFullYear() === day.getFullYear() &&
|
||||
dueDate.getMonth() === day.getMonth() &&
|
||||
dueDate.getDate() === day.getDate()
|
||||
dueDate.getFullYear() === dayAsDate.getFullYear() &&
|
||||
dueDate.getMonth() === dayAsDate.getMonth() &&
|
||||
dueDate.getDate() === dayAsDate.getDate()
|
||||
);
|
||||
}),
|
||||
[assignments, day]
|
||||
@@ -43,10 +47,14 @@ export default function DayItemsInModule({
|
||||
q.dueAt,
|
||||
"due at for quiz in day"
|
||||
);
|
||||
const dayAsDate = getDateFromStringOrThrow(
|
||||
day,
|
||||
"in quizzes in DayItemsInModule"
|
||||
);
|
||||
return (
|
||||
dueDate.getFullYear() === day.getFullYear() &&
|
||||
dueDate.getMonth() === day.getMonth() &&
|
||||
dueDate.getDate() === day.getDate()
|
||||
dueDate.getFullYear() === dayAsDate.getFullYear() &&
|
||||
dueDate.getMonth() === dayAsDate.getMonth() &&
|
||||
dueDate.getDate() === dayAsDate.getDate()
|
||||
);
|
||||
}),
|
||||
[day, quizzes]
|
||||
@@ -58,10 +66,14 @@ export default function DayItemsInModule({
|
||||
p.dueAt,
|
||||
"due at for page in day"
|
||||
);
|
||||
const dayAsDate = getDateFromStringOrThrow(
|
||||
day,
|
||||
"in pages in DayItemsInModule"
|
||||
);
|
||||
return (
|
||||
dueDate.getFullYear() === day.getFullYear() &&
|
||||
dueDate.getMonth() === day.getMonth() &&
|
||||
dueDate.getDate() === day.getDate()
|
||||
dueDate.getFullYear() === dayAsDate.getFullYear() &&
|
||||
dueDate.getMonth() === dayAsDate.getMonth() &&
|
||||
dueDate.getDate() === dayAsDate.getDate()
|
||||
);
|
||||
}),
|
||||
[day, pages]
|
||||
@@ -128,6 +140,7 @@ export default function DayItemsInModule({
|
||||
role="button"
|
||||
draggable="true"
|
||||
onDragStart={starPageDrag(p)}
|
||||
onDragEnd={endItemDrag}
|
||||
>
|
||||
{p.name}
|
||||
</li>
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
"use client"
|
||||
"use client";
|
||||
|
||||
import {
|
||||
dateToMarkdownString,
|
||||
getDateFromStringOrThrow,
|
||||
} from "@/models/local/timeUtils";
|
||||
|
||||
export interface CalendarMonthModel {
|
||||
year: number;
|
||||
month: number;
|
||||
weeks: number[][];
|
||||
daysByWeek: (Date)[][];
|
||||
daysByWeek: string[][]; //iso date is memo-izable
|
||||
}
|
||||
|
||||
function weeksInMonth(year: number, month: number): number {
|
||||
@@ -27,17 +33,25 @@ function createCalendarMonth(year: number, month: number): CalendarMonthModel {
|
||||
const daysByWeek = Array.from({ length: weeksNumber }).map((_, weekIndex) =>
|
||||
Array.from({ length: 7 }).map((_, dayIndex) => {
|
||||
if (weekIndex === 0 && dayIndex < firstDayOfMonth) {
|
||||
return new Date(year, month - 1, dayIndex - firstDayOfMonth + 1);
|
||||
return dateToMarkdownString(
|
||||
new Date(year, month - 1, dayIndex - firstDayOfMonth + 1)
|
||||
);
|
||||
} else if (currentDay <= daysInMonth) {
|
||||
return new Date(year, month - 1, currentDay++);
|
||||
return dateToMarkdownString(new Date(year, month - 1, currentDay++));
|
||||
} else {
|
||||
currentDay++;
|
||||
return new Date(year, month, currentDay - daysInMonth - 1);
|
||||
return dateToMarkdownString(
|
||||
new Date(year, month, currentDay - daysInMonth - 1)
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const weeks = daysByWeek.map((week) => week.map((day) => day.getDate()));
|
||||
const weeks = daysByWeek.map((week) =>
|
||||
week.map((day) =>
|
||||
getDateFromStringOrThrow(day, "calculating weeks").getDate()
|
||||
)
|
||||
);
|
||||
|
||||
return { year, month, weeks, daysByWeek };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
import { ReactNode, useCallback, useState } from "react";
|
||||
import { CourseContext, DraggableItem } from "./courseContext";
|
||||
import { CourseContext } from "./courseContext";
|
||||
import { DraggableItem } from "./DraggingContext";
|
||||
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
|
||||
import {
|
||||
dateToMarkdownString,
|
||||
@@ -16,60 +17,10 @@ export default function CourseContextProvider({
|
||||
children: ReactNode;
|
||||
localCourseName: string;
|
||||
}) {
|
||||
const updateQuizMutation = useUpdateQuizMutation(localCourseName);
|
||||
const { data: settings } = useLocalCourseSettingsQuery(localCourseName);
|
||||
const [itemBeingDragged, setItemBeingDragged] = useState<
|
||||
DraggableItem | undefined
|
||||
>();
|
||||
|
||||
const itemDrop = useCallback(
|
||||
(day: Date | undefined) => {
|
||||
if (itemBeingDragged && day) {
|
||||
day.setHours(settings.defaultDueTime.hour);
|
||||
day.setHours(settings.defaultDueTime.minute);
|
||||
if (itemBeingDragged.type === "quiz") {
|
||||
const previousQuiz = itemBeingDragged.item as LocalQuiz;
|
||||
|
||||
const quiz: LocalQuiz = {
|
||||
...previousQuiz,
|
||||
dueAt: dateToMarkdownString(day),
|
||||
lockAt:
|
||||
previousQuiz.lockAt &&
|
||||
(getDateFromStringOrThrow(previousQuiz.lockAt, "lockAt date") >
|
||||
day
|
||||
? previousQuiz.lockAt
|
||||
: dateToMarkdownString(day)),
|
||||
};
|
||||
updateQuizMutation.mutate({
|
||||
quiz: quiz,
|
||||
quizName: quiz.name,
|
||||
moduleName: itemBeingDragged.sourceModuleName,
|
||||
});
|
||||
}
|
||||
}
|
||||
setItemBeingDragged(undefined);
|
||||
},
|
||||
[
|
||||
itemBeingDragged,
|
||||
settings.defaultDueTime.hour,
|
||||
settings.defaultDueTime.minute,
|
||||
updateQuizMutation,
|
||||
]
|
||||
);
|
||||
|
||||
const startItemDrag = useCallback((d: DraggableItem) => {
|
||||
setItemBeingDragged(d);
|
||||
}, []);
|
||||
const endItemDrag = useCallback(() => {
|
||||
setItemBeingDragged(undefined);
|
||||
}, []);
|
||||
return (
|
||||
<CourseContext.Provider
|
||||
value={{
|
||||
courseName: localCourseName,
|
||||
startItemDrag: startItemDrag,
|
||||
endItemDrag: endItemDrag,
|
||||
itemDrop,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
"use client";
|
||||
import { IModuleItem } from "@/models/local/IModuleItem";
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
export interface DraggableItem {
|
||||
item: IModuleItem;
|
||||
sourceModuleName: string;
|
||||
type: "quiz" | "assignment" | "page";
|
||||
}
|
||||
|
||||
export interface DraggingContextInterface {
|
||||
startItemDrag: (dragging: DraggableItem) => void;
|
||||
endItemDrag: () => void;
|
||||
itemDrop: (droppedOnDay?: string) => void;
|
||||
}
|
||||
const defaultDraggingValue: DraggingContextInterface = {
|
||||
startItemDrag: () => { },
|
||||
endItemDrag: () => { },
|
||||
itemDrop: () => { },
|
||||
};
|
||||
export const DraggingContext = createContext<DraggingContextInterface>(defaultDraggingValue);
|
||||
|
||||
export function useDraggingContext() {
|
||||
return useContext(DraggingContext);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
"use client";
|
||||
import { ReactNode, useCallback, useState } from "react";
|
||||
import { DraggableItem, DraggingContext } from "./DraggingContext";
|
||||
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
|
||||
import {
|
||||
dateToMarkdownString,
|
||||
getDateFromStringOrThrow,
|
||||
} from "@/models/local/timeUtils";
|
||||
import { useUpdateQuizMutation } from "@/hooks/localCourse/quizHooks";
|
||||
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
|
||||
|
||||
export default function DraggingContextProvider({
|
||||
children,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
localCourseName: string;
|
||||
}) {
|
||||
const updateQuizMutation = useUpdateQuizMutation();
|
||||
const { data: settings } = useLocalCourseSettingsQuery();
|
||||
const [itemBeingDragged, setItemBeingDragged] = useState<
|
||||
DraggableItem | undefined
|
||||
>();
|
||||
|
||||
const itemDrop = useCallback(
|
||||
(day: string | undefined) => {
|
||||
if (itemBeingDragged && day) {
|
||||
const dayAsDate = getDateFromStringOrThrow(day, "in drop callback");
|
||||
dayAsDate.setHours(settings.defaultDueTime.hour);
|
||||
dayAsDate.setHours(settings.defaultDueTime.minute);
|
||||
if (itemBeingDragged.type === "quiz") {
|
||||
console.log("dropping quiz");
|
||||
const previousQuiz = itemBeingDragged.item as LocalQuiz;
|
||||
|
||||
const quiz: LocalQuiz = {
|
||||
...previousQuiz,
|
||||
dueAt: dateToMarkdownString(dayAsDate),
|
||||
lockAt:
|
||||
previousQuiz.lockAt &&
|
||||
(getDateFromStringOrThrow(previousQuiz.lockAt, "lockAt date") >
|
||||
dayAsDate
|
||||
? previousQuiz.lockAt
|
||||
: dateToMarkdownString(dayAsDate)),
|
||||
};
|
||||
updateQuizMutation.mutate({
|
||||
quiz: quiz,
|
||||
quizName: quiz.name,
|
||||
moduleName: itemBeingDragged.sourceModuleName,
|
||||
});
|
||||
} else if (itemBeingDragged.type === "assignment") {
|
||||
console.log("dropped assignment");
|
||||
} else if (itemBeingDragged.type === "page") {
|
||||
console.log("dropped page");
|
||||
}
|
||||
}
|
||||
setItemBeingDragged(undefined);
|
||||
},
|
||||
[
|
||||
itemBeingDragged,
|
||||
settings.defaultDueTime.hour,
|
||||
settings.defaultDueTime.minute,
|
||||
updateQuizMutation,
|
||||
]
|
||||
);
|
||||
|
||||
const startItemDrag = useCallback((d: DraggableItem) => {
|
||||
setItemBeingDragged(d);
|
||||
}, []);
|
||||
const endItemDrag = useCallback(() => {
|
||||
setItemBeingDragged(undefined);
|
||||
}, []);
|
||||
return (
|
||||
<DraggingContext.Provider
|
||||
value={{
|
||||
startItemDrag: startItemDrag,
|
||||
endItemDrag: endItemDrag,
|
||||
itemDrop,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</DraggingContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -1,25 +1,12 @@
|
||||
"use client";
|
||||
import { IModuleItem } from "@/models/local/IModuleItem";
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
export interface DraggableItem {
|
||||
item: IModuleItem;
|
||||
sourceModuleName: string;
|
||||
type: "quiz" | "assignment" | "page";
|
||||
}
|
||||
|
||||
export interface CourseContextInterface {
|
||||
courseName: string;
|
||||
startItemDrag: (dragging: DraggableItem) => void;
|
||||
endItemDrag: () => void;
|
||||
itemDrop: (droppedOnDay?: Date) => void;
|
||||
}
|
||||
|
||||
const defaultValue: CourseContextInterface = {
|
||||
startItemDrag: () => { },
|
||||
endItemDrag: () => { },
|
||||
itemDrop: () => { },
|
||||
courseName: ""
|
||||
courseName: "",
|
||||
};
|
||||
|
||||
export const CourseContext =
|
||||
@@ -28,3 +15,4 @@ export const CourseContext =
|
||||
export function useCourseContext() {
|
||||
return useContext(CourseContext);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@ export default function ExpandableModule({
|
||||
}: {
|
||||
moduleName: string;
|
||||
}) {
|
||||
const { courseName } = useCourseContext();
|
||||
const { assignments, quizzes, pages } = useModuleDataQuery(
|
||||
courseName,
|
||||
moduleName
|
||||
);
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@ import { useCourseContext } from "../context/courseContext";
|
||||
import ExpandableModule from "./ExpandableModule";
|
||||
|
||||
export default function ModuleList() {
|
||||
const { courseName } = useCourseContext();
|
||||
const { data: moduleNames } = useModuleNamesQuery(courseName);
|
||||
const { data: moduleNames } = useModuleNamesQuery();
|
||||
return (
|
||||
<div>
|
||||
{moduleNames.map((m) => (
|
||||
|
||||
@@ -3,15 +3,13 @@ import MonacoEditor from "@/components/MonacoEditor";
|
||||
import { useQuizQuery } from "@/hooks/localCourse/quizHooks";
|
||||
|
||||
export default function EditQuiz({
|
||||
courseName,
|
||||
moduleName,
|
||||
quizName,
|
||||
}: {
|
||||
courseName: string;
|
||||
quizName: string;
|
||||
moduleName: string;
|
||||
}) {
|
||||
const { data: quiz } = useQuizQuery(courseName, moduleName, quizName);
|
||||
const { data: quiz } = useQuizQuery(moduleName, quizName);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -2,15 +2,9 @@ import React from "react";
|
||||
import EditQuiz from "./EditQuiz";
|
||||
|
||||
export default async function Page({
|
||||
params: { courseName, moduleName, quizName },
|
||||
params: { moduleName, quizName },
|
||||
}: {
|
||||
params: { courseName: string; quizName: string; moduleName: string };
|
||||
params: { quizName: string; moduleName: string };
|
||||
}) {
|
||||
return (
|
||||
<EditQuiz
|
||||
courseName={courseName}
|
||||
quizName={quizName}
|
||||
moduleName={moduleName}
|
||||
/>
|
||||
);
|
||||
return <EditQuiz quizName={quizName} moduleName={moduleName} />;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import CourseContextProvider from "./context/CourseContextProvider";
|
||||
import CourseCalendar from "./calendar/CourseCalendar";
|
||||
import CourseSettings from "./CourseSettings";
|
||||
import ModuleList from "./modules/ModuleList";
|
||||
import DraggingContextProvider from "./context/DraggingContextProvider";
|
||||
|
||||
export default async function CoursePage({
|
||||
params: { courseName },
|
||||
@@ -11,14 +12,16 @@ export default async function CoursePage({
|
||||
return (
|
||||
<CourseContextProvider localCourseName={courseName}>
|
||||
<div className="h-full flex flex-col">
|
||||
<CourseSettings courseName={courseName} />
|
||||
<CourseSettings />
|
||||
<div className="flex flex-row min-h-0">
|
||||
<div className="flex-1 min-h-0">
|
||||
<CourseCalendar />
|
||||
</div>
|
||||
<div className="w-96 p-3">
|
||||
<ModuleList />
|
||||
</div>
|
||||
<DraggingContextProvider localCourseName={courseName}>
|
||||
<div className="flex-1 min-h-0">
|
||||
<CourseCalendar />
|
||||
</div>
|
||||
<div className="w-96 p-3">
|
||||
<ModuleList />
|
||||
</div>
|
||||
</DraggingContextProvider>
|
||||
</div>
|
||||
</div>
|
||||
</CourseContextProvider>
|
||||
|
||||
Reference in New Issue
Block a user