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 9b2229e..3017c04 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
@@ -7,6 +7,17 @@ import {
import { localAssignmentMarkdown } from "@/models/local/assignment/localAssignment";
import { useEffect, useState } from "react";
import AssignmentPreview from "./AssignmentPreview";
+import { getCourseUrl } from "@/services/urlUtils";
+import Link from "next/link";
+import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
+import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
+import {
+ useAddAssignmentToCanvasMutation,
+ useCanvasAssignmentsQuery,
+ useDeleteAssignmentFromCanvasMutation,
+} from "@/hooks/canvas/canvasAssignmentHooks";
+import { Spinner } from "@/components/Spinner";
+import { baseCanvasUrl } from "@/services/canvas/canvasServiceUtils";
export default function EditAssignment({
moduleName,
@@ -68,9 +79,71 @@ export default function EditAssignment({
-
-
-
+
+
+ );
+}
+
+function AssignmentButtons({
+ moduleName,
+ assignmentName,
+}: {
+ assignmentName: string;
+ moduleName: string;
+}) {
+ const { courseName } = useCourseContext();
+ const { data: settings } = useLocalCourseSettingsQuery();
+ const { data: canvasAssignments } = useCanvasAssignmentsQuery();
+ const { data: assignment } = useAssignmentQuery(moduleName, assignmentName);
+ const addToCanvas = useAddAssignmentToCanvasMutation();
+ const deleteFromCanvas = useDeleteAssignmentFromCanvasMutation();
+
+ const assignmentInCanvas = canvasAssignments.find(
+ (a) => a.name === assignmentName
+ );
+ return (
+
+ {(addToCanvas.isPending || deleteFromCanvas.isPending) &&
}
+ {assignmentInCanvas && !assignmentInCanvas.published && (
+
Not Published
+ )}
+ {!assignmentInCanvas && (
+
+ )}
+ {assignmentInCanvas && (
+
+ View in Canvas
+
+ )}
+ {assignmentInCanvas && (
+
+ )}
+
+ Go Back
+
);
}
diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx
index 99db4fc..6df3cf3 100644
--- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx
+++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuiz.tsx
@@ -135,10 +135,10 @@ function QuizButtons({
moduleName: string;
toggleHelp: () => void;
}) {
+ const { courseName } = useCourseContext();
+ const { data: settings } = useLocalCourseSettingsQuery();
const { data: canvasQuizzes } = useCanvasQuizzesQuery();
const { data: quiz } = useQuizQuery(moduleName, quizName);
- const { data: settings } = useLocalCourseSettingsQuery();
- const { courseName } = useCourseContext();
const addToCanvas = useAddQuizToCanvasMutation();
const deleteFromCanvas = useDeleteQuizFromCanvasMutation();
diff --git a/nextjs/src/components/editor/InnerMonacoEditor.tsx b/nextjs/src/components/editor/InnerMonacoEditor.tsx
index f273a16..81c7ea1 100644
--- a/nextjs/src/components/editor/InnerMonacoEditor.tsx
+++ b/nextjs/src/components/editor/InnerMonacoEditor.tsx
@@ -46,14 +46,6 @@ export default function InnerMonacoEditor({
}
}, [onChange, value]);
- useEffect(() => {
- window.addEventListener("resize", () => {
- if (editorRef.current) {
- editorRef.current.layout();
- }
- });
- }, []);
-
return (
+ ["canvas", canvasCourseId, "assignments"] as const,
+ assignment: (canvasCourseId: number, assignmentName: string) =>
+ ["canvas", canvasCourseId, "assignment", assignmentName] as const,
+};
+
+export const useCanvasAssignmentsQuery = () => {
+ const { data: settings } = useLocalCourseSettingsQuery();
+
+ return useSuspenseQuery({
+ queryKey: canvasAssignmentKeys.assignments(settings.canvasId),
+ queryFn: async () => canvasAssignmentService.getAll(settings.canvasId),
+ });
+};
+
+// export const useCanvasAssignmentsQuery = () => {
+// const { data: settings } = useLocalCourseSettingsQuery();
+// const { data: allAssignments } = useInnerCanvasAssignmentsQuery();
+
+// return useSuspenseQueries({
+// queries: allAssignments.map((a) => ({
+// queryKey: canvasAssignmentKeys.assignment(settings.canvasId, a.name),
+// queryFn: () => a,
+// })),
+// combine: (results) => ({
+// data: results.map((r) => r.data),
+// pending: results.some((r) => r.isPending),
+// }),
+// });
+// };
+
+export const useAddAssignmentToCanvasMutation = () => {
+ const { data: settings } = useLocalCourseSettingsQuery();
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: async (assignmnet: LocalAssignment) => {
+ const assignmentGroup = settings.assignmentGroups.find(
+ (g) => g.name === assignmnet.localAssignmentGroupName
+ );
+ await canvasAssignmentService.create(
+ settings.canvasId,
+ assignmnet,
+ assignmentGroup?.canvasId
+ );
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({
+ queryKey: canvasAssignmentKeys.assignments(settings.canvasId),
+ });
+ },
+ });
+};
+
+export const useDeleteAssignmentFromCanvasMutation = () => {
+ const { data: settings } = useLocalCourseSettingsQuery();
+ const queryClient = useQueryClient();
+ return useMutation({
+ mutationFn: async ({
+ canvasAssignmentId,
+ assignmentName,
+ }: {
+ canvasAssignmentId: number;
+ assignmentName: string;
+ }) => {
+ await canvasAssignmentService.delete(
+ settings.canvasId,
+ canvasAssignmentId,
+ assignmentName
+ );
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({
+ queryKey: canvasAssignmentKeys.assignments(settings.canvasId),
+ });
+ },
+ });
+};
diff --git a/nextjs/src/hooks/canvas/canvasQuizHooks.ts b/nextjs/src/hooks/canvas/canvasQuizHooks.ts
index be71d95..5d527a3 100644
--- a/nextjs/src/hooks/canvas/canvasQuizHooks.ts
+++ b/nextjs/src/hooks/canvas/canvasQuizHooks.ts
@@ -8,7 +8,8 @@ import { canvasQuizService } from "@/services/canvas/canvasQuizService";
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
export const canvasQuizKeys = {
- quizzes: (canvasCourseId: number) => ["canvas", canvasCourseId, "quizzes"],
+ quizzes: (canvasCourseId: number) =>
+ ["canvas", canvasCourseId, "quizzes"] as const,
};
export const useCanvasQuizzesQuery = () => {
@@ -29,16 +30,13 @@ export const useAddQuizToCanvasMutation = () => {
const assignmentGroup = settings.assignmentGroups.find(
(g) => g.name === quiz.localAssignmentGroupName
);
- console.log("starting");
await canvasQuizService.create(
settings.canvasId,
quiz,
assignmentGroup?.canvasId
);
- console.log("ending");
},
onSuccess: () => {
- console.log("invalidating");
queryClient.invalidateQueries({
queryKey: canvasQuizKeys.quizzes(settings.canvasId),
});
diff --git a/nextjs/src/hooks/localCourse/pageHooks.ts b/nextjs/src/hooks/localCourse/pageHooks.ts
index 805b2cc..3368180 100644
--- a/nextjs/src/hooks/localCourse/pageHooks.ts
+++ b/nextjs/src/hooks/localCourse/pageHooks.ts
@@ -6,7 +6,6 @@ import {
useSuspenseQueries,
useSuspenseQuery,
} from "@tanstack/react-query";
-import axios from "axios";
import { localCourseKeys } from "./localCourseKeys";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { axiosClient } from "@/services/axiosUtils";
diff --git a/nextjs/src/services/canvas/canvasAssignmentService.ts b/nextjs/src/services/canvas/canvasAssignmentService.ts
index 41a82ae..65ff0b0 100644
--- a/nextjs/src/services/canvas/canvasAssignmentService.ts
+++ b/nextjs/src/services/canvas/canvasAssignmentService.ts
@@ -6,6 +6,56 @@ import { markdownToHTMLSafe } from "../htmlMarkdownUtils";
import { CanvasRubricCreationResponse } from "@/models/canvas/assignments/canvasRubricCreationResponse";
import { assignmentPoints } from "@/models/local/assignment/utils/assignmentPointsUtils";
+const createRubric = async (
+ courseId: number,
+ assignmentCanvasId: number,
+ localAssignment: LocalAssignment
+) => {
+ const criterion = localAssignment.rubric.map((rubricItem, i) => ({
+ description: rubricItem.label,
+ points: rubricItem.points,
+ ratings: [
+ { description: "Full Marks", points: rubricItem.points },
+ { description: "No Marks", points: 0 },
+ ],
+ }));
+
+ const rubricBody = {
+ rubric_association_id: assignmentCanvasId,
+ rubric: {
+ title: `Rubric for Assignment: ${localAssignment.name}`,
+ association_id: assignmentCanvasId,
+ association_type: "Assignment",
+ use_for_grading: true,
+ criteria: criterion,
+ },
+ rubric_association: {
+ association_id: assignmentCanvasId,
+ association_type: "Assignment",
+ purpose: "grading",
+ use_for_grading: true,
+ },
+ };
+
+ const rubricUrl = `${canvasApi}/courses/${courseId}/rubrics`;
+ const rubricResponse = await axiosClient.post(
+ rubricUrl,
+ rubricBody
+ );
+
+ if (!rubricResponse.data) throw new Error("Failed to create rubric");
+
+ const assignmentPointAdjustmentUrl = `${canvasApi}/courses/${courseId}/assignments/${assignmentCanvasId}`;
+ const assignmentPointAdjustmentBody = {
+ assignment: { points_possible: assignmentPoints(localAssignment) },
+ };
+
+ await axiosClient.put(
+ assignmentPointAdjustmentUrl,
+ assignmentPointAdjustmentBody
+ );
+};
+
export const canvasAssignmentService = {
async getAll(courseId: number): Promise {
const url = `${canvasApi}/courses/${courseId}/assignments`;
@@ -23,24 +73,22 @@ export const canvasAssignmentService = {
canvasCourseId: number,
localAssignment: LocalAssignment,
canvasAssignmentGroupId?: number
- ): Promise {
+ ) {
console.log(`Creating assignment: ${localAssignment.name}`);
const url = `${canvasApi}/courses/${canvasCourseId}/assignments`;
const body = {
- assignment: {
- name: localAssignment.name,
- submission_types: localAssignment.submissionTypes.map((t) =>
- t.toString()
- ),
- allowed_extensions: localAssignment.allowedFileUploadExtensions.map(
- (e) => e.toString()
- ),
- description: markdownToHTMLSafe(localAssignment.description),
- due_at: localAssignment.dueAt,
- lock_at: localAssignment.lockAt,
- points_possible: assignmentPoints(localAssignment),
- assignment_group_id: canvasAssignmentGroupId,
- },
+ name: localAssignment.name,
+ submission_types: localAssignment.submissionTypes.map((t) =>
+ t.toString()
+ ),
+ allowed_extensions: localAssignment.allowedFileUploadExtensions.map((e) =>
+ e.toString()
+ ),
+ description: markdownToHTMLSafe(localAssignment.description),
+ due_at: localAssignment.dueAt,
+ lock_at: localAssignment.lockAt,
+ points_possible: assignmentPoints(localAssignment),
+ assignment_group_id: canvasAssignmentGroupId,
};
const response = await axiosClient.post(url, body);
@@ -48,11 +96,7 @@ export const canvasAssignmentService = {
if (!canvasAssignment) throw new Error("Created Canvas assignment is null");
- await this.createRubric(
- canvasCourseId,
- canvasAssignment.id,
- localAssignment
- );
+ await createRubric(canvasCourseId, canvasAssignment.id, localAssignment);
return canvasAssignment.id;
},
@@ -62,28 +106,26 @@ export const canvasAssignmentService = {
canvasAssignmentId: number,
localAssignment: LocalAssignment,
canvasAssignmentGroupId?: number
- ): Promise {
+ ) {
console.log(`Updating assignment: ${localAssignment.name}`);
const url = `${canvasApi}/courses/${courseId}/assignments/${canvasAssignmentId}`;
const body = {
- assignment: {
- name: localAssignment.name,
- submission_types: localAssignment.submissionTypes.map((t) =>
- t.toString()
- ),
- allowed_extensions: localAssignment.allowedFileUploadExtensions.map(
- (e) => e.toString()
- ),
- description: markdownToHTMLSafe(localAssignment.description),
- due_at: localAssignment.dueAt,
- lock_at: localAssignment.lockAt,
- points_possible: assignmentPoints(localAssignment),
- assignment_group_id: canvasAssignmentGroupId,
- },
+ name: localAssignment.name,
+ submission_types: localAssignment.submissionTypes.map((t) =>
+ t.toString()
+ ),
+ allowed_extensions: localAssignment.allowedFileUploadExtensions.map((e) =>
+ e.toString()
+ ),
+ description: markdownToHTMLSafe(localAssignment.description),
+ due_at: localAssignment.dueAt,
+ lock_at: localAssignment.lockAt,
+ points_possible: assignmentPoints(localAssignment),
+ assignment_group_id: canvasAssignmentGroupId,
};
await axiosClient.put(url, body);
- await this.createRubric(courseId, canvasAssignmentId, localAssignment);
+ await createRubric(courseId, canvasAssignmentId, localAssignment);
},
async delete(
@@ -100,54 +142,4 @@ export const canvasAssignmentService = {
throw new Error("Failed to delete assignment");
}
},
-
- async createRubric(
- courseId: number,
- assignmentCanvasId: number,
- localAssignment: LocalAssignment
- ): Promise {
- const criterion = localAssignment.rubric.map((rubricItem, i) => ({
- description: rubricItem.label,
- points: rubricItem.points,
- ratings: [
- { description: "Full Marks", points: rubricItem.points },
- { description: "No Marks", points: 0 },
- ],
- }));
-
- const rubricBody = {
- rubric_association_id: assignmentCanvasId,
- rubric: {
- title: `Rubric for Assignment: ${localAssignment.name}`,
- association_id: assignmentCanvasId,
- association_type: "Assignment",
- use_for_grading: true,
- criteria: criterion,
- },
- rubric_association: {
- association_id: assignmentCanvasId,
- association_type: "Assignment",
- purpose: "grading",
- use_for_grading: true,
- },
- };
-
- const rubricUrl = `${canvasApi}/courses/${courseId}/rubrics`;
- const rubricResponse = await axiosClient.post(
- rubricUrl,
- rubricBody
- );
-
- if (!rubricResponse.data) throw new Error("Failed to create rubric");
-
- const assignmentPointAdjustmentUrl = `${canvasApi}/courses/${courseId}/assignments/${assignmentCanvasId}`;
- const assignmentPointAdjustmentBody = {
- assignment: { points_possible: assignmentPoints(localAssignment) },
- };
-
- await axiosClient.put(
- assignmentPointAdjustmentUrl,
- assignmentPointAdjustmentBody
- );
- },
};