mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
can drag and drop quizzes and assignments
This commit is contained in:
@@ -15,3 +15,19 @@ export async function GET(
|
|||||||
);
|
);
|
||||||
return Response.json(settings);
|
return Response.json(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function PUT(
|
||||||
|
request: Request,
|
||||||
|
{
|
||||||
|
params: { courseName, moduleName, assignmentName },
|
||||||
|
}: { params: { courseName: string; moduleName: string; assignmentName: string } }
|
||||||
|
) {
|
||||||
|
const assignment = await request.json()
|
||||||
|
await fileStorageService.updateAssignment(
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
assignmentName,
|
||||||
|
assignment
|
||||||
|
);
|
||||||
|
return Response.json({});
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,3 +13,19 @@ export async function GET(
|
|||||||
);
|
);
|
||||||
return Response.json(settings);
|
return Response.json(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function PUT(
|
||||||
|
request: Request,
|
||||||
|
{
|
||||||
|
params: { courseName, moduleName, pageName },
|
||||||
|
}: { params: { courseName: string; moduleName: string; pageName: string } }
|
||||||
|
) {
|
||||||
|
const page = await request.json()
|
||||||
|
await fileStorageService.updatePage(
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
pageName,
|
||||||
|
page
|
||||||
|
);
|
||||||
|
return Response.json({});
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,14 @@ import { DraggingContext } from "./draggingContext";
|
|||||||
import { useUpdateQuizMutation } from "@/hooks/localCourse/quizHooks";
|
import { useUpdateQuizMutation } from "@/hooks/localCourse/quizHooks";
|
||||||
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
|
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
|
||||||
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
|
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
|
||||||
import { getDateFromStringOrThrow, dateToMarkdownString } from "@/models/local/timeUtils";
|
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";
|
||||||
|
|
||||||
export default function DraggingContextProvider({
|
export default function DraggingContextProvider({
|
||||||
children,
|
children,
|
||||||
@@ -13,6 +20,8 @@ export default function DraggingContextProvider({
|
|||||||
localCourseName: string;
|
localCourseName: string;
|
||||||
}) {
|
}) {
|
||||||
const updateQuizMutation = useUpdateQuizMutation();
|
const updateQuizMutation = useUpdateQuizMutation();
|
||||||
|
const updateAssignmentMutation = useUpdateAssignmentMutation();
|
||||||
|
const updatePageMutation = useUpdatePageMutation();
|
||||||
const { data: settings } = useLocalCourseSettingsQuery();
|
const { data: settings } = useLocalCourseSettingsQuery();
|
||||||
|
|
||||||
const itemDrop = useCallback(
|
const itemDrop = useCallback(
|
||||||
@@ -35,12 +44,7 @@ export default function DraggingContextProvider({
|
|||||||
const quiz: LocalQuiz = {
|
const quiz: LocalQuiz = {
|
||||||
...previousQuiz,
|
...previousQuiz,
|
||||||
dueAt: dateToMarkdownString(dayAsDate),
|
dueAt: dateToMarkdownString(dayAsDate),
|
||||||
lockAt:
|
lockAt: getLaterDate(previousQuiz.lockAt, dayAsDate),
|
||||||
previousQuiz.lockAt &&
|
|
||||||
(getDateFromStringOrThrow(previousQuiz.lockAt, "lockAt date") >
|
|
||||||
dayAsDate
|
|
||||||
? previousQuiz.lockAt
|
|
||||||
: dateToMarkdownString(dayAsDate)),
|
|
||||||
};
|
};
|
||||||
updateQuizMutation.mutate({
|
updateQuizMutation.mutate({
|
||||||
quiz: quiz,
|
quiz: quiz,
|
||||||
@@ -48,15 +52,46 @@ export default function DraggingContextProvider({
|
|||||||
moduleName: itemBeingDragged.sourceModuleName,
|
moduleName: itemBeingDragged.sourceModuleName,
|
||||||
});
|
});
|
||||||
} else if (itemBeingDragged.type === "assignment") {
|
} else if (itemBeingDragged.type === "assignment") {
|
||||||
console.log("dropped assignment");
|
updateAssignment(dayAsDate);
|
||||||
} else if (itemBeingDragged.type === "page") {
|
} else if (itemBeingDragged.type === "page") {
|
||||||
console.log("dropped page");
|
console.log("dropped page");
|
||||||
|
const previousPage = itemBeingDragged.item as LocalCoursePage;
|
||||||
|
const page: LocalCoursePage = {
|
||||||
|
...previousPage,
|
||||||
|
dueAt: dateToMarkdownString(dayAsDate),
|
||||||
|
};
|
||||||
|
updatePageMutation.mutate({
|
||||||
|
page,
|
||||||
|
moduleName: itemBeingDragged.sourceModuleName,
|
||||||
|
pageName: page.name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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({
|
||||||
|
assignment,
|
||||||
|
moduleName: itemBeingDragged.sourceModuleName,
|
||||||
|
assignmentName: assignment.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
settings.defaultDueTime.hour,
|
settings.defaultDueTime.hour,
|
||||||
settings.defaultDueTime.minute,
|
settings.defaultDueTime.minute,
|
||||||
|
updateAssignmentMutation,
|
||||||
updateQuizMutation,
|
updateQuizMutation,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -71,3 +106,14 @@ export default function DraggingContextProvider({
|
|||||||
</DraggingContext.Provider>
|
</DraggingContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
function getLaterDate(
|
||||||
|
firstDate: string | undefined,
|
||||||
|
dayAsDate: Date
|
||||||
|
): string | undefined {
|
||||||
|
return (
|
||||||
|
firstDate &&
|
||||||
|
(getDateFromStringOrThrow(firstDate, "lockAt date") > dayAsDate
|
||||||
|
? firstDate
|
||||||
|
: dateToMarkdownString(dayAsDate))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { localCourseKeys } from "./localCourseKeys";
|
import { localCourseKeys } from "./localCourseKeys";
|
||||||
import { LocalAssignment } from "@/models/local/assignment/localAssignment";
|
import { LocalAssignment } from "@/models/local/assignment/localAssignment";
|
||||||
import { useSuspenseQuery, useSuspenseQueries } from "@tanstack/react-query";
|
import { useSuspenseQuery, useSuspenseQueries, useQueryClient, useMutation } from "@tanstack/react-query";
|
||||||
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
||||||
|
|
||||||
export const useAssignmentNamesQuery = (moduleName: string) => {
|
export const useAssignmentNamesQuery = (moduleName: string) => {
|
||||||
@@ -72,3 +72,40 @@ export const useAssignmentsQueries = (
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useUpdateAssignmentMutation = () => {
|
||||||
|
const { courseName } = useCourseContext();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async ({
|
||||||
|
assignment,
|
||||||
|
moduleName,
|
||||||
|
assignmentName,
|
||||||
|
}: {
|
||||||
|
assignment: LocalAssignment;
|
||||||
|
moduleName: string;
|
||||||
|
assignmentName: string;
|
||||||
|
}) => {
|
||||||
|
queryClient.setQueryData(
|
||||||
|
localCourseKeys.assignment(courseName, moduleName, assignmentName),
|
||||||
|
assignment
|
||||||
|
);
|
||||||
|
const url =
|
||||||
|
"/api/courses/" +
|
||||||
|
encodeURIComponent(courseName) +
|
||||||
|
"/modules/" +
|
||||||
|
encodeURIComponent(moduleName) +
|
||||||
|
"/assignments/" +
|
||||||
|
encodeURIComponent(assignmentName);
|
||||||
|
await axios.put(url, assignment);
|
||||||
|
},
|
||||||
|
onSuccess: (_, { moduleName, assignmentName }) => {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: localCourseKeys.assignment(courseName, moduleName, assignmentName),
|
||||||
|
});
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: localCourseKeys.assignmentNames(courseName, moduleName),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
"use client"
|
"use client";
|
||||||
import { LocalCoursePage } from "@/models/local/page/localCoursePage";
|
import { LocalCoursePage } from "@/models/local/page/localCoursePage";
|
||||||
import { useSuspenseQueries, useSuspenseQuery } from "@tanstack/react-query";
|
import {
|
||||||
|
useMutation,
|
||||||
|
useQueryClient,
|
||||||
|
useSuspenseQueries,
|
||||||
|
useSuspenseQuery,
|
||||||
|
} from "@tanstack/react-query";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { localCourseKeys } from "./localCourseKeys";
|
import { localCourseKeys } from "./localCourseKeys";
|
||||||
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
||||||
@@ -65,3 +70,40 @@ function getPageQueryConfig(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useUpdatePageMutation = () => {
|
||||||
|
const { courseName } = useCourseContext();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async ({
|
||||||
|
page,
|
||||||
|
moduleName,
|
||||||
|
pageName,
|
||||||
|
}: {
|
||||||
|
page: LocalCoursePage;
|
||||||
|
moduleName: string;
|
||||||
|
pageName: string;
|
||||||
|
}) => {
|
||||||
|
queryClient.setQueryData(
|
||||||
|
localCourseKeys.page(courseName, moduleName, pageName),
|
||||||
|
page
|
||||||
|
);
|
||||||
|
const url =
|
||||||
|
"/api/courses/" +
|
||||||
|
encodeURIComponent(courseName) +
|
||||||
|
"/modules/" +
|
||||||
|
encodeURIComponent(moduleName) +
|
||||||
|
"/pages/" +
|
||||||
|
encodeURIComponent(pageName);
|
||||||
|
await axios.put(url, page);
|
||||||
|
},
|
||||||
|
onSuccess: (_, { moduleName, pageName }) => {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: localCourseKeys.page(courseName, moduleName, pageName),
|
||||||
|
});
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: localCourseKeys.pageNames(courseName, moduleName),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ export const useUpdateQuizMutation = () => {
|
|||||||
moduleName: string;
|
moduleName: string;
|
||||||
quizName: string;
|
quizName: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
queryClient.setQueryData(
|
||||||
|
localCourseKeys.quiz(courseName, moduleName, quizName),
|
||||||
|
quiz
|
||||||
|
);
|
||||||
const url =
|
const url =
|
||||||
"/api/courses/" +
|
"/api/courses/" +
|
||||||
encodeURIComponent(courseName) +
|
encodeURIComponent(courseName) +
|
||||||
@@ -86,19 +90,15 @@ export const useUpdateQuizMutation = () => {
|
|||||||
encodeURIComponent(moduleName) +
|
encodeURIComponent(moduleName) +
|
||||||
"/quizzes/" +
|
"/quizzes/" +
|
||||||
encodeURIComponent(quizName);
|
encodeURIComponent(quizName);
|
||||||
queryClient.setQueryData(
|
|
||||||
localCourseKeys.quiz(courseName, moduleName, quizName),
|
|
||||||
quiz
|
|
||||||
);
|
|
||||||
await axios.put(url, quiz);
|
await axios.put(url, quiz);
|
||||||
},
|
},
|
||||||
onSuccess: (_, { moduleName, quizName }) => {
|
onSuccess: (_, { moduleName, quizName }) => {
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: localCourseKeys.quiz(courseName, moduleName, quizName),
|
queryKey: localCourseKeys.quiz(courseName, moduleName, quizName),
|
||||||
});
|
});
|
||||||
// queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
// queryKey: localCourseKeys.quizNames(courseName, moduleName),
|
queryKey: localCourseKeys.quizNames(courseName, moduleName),
|
||||||
// });
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ import {
|
|||||||
directoryOrFileExists,
|
directoryOrFileExists,
|
||||||
hasFileSystemEntries,
|
hasFileSystemEntries,
|
||||||
} from "./utils/fileSystemUtils";
|
} from "./utils/fileSystemUtils";
|
||||||
import { localAssignmentMarkdown } from "@/models/local/assignment/localAssignment";
|
import { LocalAssignment, localAssignmentMarkdown } from "@/models/local/assignment/localAssignment";
|
||||||
import { LocalQuiz, localQuizMarkdownUtils } from "@/models/local/quiz/localQuiz";
|
import { LocalQuiz, localQuizMarkdownUtils } from "@/models/local/quiz/localQuiz";
|
||||||
import { localPageMarkdownUtils } from "@/models/local/page/localCoursePage";
|
import { LocalCoursePage, localPageMarkdownUtils } from "@/models/local/page/localCoursePage";
|
||||||
import { quizMarkdownUtils } from "@/models/local/quiz/utils/quizMarkdownUtils";
|
import { quizMarkdownUtils } from "@/models/local/quiz/utils/quizMarkdownUtils";
|
||||||
|
import { assignmentMarkdownSerializer } from "@/models/local/assignment/utils/assignmentMarkdownSerializer";
|
||||||
|
|
||||||
const basePath = process.env.STORAGE_DIRECTORY ?? "./storage";
|
const basePath = process.env.STORAGE_DIRECTORY ?? "./storage";
|
||||||
console.log("base path", basePath);
|
console.log("base path", basePath);
|
||||||
@@ -136,6 +137,19 @@ export const fileStorageService = {
|
|||||||
);
|
);
|
||||||
return localAssignmentMarkdown.parseMarkdown(rawFile);
|
return localAssignmentMarkdown.parseMarkdown(rawFile);
|
||||||
},
|
},
|
||||||
|
async updateAssignment(courseName: string, moduleName: string, assignmentName: string, assignment: LocalAssignment) {
|
||||||
|
const filePath = path.join(
|
||||||
|
basePath,
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
"assignments",
|
||||||
|
assignmentName+".md"
|
||||||
|
);
|
||||||
|
|
||||||
|
const assignmentMarkdown = assignmentMarkdownSerializer.toMarkdown(assignment);
|
||||||
|
console.log(`Saving assignment ${filePath}`);
|
||||||
|
await fs.writeFile(filePath, assignmentMarkdown);
|
||||||
|
},
|
||||||
|
|
||||||
async getQuiz(courseName: string, moduleName: string, quizName: string) {
|
async getQuiz(courseName: string, moduleName: string, quizName: string) {
|
||||||
const filePath = path.join(
|
const filePath = path.join(
|
||||||
@@ -180,6 +194,19 @@ export const fileStorageService = {
|
|||||||
);
|
);
|
||||||
return localPageMarkdownUtils.parseMarkdown(rawFile);
|
return localPageMarkdownUtils.parseMarkdown(rawFile);
|
||||||
},
|
},
|
||||||
|
async updatePage(courseName: string, moduleName: string, pageName: string, page: LocalCoursePage) {
|
||||||
|
const filePath = path.join(
|
||||||
|
basePath,
|
||||||
|
courseName,
|
||||||
|
moduleName,
|
||||||
|
"pages",
|
||||||
|
pageName+".md"
|
||||||
|
);
|
||||||
|
|
||||||
|
const pageMarkdown = localPageMarkdownUtils.toMarkdown(page);
|
||||||
|
console.log(`Saving page ${filePath}`);
|
||||||
|
await fs.writeFile(filePath, pageMarkdown);
|
||||||
|
},
|
||||||
|
|
||||||
async getEmptyDirectories(): Promise<string[]> {
|
async getEmptyDirectories(): Promise<string[]> {
|
||||||
if (!(await directoryOrFileExists(basePath))) {
|
if (!(await directoryOrFileExists(basePath))) {
|
||||||
|
|||||||
Reference in New Issue
Block a user