diff --git a/nextjs/src/app/MyToaster.tsx b/nextjs/src/app/MyToaster.tsx
new file mode 100644
index 0000000..9038a29
--- /dev/null
+++ b/nextjs/src/app/MyToaster.tsx
@@ -0,0 +1,34 @@
+"use client";
+import React from "react";
+import { Toaster, ToastBar, useToaster } from "react-hot-toast";
+
+export const MyToaster = () => {
+ const { toasts, handlers } = useToaster({ duration: Infinity });
+ const { startPause, endPause } = handlers;
+
+ return (
+ //
+
+ );
+};
diff --git a/nextjs/src/app/course/[courseName]/calendar/Day.tsx b/nextjs/src/app/course/[courseName]/calendar/Day.tsx
index 5eefcd6..3c09557 100644
--- a/nextjs/src/app/course/[courseName]/calendar/Day.tsx
+++ b/nextjs/src/app/course/[courseName]/calendar/Day.tsx
@@ -107,7 +107,7 @@ function DraggableListItem({
e.dataTransfer.setData(
"draggableItem",
JSON.stringify({
- type: "assignment",
+ type,
item,
sourceModuleName: moduleName,
})
diff --git a/nextjs/src/app/globals.css b/nextjs/src/app/globals.css
index 65ac91e..d0976a0 100644
--- a/nextjs/src/app/globals.css
+++ b/nextjs/src/app/globals.css
@@ -1,3 +1,5 @@
+@import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap');
+
@tailwind base;
@tailwind components;
@tailwind utilities;
@@ -8,6 +10,10 @@
}
}
+:root {
+ font-family: "DM Sans", sans-serif;
+}
+
/* monaco editor */
.monaco-editor-background,
.monaco-editor .margin {
diff --git a/nextjs/src/app/layout.tsx b/nextjs/src/app/layout.tsx
index 58e8585..fa58ffd 100644
--- a/nextjs/src/app/layout.tsx
+++ b/nextjs/src/app/layout.tsx
@@ -5,6 +5,8 @@ import { Suspense } from "react";
import { getQueryClient } from "./providersQueryClientUtils";
import { hydrateCourses } from "@/hooks/hookHydration";
import { dehydrate, HydrationBoundary } from "@tanstack/react-query";
+import { ToastBar, Toaster } from "react-hot-toast";
+import { MyToaster } from "./MyToaster";
export const metadata: Metadata = {
title: "Canvas Manager 2.0",
@@ -21,7 +23,20 @@ export default async function RootLayout({
return (
+
+
+ {/* */}
+
diff --git a/nextjs/src/hooks/localCourse/assignmentHooks.ts b/nextjs/src/hooks/localCourse/assignmentHooks.ts
index 1687285..b4a8cab 100644
--- a/nextjs/src/hooks/localCourse/assignmentHooks.ts
+++ b/nextjs/src/hooks/localCourse/assignmentHooks.ts
@@ -9,6 +9,7 @@ import {
useMutation,
} from "@tanstack/react-query";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
+import { axiosClient } from "@/services/axiosUtils";
export const getAssignmentNamesQueryConfig = (
courseName: string,
@@ -22,7 +23,7 @@ export const getAssignmentNamesQueryConfig = (
"/modules/" +
encodeURIComponent(moduleName) +
"/assignments";
- const response = await axios.get(url);
+ const response = await axiosClient.get(url);
return response.data;
},
});
@@ -53,7 +54,7 @@ export const getAssignmentQueryConfig = (
encodeURIComponent(moduleName) +
"/assignments/" +
encodeURIComponent(assignmentName);
- const response = await axios.get(url);
+ const response = await axiosClient.get(url);
return response.data;
},
};
@@ -110,7 +111,7 @@ export const useUpdateAssignmentMutation = () => {
encodeURIComponent(moduleName) +
"/assignments/" +
encodeURIComponent(assignmentName);
- await axios.put(url, assignment);
+ await axiosClient.put(url, assignment);
},
onSuccess: (_, { moduleName, assignmentName }) => {
queryClient.invalidateQueries({
diff --git a/nextjs/src/hooks/localCourse/localCoursesHooks.ts b/nextjs/src/hooks/localCourse/localCoursesHooks.ts
index 8641711..fbbbd14 100644
--- a/nextjs/src/hooks/localCourse/localCoursesHooks.ts
+++ b/nextjs/src/hooks/localCourse/localCoursesHooks.ts
@@ -7,6 +7,7 @@ import {
} from "@tanstack/react-query";
import axios from "axios";
import { localCourseKeys } from "./localCourseKeys";
+import { axiosClient } from "@/services/axiosUtils";
import {
getAssignmentNamesQueryConfig,
getAssignmentQueryConfig,
@@ -23,7 +24,7 @@ export const useLocalCourseNamesQuery = () =>
queryKey: localCourseKeys.allCourses,
queryFn: async (): Promise => {
const url = `/api/courses`;
- const response = await axios.get(url);
+ const response = await axiosClient.get(url);
return response.data;
},
});
@@ -34,7 +35,7 @@ export const useLocalCourseSettingsQuery = () => {
queryKey: localCourseKeys.settings(courseName),
queryFn: async (): Promise => {
const url = `/api/courses/${courseName}/settings`;
- const response = await axios.get(url);
+ const response = await axiosClient.get(url);
return response.data;
},
});
@@ -46,7 +47,7 @@ export const useModuleNamesQuery = () => {
queryKey: localCourseKeys.moduleNames(courseName),
queryFn: async (): Promise => {
const url = `/api/courses/${courseName}/modules`;
- const response = await axios.get(url);
+ const response = await axiosClient.get(url);
return response.data;
},
});
@@ -185,7 +186,7 @@ export const useAllCourseDataQuery = () => {
// previousCourse: LocalCourse;
// }) => {
// const url = `/api/courses/${courseName}`;
-// await axios.put(url, body);
+// await axiosClient.put(url, body);
// },
// onSuccess: () => {
// queryClient.invalidateQueries({
diff --git a/nextjs/src/hooks/localCourse/pageHooks.ts b/nextjs/src/hooks/localCourse/pageHooks.ts
index 4c65e73..f74a119 100644
--- a/nextjs/src/hooks/localCourse/pageHooks.ts
+++ b/nextjs/src/hooks/localCourse/pageHooks.ts
@@ -9,6 +9,7 @@ import {
import axios from "axios";
import { localCourseKeys } from "./localCourseKeys";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
+import { axiosClient } from "@/services/axiosUtils";
export function getPageNamesQueryConfig(
courseName: string,
@@ -23,7 +24,7 @@ export function getPageNamesQueryConfig(
"/modules/" +
encodeURIComponent(moduleName) +
"/pages";
- const response = await axios.get(url);
+ const response = await axiosClient.get(url);
return response.data;
},
};
@@ -68,7 +69,7 @@ export function getPageQueryConfig(
"/pages/" +
encodeURIComponent(pageName);
try {
- const response = await axios.get(url);
+ const response = await axiosClient.get(url);
return response.data;
} catch (e) {
console.log("error getting page", e, url);
@@ -103,7 +104,7 @@ export const useUpdatePageMutation = () => {
encodeURIComponent(moduleName) +
"/pages/" +
encodeURIComponent(pageName);
- await axios.put(url, page);
+ await axiosClient.put(url, page);
},
onSuccess: (_, { moduleName, pageName }) => {
queryClient.invalidateQueries({
diff --git a/nextjs/src/hooks/localCourse/quizHooks.ts b/nextjs/src/hooks/localCourse/quizHooks.ts
index e4e6ff2..1029e39 100644
--- a/nextjs/src/hooks/localCourse/quizHooks.ts
+++ b/nextjs/src/hooks/localCourse/quizHooks.ts
@@ -6,9 +6,9 @@ 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";
export function getQuizNamesQueryConfig(courseName: string, moduleName: string) {
@@ -20,7 +20,7 @@ export function getQuizNamesQueryConfig(courseName: string, moduleName: string)
"/modules/" +
encodeURIComponent(moduleName) +
"/quizzes";
- const response = await axios.get(url);
+ const response = await axiosClient.get(url);
return response.data;
},
};
@@ -63,7 +63,7 @@ export function getQuizQueryConfig(
encodeURIComponent(moduleName) +
"/quizzes/" +
encodeURIComponent(quizName);
- const response = await axios.get(url);
+ const response = await axiosClient.get(url);
return response.data;
},
};
@@ -93,7 +93,7 @@ export const useUpdateQuizMutation = () => {
encodeURIComponent(moduleName) +
"/quizzes/" +
encodeURIComponent(quizName);
- await axios.put(url, quiz);
+ await axiosClient.put(url, quiz);
},
onSuccess: (_, { moduleName, quizName }) => {
queryClient.invalidateQueries({
diff --git a/nextjs/src/models/local/assignment/utils/assignmentMarkdownSerializer.ts b/nextjs/src/models/local/assignment/utils/assignmentMarkdownSerializer.ts
index bbb1ece..8ea2a9b 100644
--- a/nextjs/src/models/local/assignment/utils/assignmentMarkdownSerializer.ts
+++ b/nextjs/src/models/local/assignment/utils/assignmentMarkdownSerializer.ts
@@ -39,10 +39,16 @@ const settingsToMarkdown = (assignment: LocalAssignment) => {
export const assignmentMarkdownSerializer = {
toMarkdown(assignment: LocalAssignment): string {
- const settingsMarkdown = settingsToMarkdown(assignment);
- const rubricMarkdown = assignmentRubricToMarkdown(assignment);
- const assignmentMarkdown = `${settingsMarkdown}\n---\n\n${assignment.description}\n\n## Rubric\n\n${rubricMarkdown}`;
+ try {
+ const settingsMarkdown = settingsToMarkdown(assignment);
+ const rubricMarkdown = assignmentRubricToMarkdown(assignment);
+ const assignmentMarkdown = `${settingsMarkdown}\n---\n\n${assignment.description}\n\n## Rubric\n\n${rubricMarkdown}`;
- return assignmentMarkdown;
+ return assignmentMarkdown;
+ } catch (e) {
+ console.log(assignment);
+ console.log("Error converting assignment to markdown");
+ throw e;
+ }
},
};
diff --git a/nextjs/src/services/axiosUtils.ts b/nextjs/src/services/axiosUtils.ts
new file mode 100644
index 0000000..7e364d1
--- /dev/null
+++ b/nextjs/src/services/axiosUtils.ts
@@ -0,0 +1,27 @@
+import axios, { AxiosInstance, AxiosError } from "axios";
+import toast from "react-hot-toast";
+
+export const axiosClient: AxiosInstance = axios.create();
+
+axiosClient.interceptors.response.use(
+ (response) => response,
+ (error: AxiosError) => {
+ if (error.response) {
+ console.log("response error", error.response);
+ const responseErrorText =
+ typeof error.response.data === "object"
+ ? (error.response.data as any).error
+ : error.response.data;
+ toast.error(
+ `Error: ${error.response.status} - ${responseErrorText}, ${decodeURI(
+ error.response.config.url ?? ""
+ )}`
+ );
+ } else if (error.request) {
+ toast.error("Error: No response from server");
+ } else {
+ toast.error(`Error: ${error.message}`);
+ }
+ return Promise.reject(error);
+ }
+);