diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx index deba104..919c874 100644 --- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx +++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx @@ -179,7 +179,7 @@ function AssignmentButtons({ canvasIsRefetching || deleteFromCanvas.isPending || updateAssignment.isPending; - + return (
@@ -193,7 +193,7 @@ function AssignmentButtons({ {!assignmentInCanvas && ( diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/EditPageButtons.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/EditPageButtons.tsx index d0ac5eb..1e71ba7 100644 --- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/EditPageButtons.tsx +++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/EditPageButtons.tsx @@ -40,7 +40,7 @@ export default function EditPageButtons({ {requestIsPending && } {!pageInCanvas && ( )} {quizInCanvas && ( diff --git a/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts b/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts index e4ccaac..cc9d18c 100644 --- a/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts +++ b/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts @@ -8,6 +8,11 @@ import { } from "@tanstack/react-query"; import { useLocalCourseSettingsQuery } from "../localCourse/localCoursesHooks"; import { LocalAssignment } from "@/models/local/assignment/localAssignment"; +import { canvasModuleService } from "@/services/canvas/canvasModuleService"; +import { + useAddCanvasModuleMutation, + useCanvasModulesQuery, +} from "./canvasModuleHooks"; export const canvasAssignmentKeys = { assignments: (canvasCourseId: number) => @@ -43,18 +48,38 @@ export const useCanvasAssignmentsQuery = () => { export const useAddAssignmentToCanvasMutation = () => { const { data: settings } = useLocalCourseSettingsQuery(); + const { data: canvasModules } = useCanvasModulesQuery(); + const addModule = useAddCanvasModuleMutation(); const queryClient = useQueryClient(); return useMutation({ - mutationFn: async (assignment: LocalAssignment) => { + mutationFn: async ({ + assignment, + moduleName, + }: { + assignment: LocalAssignment; + moduleName: string; + }) => { const assignmentGroup = settings.assignmentGroups.find( (g) => g.name === assignment.localAssignmentGroupName ); - await canvasAssignmentService.create( + const canvasAssignmentId = await canvasAssignmentService.create( settings.canvasId, assignment, assignmentGroup?.canvasId ); + const canvasModule = canvasModules.find((c) => c.name === moduleName); + const moduleId = canvasModule + ? canvasModule.id + : await addModule.mutateAsync(moduleName); + + await canvasModuleService.createModuleItem( + settings.canvasId, + moduleId, + assignment.name, + "Assignment", + canvasAssignmentId + ); }, onSuccess: () => { queryClient.invalidateQueries({ diff --git a/nextjs/src/hooks/canvas/canvasPageHooks.ts b/nextjs/src/hooks/canvas/canvasPageHooks.ts index ae9e39d..0149eba 100644 --- a/nextjs/src/hooks/canvas/canvasPageHooks.ts +++ b/nextjs/src/hooks/canvas/canvasPageHooks.ts @@ -1,7 +1,16 @@ import { LocalCoursePage } from "@/models/local/page/localCoursePage"; import { canvasPageService } from "@/services/canvas/canvasPageService"; -import { useMutation, useQuery, useQueryClient, useSuspenseQuery } from "@tanstack/react-query"; +import { + useMutation, + useQueryClient, + useSuspenseQuery, +} from "@tanstack/react-query"; import { useLocalCourseSettingsQuery } from "../localCourse/localCoursesHooks"; +import { canvasModuleService } from "@/services/canvas/canvasModuleService"; +import { + useCanvasModulesQuery, + useAddCanvasModuleMutation, +} from "./canvasModuleHooks"; export const canvasPageKeys = { pagesInCourse: (courseCanvasId: number) => [ @@ -22,9 +31,35 @@ export const useCanvasPagesQuery = () => { export const useCreateCanvasPageMutation = () => { const { data: settings } = useLocalCourseSettingsQuery(); const queryClient = useQueryClient(); + const { data: canvasModules } = useCanvasModulesQuery(); + const addModule = useAddCanvasModuleMutation(); + return useMutation({ - mutationFn: async (page: LocalCoursePage) => - canvasPageService.create(settings.canvasId, page), + mutationFn: async ({ + page, + moduleName, + }: { + page: LocalCoursePage; + moduleName: string; + }) => { + const canvasPage = await canvasPageService.create( + settings.canvasId, + page + ); + + const canvasModule = canvasModules.find((c) => c.name === moduleName); + const moduleId = canvasModule + ? canvasModule.id + : await addModule.mutateAsync(moduleName); + + await canvasModuleService.createPageModuleItem( + settings.canvasId, + moduleId, + page.name, + canvasPage + ); + return canvasPage; + }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: canvasPageKeys.pagesInCourse(settings.canvasId), diff --git a/nextjs/src/hooks/canvas/canvasQuizHooks.ts b/nextjs/src/hooks/canvas/canvasQuizHooks.ts index 5d527a3..ec03da2 100644 --- a/nextjs/src/hooks/canvas/canvasQuizHooks.ts +++ b/nextjs/src/hooks/canvas/canvasQuizHooks.ts @@ -6,6 +6,8 @@ import { import { useLocalCourseSettingsQuery } from "../localCourse/localCoursesHooks"; import { canvasQuizService } from "@/services/canvas/canvasQuizService"; import { LocalQuiz } from "@/models/local/quiz/localQuiz"; +import { useAddCanvasModuleMutation, useCanvasModulesQuery } from "./canvasModuleHooks"; +import { canvasModuleService } from "@/services/canvas/canvasModuleService"; export const canvasQuizKeys = { quizzes: (canvasCourseId: number) => @@ -24,17 +26,38 @@ export const useCanvasQuizzesQuery = () => { export const useAddQuizToCanvasMutation = () => { const { data: settings } = useLocalCourseSettingsQuery(); const queryClient = useQueryClient(); + const { data: canvasModules } = useCanvasModulesQuery(); + const addModule = useAddCanvasModuleMutation(); return useMutation({ - mutationFn: async (quiz: LocalQuiz) => { + mutationFn: async ({ + quiz, + moduleName, + }: { + quiz: LocalQuiz; + moduleName: string; + }) => { const assignmentGroup = settings.assignmentGroups.find( (g) => g.name === quiz.localAssignmentGroupName ); - await canvasQuizService.create( + const canvasQuizId = await canvasQuizService.create( settings.canvasId, quiz, assignmentGroup?.canvasId ); + + const canvasModule = canvasModules.find((c) => c.name === moduleName); + const moduleId = canvasModule + ? canvasModule.id + : await addModule.mutateAsync(moduleName); + + await canvasModuleService.createModuleItem( + settings.canvasId, + moduleId, + quiz.name, + "Quiz", + canvasQuizId + ); }, onSuccess: () => { queryClient.invalidateQueries({ diff --git a/nextjs/src/services/canvas/canvasAssignmentService.ts b/nextjs/src/services/canvas/canvasAssignmentService.ts index 061718a..cce9f5d 100644 --- a/nextjs/src/services/canvas/canvasAssignmentService.ts +++ b/nextjs/src/services/canvas/canvasAssignmentService.ts @@ -6,6 +6,8 @@ import { markdownToHTMLSafe } from "../htmlMarkdownUtils"; import { CanvasRubricCreationResponse } from "@/models/canvas/assignments/canvasRubricCreationResponse"; import { assignmentPoints } from "@/models/local/assignment/utils/assignmentPointsUtils"; import { getDateFromString } from "@/models/local/timeUtils"; +import { canvasModuleService } from "./canvasModuleService"; +import { CanvasModule } from "@/models/canvas/modules/canvasModule"; export const canvasAssignmentService = { @@ -23,7 +25,7 @@ export const canvasAssignmentService = { async create( canvasCourseId: number, localAssignment: LocalAssignment, - canvasAssignmentGroupId?: number + canvasAssignmentGroupId?: number, ) { console.log(`Creating assignment: ${localAssignment.name}`); const url = `${canvasApi}/courses/${canvasCourseId}/assignments`; diff --git a/nextjs/src/services/canvas/canvasModuleService.ts b/nextjs/src/services/canvas/canvasModuleService.ts index 23d15b2..43784ba 100644 --- a/nextjs/src/services/canvas/canvasModuleService.ts +++ b/nextjs/src/services/canvas/canvasModuleService.ts @@ -24,9 +24,9 @@ export const canvasModuleService = { canvasCourseId: number, canvasModuleId: number, title: string, - type: string, + type: "Assignment" | "Quiz", contentId: number | string - ): Promise { + ) { console.log(`Creating new module item ${title}`); const url = `${canvasApi}/courses/${canvasCourseId}/modules/${canvasModuleId}/items`; const body = { module_item: { title, type, content_id: contentId } }; @@ -38,7 +38,7 @@ export const canvasModuleService = { canvasModuleId: number, title: string, canvasPage: CanvasPage - ): Promise { + ) { console.log(`Creating new module item ${title}`); const url = `${canvasApi}/courses/${canvasCourseId}/modules/${canvasModuleId}/items`; const body = { @@ -60,6 +60,7 @@ export const canvasModuleService = { name: moduleName, }, }; - await axiosClient.post(url, body); + const response = await axiosClient.post(url, body); + return response.data.id; }, }; diff --git a/nextjs/src/services/canvas/canvasQuizService.ts b/nextjs/src/services/canvas/canvasQuizService.ts index a3b545c..5dc24e8 100644 --- a/nextjs/src/services/canvas/canvasQuizService.ts +++ b/nextjs/src/services/canvas/canvasQuizService.ts @@ -127,7 +127,7 @@ export const canvasQuizService = { canvasCourseId: number, localQuiz: LocalQuiz, canvasAssignmentGroupId?: number - ): Promise { + ) { console.log("Creating quiz", localQuiz); const url = `${canvasApi}/courses/${canvasCourseId}/quizzes`; @@ -158,8 +158,6 @@ export const canvasQuizService = { }; const { data: canvasQuiz } = await axiosClient.post(url, body); - if (!canvasQuiz) throw new Error("Created quiz is null"); - await createQuizQuestions(canvasCourseId, canvasQuiz.id, localQuiz); return canvasQuiz.id; }, diff --git a/requests/assignment.http b/requests/assignment.http index 359feb0..274f383 100644 --- a/requests/assignment.http +++ b/requests/assignment.http @@ -140,3 +140,17 @@ Authorization: Bearer {{$dotenv CANVAS_TOKEN}} ### GET https://snow.instructure.com/api/v1/courses/871954 Authorization: Bearer {{$dotenv CANVAS_TOKEN}} + + +### +POST https://snow.instructure.com/api/v1/courses/960410/modules +Authorization: Bearer {{$dotenv CANVAS_TOKEN}} +Content-Type: application/json + +{ + "module": { + "name": "test module" + } +} + +