diff --git a/nextjs/.gitignore b/nextjs/.gitignore
index f73c6c9..253ad55 100644
--- a/nextjs/.gitignore
+++ b/nextjs/.gitignore
@@ -1,5 +1,8 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+.pnpm-store/
+
+
# dependencies
/node_modules
/.pnp
diff --git a/nextjs/run.sh b/nextjs/run.sh
index 4eefe0d..7379441 100755
--- a/nextjs/run.sh
+++ b/nextjs/run.sh
@@ -10,4 +10,13 @@ docker run -it --rm \
-v ~/projects/faculty/1810/2024-fall-alex/modules:/app/storage/intro_to_web \
-v ~/projects/faculty/4850_AdvancedFE/2024-fall-alex/modules:/app/storage/advanced_frontend \
node \
- bash -c "npm i && npm run dev -- -H 0.0.0.0"
+ sh -c "
+ mkdir -p ~/.npm-global && \
+ npm config set prefix '~/.npm-global' && \
+ export PATH=~/.npm-global/bin:\$PATH && \
+ npm install -g pnpm && \
+ pnpm install && pnpm start
+ "
+
+
+ # bash -c "npm i -g pnpm && pnpm i && pnpm run dev -- -H 0.0.0.0"
diff --git a/nextjs/src/app/api/canvas/[...rest]/route.ts b/nextjs/src/app/api/canvas/[...rest]/route.ts
index 7fef3ce..083efd4 100644
--- a/nextjs/src/app/api/canvas/[...rest]/route.ts
+++ b/nextjs/src/app/api/canvas/[...rest]/route.ts
@@ -17,13 +17,14 @@ const getUrl = (params: { rest: string[] }, req: NextRequest) => {
appendQueryParams(url, req);
- return url;
+ return url;``
};
const proxyResponseHeaders = (response: any) => {
const headers = new Headers();
Object.entries(response.headers).forEach(([key, value]) => {
- headers.set(key, value as string);
+ if (["link", "x-rate-limit-remaining"].includes(key))
+ headers.set(key, value as string);
});
return headers;
};
@@ -32,21 +33,19 @@ export async function GET(
req: NextRequest,
{ params }: { params: Promise<{ rest: string[] }> }
) {
- return withErrorHandling(async () => {
- try {
- const url = getUrl(await params, req);
+ try {
+ const url = getUrl(await params, req);
- const response = await axiosClient.get(url.toString());
-
- const headers = proxyResponseHeaders(response);
- return new NextResponse(JSON.stringify(response.data), { headers });
- } catch (error: any) {
- return new NextResponse(
- JSON.stringify({ error: error.message || "Canvas GET request failed" }),
- { status: error.response?.status || 500 }
- );
- }
- });
+ const response = await axiosClient.get(url.toString());
+ const headers = proxyResponseHeaders(response);
+ return NextResponse.json(response.data, { headers });
+ } catch (error: any) {
+ console.log("canvas get error", error, error?.message);
+ return NextResponse.json(
+ JSON.stringify({ error: error.message || "Canvas GET request failed" }),
+ { status: error.response?.status || 500 }
+ );
+ }
}
export async function POST(
diff --git a/nextjs/src/app/course/[courseName]/calendar/day/DayTitle.tsx b/nextjs/src/app/course/[courseName]/calendar/day/DayTitle.tsx
index 3753a28..83b0fac 100644
--- a/nextjs/src/app/course/[courseName]/calendar/day/DayTitle.tsx
+++ b/nextjs/src/app/course/[courseName]/calendar/day/DayTitle.tsx
@@ -6,11 +6,11 @@ import NewItemForm from "../../modules/NewItemForm";
import { DraggableItem } from "../../context/drag/draggingContext";
import { useDragStyleContext } from "../../context/drag/dragStyleContext";
import { getLectureForDay } from "@/models/local/lectureUtils";
-import { trpc } from "@/services/trpc/utils";
+import { useLecturesSuspenseQuery } from "@/hooks/localCourse/lectureHooks";
export function DayTitle({ day, dayAsDate }: { day: string; dayAsDate: Date }) {
const { courseName } = useCourseContext();
- const [weeks] = trpc.lectures.getLectures.useSuspenseQuery({ courseName });
+ const [weeks] = useLecturesSuspenseQuery();
const { setIsDragging } = useDragStyleContext();
const todaysLecture = getLectureForDay(weeks, dayAsDate);
const modal = useModal();
diff --git a/nextjs/src/app/course/[courseName]/calendar/day/useTodaysItems.tsx b/nextjs/src/app/course/[courseName]/calendar/day/useTodaysItems.tsx
index 614886a..0bcc630 100644
--- a/nextjs/src/app/course/[courseName]/calendar/day/useTodaysItems.tsx
+++ b/nextjs/src/app/course/[courseName]/calendar/day/useTodaysItems.tsx
@@ -33,7 +33,7 @@ export function useTodaysItems(day: string) {
}[] = todaysModules
? Object.keys(todaysModules).flatMap((moduleName) =>
todaysModules[moduleName].assignments.map((assignment) => {
- const canvasAssignment = canvasAssignments.find(
+ const canvasAssignment = canvasAssignments?.find(
(c) => c.name === assignment.name
);
return {
@@ -57,7 +57,7 @@ export function useTodaysItems(day: string) {
}[] = todaysModules
? Object.keys(todaysModules).flatMap((moduleName) =>
todaysModules[moduleName].quizzes.map((quiz) => {
- const canvasQuiz = canvasQuizzes.find((q) => q.title === quiz.name);
+ const canvasQuiz = canvasQuizzes?.find((q) => q.title === quiz.name);
return {
moduleName,
quiz,
@@ -79,7 +79,7 @@ export function useTodaysItems(day: string) {
}[] = todaysModules
? Object.keys(todaysModules).flatMap((moduleName) =>
todaysModules[moduleName].pages.map((page) => {
- const canvasPage = canvasPages.find((p) => p.title === page.name);
+ const canvasPage = canvasPages?.find((p) => p.title === page.name);
return {
moduleName,
page,
diff --git a/nextjs/src/app/course/[courseName]/context/CalendarItemsContextProvider.tsx b/nextjs/src/app/course/[courseName]/context/CalendarItemsContextProvider.tsx
index f05e8ae..014ff7c 100644
--- a/nextjs/src/app/course/[courseName]/context/CalendarItemsContextProvider.tsx
+++ b/nextjs/src/app/course/[courseName]/context/CalendarItemsContextProvider.tsx
@@ -18,9 +18,6 @@ export default function CalendarItemsContextProvider({
const { assignmentsAndModules, quizzesAndModules, pagesAndModules } =
useAllCourseDataQuery();
-
-
-
const assignmentsByModuleByDate = assignmentsAndModules.reduce(
(previous, { assignment, moduleName }) => {
const dueDay = getDateOnlyMarkdownString(
diff --git a/nextjs/src/app/course/[courseName]/context/drag/useItemDropOnDay.ts b/nextjs/src/app/course/[courseName]/context/drag/useItemDropOnDay.ts
index 2f1c43d..442259c 100644
--- a/nextjs/src/app/course/[courseName]/context/drag/useItemDropOnDay.ts
+++ b/nextjs/src/app/course/[courseName]/context/drag/useItemDropOnDay.ts
@@ -1,6 +1,9 @@
"use client";
import { useUpdateAssignmentMutation } from "@/hooks/localCourse/assignmentHooks";
-import { useLectureUpdateMutation } from "@/hooks/localCourse/lectureHooks";
+import {
+ useLecturesSuspenseQuery,
+ useLectureUpdateMutation,
+} from "@/hooks/localCourse/lectureHooks";
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
import { useUpdatePageMutation } from "@/hooks/localCourse/pageHooks";
import { LocalAssignment } from "@/models/local/assignment/localAssignment";
@@ -36,9 +39,7 @@ export function useItemDropOnDay({
const [settings] = useLocalCourseSettingsQuery();
const { courseName } = useCourseContext();
// const { data: weeks } = useLecturesByWeekQuery();
- const [weeks] = trpc.lectures.getLectures.useSuspenseQuery({
- courseName: settings.name,
- });
+ const [weeks] = useLecturesSuspenseQuery();
const updateQuizMutation = useUpdateQuizMutation();
const updateLectureMutation = useLectureUpdateMutation();
const updateAssignmentMutation = useUpdateAssignmentMutation();
diff --git a/nextjs/src/app/course/[courseName]/lecture/[lectureDay]/EditLecture.tsx b/nextjs/src/app/course/[courseName]/lecture/[lectureDay]/EditLecture.tsx
index 429f353..8c2fdfd 100644
--- a/nextjs/src/app/course/[courseName]/lecture/[lectureDay]/EditLecture.tsx
+++ b/nextjs/src/app/course/[courseName]/lecture/[lectureDay]/EditLecture.tsx
@@ -1,7 +1,7 @@
"use client";
import { MonacoEditor } from "@/components/editor/MonacoEditor";
-import { useLectureUpdateMutation } from "@/hooks/localCourse/lectureHooks";
+import { useLecturesSuspenseQuery, useLectureUpdateMutation } from "@/hooks/localCourse/lectureHooks";
import {
lectureToString,
parseLecture,
@@ -17,7 +17,7 @@ import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHoo
export default function EditLecture({ lectureDay }: { lectureDay: string }) {
const { courseName } = useCourseContext();
const [settings] = useLocalCourseSettingsQuery();
- const [weeks] = trpc.lectures.getLectures.useSuspenseQuery({ courseName });
+ const [weeks] = useLecturesSuspenseQuery();
const updateLecture = useLectureUpdateMutation();
const lecture = weeks
diff --git a/nextjs/src/app/course/[courseName]/lecture/[lectureDay]/preview/LecturePreviewPage.tsx b/nextjs/src/app/course/[courseName]/lecture/[lectureDay]/preview/LecturePreviewPage.tsx
index f8915b3..f9a2871 100644
--- a/nextjs/src/app/course/[courseName]/lecture/[lectureDay]/preview/LecturePreviewPage.tsx
+++ b/nextjs/src/app/course/[courseName]/lecture/[lectureDay]/preview/LecturePreviewPage.tsx
@@ -5,6 +5,7 @@ import { getCourseUrl, getLectureUrl } from "@/services/urlUtils";
import { useCourseContext } from "../../../context/courseContext";
import Link from "next/link";
import { trpc } from "@/services/trpc/utils";
+import { useLecturesSuspenseQuery } from "@/hooks/localCourse/lectureHooks";
export default function LecturePreviewPage({
lectureDay,
@@ -12,7 +13,7 @@ export default function LecturePreviewPage({
lectureDay: string;
}) {
const { courseName } = useCourseContext();
- const [weeks] = trpc.lectures.getLectures.useSuspenseQuery({ courseName });
+ const [weeks] = useLecturesSuspenseQuery();
const lecture = weeks
.flatMap(({ lectures }) => lectures.map((lecture) => lecture))
.find((l) => l.date === lectureDay);
diff --git a/nextjs/src/app/course/[courseName]/modules/ExpandableModule.tsx b/nextjs/src/app/course/[courseName]/modules/ExpandableModule.tsx
index 503d7b4..3a08863 100644
--- a/nextjs/src/app/course/[courseName]/modules/ExpandableModule.tsx
+++ b/nextjs/src/app/course/[courseName]/modules/ExpandableModule.tsx
@@ -21,8 +21,9 @@ import { getModuleItemUrl } from "@/services/urlUtils";
import { useCourseContext } from "../context/courseContext";
import { Expandable } from "../../../../components/Expandable";
import { useDragStyleContext } from "../context/drag/dragStyleContext";
-import { useAssignmentsQuery } from "@/hooks/localCourse/assignmentHooks";
import { useQuizzesQueries } from "@/hooks/localCourse/quizHooks";
+import { useAssignmentNamesQuery } from "@/hooks/localCourse/assignmentHooks";
+import { trpc } from "@/services/trpc/utils";
export default function ExpandableModule({
moduleName,
@@ -30,8 +31,14 @@ export default function ExpandableModule({
moduleName: string;
}) {
const { itemDropOnModule } = useDraggingContext();
-
- const [assignments ] = useAssignmentsQuery(moduleName);
+ const { courseName } = useCourseContext();
+ const [assignmentNames] = useAssignmentNamesQuery(moduleName);
+
+ const [assignments] = trpc.useSuspenseQueries((t) =>
+ assignmentNames.map((assignmentName) =>
+ t.assignment.getAssignment({ courseName, moduleName, assignmentName })
+ )
+ );
const [quizzes] = useQuizzesQueries(moduleName);
const [pages] = usePagesQueries(moduleName);
const modal = useModal();
diff --git a/nextjs/src/app/course/[courseName]/modules/ModuleCanvasStatus.tsx b/nextjs/src/app/course/[courseName]/modules/ModuleCanvasStatus.tsx
index ce21479..d584fc1 100644
--- a/nextjs/src/app/course/[courseName]/modules/ModuleCanvasStatus.tsx
+++ b/nextjs/src/app/course/[courseName]/modules/ModuleCanvasStatus.tsx
@@ -10,7 +10,7 @@ export function ModuleCanvasStatus({ moduleName }: { moduleName: string }) {
const { data: canvasModules } = useCanvasModulesQuery();
const addToCanvas = useAddCanvasModuleMutation();
- const canvasModule = canvasModules.find((c) => c.name === moduleName);
+ const canvasModule = canvasModules?.find((c) => c.name === moduleName);
return (
diff --git a/nextjs/src/app/course/[courseName]/modules/ModuleList.tsx b/nextjs/src/app/course/[courseName]/modules/ModuleList.tsx
index e438ffc..f3ed202 100644
--- a/nextjs/src/app/course/[courseName]/modules/ModuleList.tsx
+++ b/nextjs/src/app/course/[courseName]/modules/ModuleList.tsx
@@ -7,9 +7,9 @@ export default function ModuleList() {
const [moduleNames] = useModuleNamesQuery();
return (
- {/* {moduleNames.map((m) => (
+ {moduleNames.map((m) => (
- ))} */}
+ ))}
diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentButtons.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentButtons.tsx
index 95e2580..4a49ea9 100644
--- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentButtons.tsx
+++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentButtons.tsx
@@ -43,7 +43,7 @@ export function AssignmentButtons({
const [isLoading, setIsLoading] = useState(false);
const modal = useModal();
- const assignmentInCanvas = canvasAssignments.find(
+ const assignmentInCanvas = canvasAssignments?.find(
(a) => a.name === assignmentName
);
@@ -61,7 +61,7 @@ export function AssignmentButtons({
{anythingIsLoading &&
}
- {assignmentInCanvas && !assignmentInCanvas.published && (
+ {assignmentInCanvas && !assignmentInCanvas?.published && (
Not Published
)}
{!assignmentInCanvas && (
@@ -125,8 +125,8 @@ export function AssignmentButtons({
)}
diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/QuizButton.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/QuizButton.tsx
index 491ed89..3b1a756 100644
--- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/QuizButton.tsx
+++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/QuizButton.tsx
@@ -36,7 +36,7 @@ export function QuizButtons({
const deleteLocal = useDeleteQuizMutation();
const modal = useModal();
- const quizInCanvas = canvasQuizzes.find((c) => c.title === quizName);
+ const quizInCanvas = canvasQuizzes?.find((c) => c.title === quizName);
return (
@@ -90,8 +90,8 @@ export function QuizButtons({
{
+ await deleteLocal.mutateAsync({ moduleName, quizName, courseName });
router.push(getCourseUrl(courseName));
- deleteLocal.mutate({ moduleName, quizName, courseName });
}}
className="btn-danger"
>
diff --git a/nextjs/src/app/course/[courseName]/settings/AssignmentGroupManagement.tsx b/nextjs/src/app/course/[courseName]/settings/AssignmentGroupManagement.tsx
index 5633d45..ab9409f 100644
--- a/nextjs/src/app/course/[courseName]/settings/AssignmentGroupManagement.tsx
+++ b/nextjs/src/app/course/[courseName]/settings/AssignmentGroupManagement.tsx
@@ -12,7 +12,7 @@ import { useSetAssignmentGroupsMutation } from "@/hooks/canvas/canvasCourseHooks
export default function AssignmentGroupManagement() {
const [settings] = useLocalCourseSettingsQuery();
const updateSettings = useUpdateLocalCourseSettingsMutation();
- const applyInCanvas = useSetAssignmentGroupsMutation(settings.canvasId); // untested
+ // const applyInCanvas = useSetAssignmentGroupsMutation(settings.canvasId); // untested
const [assignmentGroups, setAssignmentGroups] = useState<
LocalAssignmentGroup[]
diff --git a/nextjs/src/app/newCourse/NewCourseForm.tsx b/nextjs/src/app/newCourse/NewCourseForm.tsx
index 3eddd72..bd9f797 100644
--- a/nextjs/src/app/newCourse/NewCourseForm.tsx
+++ b/nextjs/src/app/newCourse/NewCourseForm.tsx
@@ -13,7 +13,10 @@ import { useEmptyDirectoriesQuery } from "@/hooks/localCourse/storageDirectoryHo
import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel";
import { CanvasEnrollmentTermModel } from "@/models/canvas/enrollmentTerms/canvasEnrollmentTermModel";
import { AssignmentSubmissionType } from "@/models/local/assignment/assignmentSubmissionType";
-import { DayOfWeek } from "@/models/local/localCourseSettings";
+import {
+ DayOfWeek,
+ LocalCourseSettings,
+} from "@/models/local/localCourseSettings";
import { getCourseUrl } from "@/services/urlUtils";
import { useRouter } from "next/navigation";
import React, { useMemo, useState } from "react";
@@ -47,6 +50,9 @@ export default function NewCourseForm() {
const [selectedDirectory, setSelectedDirectory] = useState<
string | undefined
>();
+ const [courseToImport, setCourseToImport] = useState<
+ LocalCourseSettings | undefined
+ >();
const createCourse = useCreateLocalCourseMutation();
const formIsComplete =
@@ -71,17 +77,34 @@ export default function NewCourseForm() {
setSelectedDirectory={setSelectedDirectory}
selectedDaysOfWeek={selectedDaysOfWeek}
setSelectedDaysOfWeek={setSelectedDaysOfWeek}
+ courseToImport={courseToImport}
+ setCourseToImport={setCourseToImport}
/>
)}
{
+ onClick={async () => {
if (formIsComplete) {
- createCourse
- .mutateAsync({
- settings: {
+ const newSettings: LocalCourseSettings = courseToImport
+ ? {
+ ...courseToImport,
+ name: selectedDirectory,
+ daysOfWeek: selectedDaysOfWeek,
+ canvasId: selectedCanvasCourse.id,
+ startDate: selectedTerm.start_at ?? "",
+ endDate: selectedTerm.end_at ?? "",
+ holidays: [],
+ assignmentGroups: courseToImport.assignmentGroups.map(
+ (assignmentGroup) => {
+ const { canvasId, ...groupWithoutCanvas } =
+ assignmentGroup;
+ return groupWithoutCanvas;
+ }
+ ),
+ }
+ : {
name: selectedDirectory,
assignmentGroups: [],
daysOfWeek: selectedDaysOfWeek,
@@ -96,11 +119,12 @@ export default function NewCourseForm() {
defaultFileUploadTypes: ["pdf", "png", "jpg", "jpeg"],
defaultLockHoursOffset: 0,
holidays: [],
- },
- })
- .then(() => {
- router.push(getCourseUrl(selectedDirectory));
- });
+ };
+ await createCourse.mutateAsync({
+ settings: newSettings,
+ settingsFromCourseToImport: courseToImport,
+ });
+ router.push(getCourseUrl(selectedDirectory));
}
}}
>
@@ -125,6 +149,8 @@ function OtherSettings({
setSelectedDirectory,
selectedDaysOfWeek,
setSelectedDaysOfWeek,
+ courseToImport,
+ setCourseToImport,
}: {
selectedTerm: CanvasEnrollmentTermModel;
selectedCanvasCourse: CanvasCourseModel | undefined;
@@ -137,15 +163,21 @@ function OtherSettings({
>;
selectedDaysOfWeek: DayOfWeek[];
setSelectedDaysOfWeek: React.Dispatch>;
+ courseToImport: LocalCourseSettings | undefined;
+ setCourseToImport: React.Dispatch<
+ React.SetStateAction
+ >;
}) {
const { data: canvasCourses } = useCourseListInTermQuery(selectedTerm.id);
const [allSettings] = useLocalCoursesSettingsQuery();
const [emptyDirectories] = useEmptyDirectoriesQuery();
const populatedCanvasCourseIds = allSettings.map((s) => s.canvasId);
- const availableCourses = canvasCourses.filter(
- (canvas) => !populatedCanvasCourseIds.includes(canvas.id)
- );
+ const availableCourses =
+ canvasCourses?.filter(
+ (canvas: CanvasCourseModel) =>
+ !populatedCanvasCourseIds.includes(canvas.id)
+ ) ?? [];
return (
<>
@@ -183,6 +215,13 @@ function OtherSettings({
}}
/>
+ c.name}
+ />
>
);
}
diff --git a/nextjs/src/app/todaysLectures/OneCourseLectures.tsx b/nextjs/src/app/todaysLectures/OneCourseLectures.tsx
index aaa9e8d..68e9cf7 100644
--- a/nextjs/src/app/todaysLectures/OneCourseLectures.tsx
+++ b/nextjs/src/app/todaysLectures/OneCourseLectures.tsx
@@ -5,12 +5,11 @@ import { getLecturePreviewUrl } from "@/services/urlUtils";
import Link from "next/link";
import { useCourseContext } from "../course/[courseName]/context/courseContext";
import { getLectureForDay } from "@/models/local/lectureUtils";
-import { trpc } from "@/services/trpc/utils";
+import { useLecturesSuspenseQuery as useLecturesQuery } from "@/hooks/localCourse/lectureHooks";
export default function OneCourseLectures() {
const { courseName } = useCourseContext();
- // const { data: weeks } = useLecturesByWeekQuery();
- const [weeks] = trpc.lectures.getLectures.useSuspenseQuery({ courseName });
+ const [weeks] = useLecturesQuery();
const dayAsDate = new Date();
const dayAsString = getDateOnlyMarkdownString(dayAsDate);
diff --git a/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts b/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts
index d7cceda..d2a4920 100644
--- a/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts
+++ b/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts
@@ -1,11 +1,5 @@
import { canvasAssignmentService } from "@/services/canvas/canvasAssignmentService";
-import { canvasService } from "@/services/canvas/canvasService";
-import {
- useMutation,
- useQueryClient,
- useSuspenseQueries,
- useSuspenseQuery,
-} from "@tanstack/react-query";
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useLocalCourseSettingsQuery } from "../localCourse/localCoursesHooks";
import { LocalAssignment } from "@/models/local/assignment/localAssignment";
import { canvasModuleService } from "@/services/canvas/canvasModuleService";
@@ -24,28 +18,12 @@ export const canvasAssignmentKeys = {
export const useCanvasAssignmentsQuery = () => {
const [settings] = useLocalCourseSettingsQuery();
- return useSuspenseQuery({
+ return useQuery({
queryKey: canvasAssignmentKeys.assignments(settings.canvasId),
queryFn: async () => canvasAssignmentService.getAll(settings.canvasId),
});
};
-// export const useCanvasAssignmentsQuery = () => {
-// const [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 [settings] = useLocalCourseSettingsQuery();
const { data: canvasModules } = useCanvasModulesQuery();
@@ -60,6 +38,11 @@ export const useAddAssignmentToCanvasMutation = () => {
assignment: LocalAssignment;
moduleName: string;
}) => {
+ if (!canvasModules) {
+ console.log("cannot add assignment until modules loaded");
+ return;
+ }
+
const assignmentGroup = settings.assignmentGroups.find(
(g) => g.name === assignment.localAssignmentGroupName
);
diff --git a/nextjs/src/hooks/canvas/canvasCourseHooks.ts b/nextjs/src/hooks/canvas/canvasCourseHooks.ts
index fbc0f6c..f340a14 100644
--- a/nextjs/src/hooks/canvas/canvasCourseHooks.ts
+++ b/nextjs/src/hooks/canvas/canvasCourseHooks.ts
@@ -1,7 +1,9 @@
+import { CanvasAssignmentGroup } from "@/models/canvas/assignments/canvasAssignmentGroup";
+import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel";
import { LocalAssignmentGroup } from "@/models/local/assignment/localAssignmentGroup";
import { canvasAssignmentGroupService } from "@/services/canvas/canvasAssignmentGroupService";
import { canvasService } from "@/services/canvas/canvasService";
-import { useMutation, useSuspenseQuery } from "@tanstack/react-query";
+import { useMutation, useQuery } from "@tanstack/react-query";
export const canvasCourseKeys = {
courseDetails: (canavasId: number) =>
@@ -13,34 +15,37 @@ export const canvasCourseKeys = {
};
export const useCourseListInTermQuery = (canvasTermId: number | undefined) =>
- useSuspenseQuery({
+ useQuery({
queryKey: canvasCourseKeys.courseListInTerm(canvasTermId),
- queryFn: async () =>
+ queryFn: async (): Promise =>
canvasTermId ? await canvasService.getCourses(canvasTermId) : [],
+ enabled: !!canvasTermId,
});
-export const useCanvasCourseQuery = (canvasId: number) =>
- useSuspenseQuery({
- queryKey: canvasCourseKeys.courseDetails(canvasId),
- queryFn: async () => await canvasService.getCourse(canvasId),
- });
+// export const useCanvasCourseQuery = (canvasId: number) =>
+// useQuery({
+// queryKey: canvasCourseKeys.courseDetails(canvasId),
+// queryFn: async () => await canvasService.getCourse(canvasId),
+// });
export const useSetAssignmentGroupsMutation = (canvasId: number) => {
const { data: canvasAssignmentGroups } = useAssignmentGroupsQuery(canvasId);
return useMutation({
mutationFn: async (localAssignmentGroups: LocalAssignmentGroup[]) => {
+ if (!canvasAssignmentGroups) return;
+
const localNames = localAssignmentGroups.map((g) => g.name);
const groupsToDelete = canvasAssignmentGroups.filter(
- (c) => !localNames.includes(c.name)
+ (c: CanvasAssignmentGroup) => !localNames.includes(c.name)
);
await Promise.all([
...groupsToDelete.map(
- async (g) =>
+ async (g: CanvasAssignmentGroup) =>
await canvasAssignmentGroupService.delete(canvasId, g.id, g.name)
),
...localAssignmentGroups.map(async (group) => {
const canvasGroup = canvasAssignmentGroups.find(
- (c) => c.name === group.name
+ (c: CanvasAssignmentGroup) => c.name === group.name
);
if (!canvasGroup) {
await canvasAssignmentGroupService.create(canvasId, group);
@@ -55,8 +60,8 @@ export const useSetAssignmentGroupsMutation = (canvasId: number) => {
};
export const useAssignmentGroupsQuery = (canvasId: number) => {
- return useSuspenseQuery({
+ return useQuery({
queryKey: canvasCourseKeys.assignmentGroups(canvasId),
- queryFn: async () => await canvasAssignmentGroupService.getAll(canvasId),
+ queryFn: async (): Promise => await canvasAssignmentGroupService.getAll(canvasId),
});
};
diff --git a/nextjs/src/hooks/canvas/canvasModuleHooks.ts b/nextjs/src/hooks/canvas/canvasModuleHooks.ts
index b8f8a7e..0903f3f 100644
--- a/nextjs/src/hooks/canvas/canvasModuleHooks.ts
+++ b/nextjs/src/hooks/canvas/canvasModuleHooks.ts
@@ -1,8 +1,8 @@
import { canvasModuleService } from "@/services/canvas/canvasModuleService";
import {
useMutation,
+ useQuery,
useQueryClient,
- useSuspenseQuery,
} from "@tanstack/react-query";
import { useLocalCourseSettingsQuery } from "../localCourse/localCoursesHooks";
@@ -12,7 +12,7 @@ export const canvasCourseModuleKeys = {
export const useCanvasModulesQuery = () => {
const [settings] = useLocalCourseSettingsQuery();
- return useSuspenseQuery({
+ return useQuery({
queryKey: canvasCourseModuleKeys.modules(settings.canvasId),
queryFn: async () =>
await canvasModuleService.getCourseModules(settings.canvasId),
diff --git a/nextjs/src/hooks/canvas/canvasPageHooks.ts b/nextjs/src/hooks/canvas/canvasPageHooks.ts
index 190f823..d181679 100644
--- a/nextjs/src/hooks/canvas/canvasPageHooks.ts
+++ b/nextjs/src/hooks/canvas/canvasPageHooks.ts
@@ -1,10 +1,6 @@
import { LocalCoursePage } from "@/models/local/page/localCoursePage";
import { canvasPageService } from "@/services/canvas/canvasPageService";
-import {
- useMutation,
- useQueryClient,
- useSuspenseQuery,
-} from "@tanstack/react-query";
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useLocalCourseSettingsQuery } from "../localCourse/localCoursesHooks";
import { canvasModuleService } from "@/services/canvas/canvasModuleService";
import {
@@ -22,7 +18,7 @@ export const canvasPageKeys = {
export const useCanvasPagesQuery = () => {
const [settings] = useLocalCourseSettingsQuery();
- return useSuspenseQuery({
+ return useQuery({
queryKey: canvasPageKeys.pagesInCourse(settings.canvasId),
queryFn: async () => await canvasPageService.getAll(settings.canvasId),
});
@@ -42,6 +38,10 @@ export const useCreateCanvasPageMutation = () => {
page: LocalCoursePage;
moduleName: string;
}) => {
+ if (!canvasModules) {
+ console.log("cannot add page until modules loaded");
+ return;
+ }
const canvasPage = await canvasPageService.create(
settings.canvasId,
page
diff --git a/nextjs/src/hooks/canvas/canvasQuizHooks.ts b/nextjs/src/hooks/canvas/canvasQuizHooks.ts
index 80776c7..cdfb68c 100644
--- a/nextjs/src/hooks/canvas/canvasQuizHooks.ts
+++ b/nextjs/src/hooks/canvas/canvasQuizHooks.ts
@@ -1,7 +1,7 @@
import {
useMutation,
+ useQuery,
useQueryClient,
- useSuspenseQuery,
} from "@tanstack/react-query";
import { useLocalCourseSettingsQuery } from "../localCourse/localCoursesHooks";
import { canvasQuizService } from "@/services/canvas/canvasQuizService";
@@ -20,7 +20,7 @@ export const canvasQuizKeys = {
export const useCanvasQuizzesQuery = () => {
const [settings] = useLocalCourseSettingsQuery();
- return useSuspenseQuery({
+ return useQuery({
queryKey: canvasQuizKeys.quizzes(settings.canvasId),
queryFn: async () => canvasQuizService.getAll(settings.canvasId),
});
@@ -40,6 +40,10 @@ export const useAddQuizToCanvasMutation = () => {
quiz: LocalQuiz;
moduleName: string;
}) => {
+ if (!canvasModules) {
+ console.log("cannot add quiz until modules loaded");
+ return;
+ }
const assignmentGroup = settings.assignmentGroups.find(
(g) => g.name === quiz.localAssignmentGroupName
);
diff --git a/nextjs/src/hooks/hookHydration.ts b/nextjs/src/hooks/hookHydration.ts
deleted file mode 100644
index 480a895..0000000
--- a/nextjs/src/hooks/hookHydration.ts
+++ /dev/null
@@ -1,208 +0,0 @@
-// import { QueryClient } from "@tanstack/react-query";
-// import { localCourseKeys } from "./localCourse/localCourseKeys";
-// import { fileStorageService } from "@/services/fileStorage/fileStorageService";
-// import { LocalCourseSettings } from "@/models/local/localCourseSettings";
-// import { canvasAssignmentService } from "@/services/canvas/canvasAssignmentService";
-// import { canvasAssignmentKeys } from "./canvas/canvasAssignmentHooks";
-// import { LocalAssignment } from "@/models/local/assignment/localAssignment";
-// import { LocalCoursePage } from "@/models/local/page/localCoursePage";
-// import { LocalQuiz } from "@/models/local/quiz/localQuiz";
-// import { canvasQuizService } from "@/services/canvas/canvasQuizService";
-// import { canvasPageService } from "@/services/canvas/canvasPageService";
-// import { canvasQuizKeys } from "./canvas/canvasQuizHooks";
-// import { canvasPageKeys } from "./canvas/canvasPageHooks";
-// // import { getLecturesQueryConfig } from "./localCourse/lectureHooks";
-
-// // https://tanstack.com/query/latest/docs/framework/react/guides/ssr
-// export const hydrateCourses = async (queryClient: QueryClient) => {
-// const allSettings = await fileStorageService.settings.getAllCoursesSettings();
-// await queryClient.prefetchQuery({
-// queryKey: localCourseKeys.allCoursesSettings,
-// queryFn: () => allSettings,
-// });
-
-// await Promise.all(
-// allSettings.map(async (settings) => {
-// await hydrateCourse(queryClient, settings);
-// })
-// );
-// };
-
-// export const hydrateCourse = async (
-// queryClient: QueryClient,
-// courseSettings: LocalCourseSettings
-// ) => {
-// const courseName = courseSettings.name;
-// const moduleNames = await fileStorageService.modules.getModuleNames(
-// courseName
-// );
-
-// // await Promise.all(
-// // moduleNames.map(async (moduleName) => {
-// // const assignments = await trpcHelpers.assignment.getAllAssignments.fetch({
-// // courseName,
-// // moduleName,
-// // });
-// // await Promise.all(
-// // assignments.map(
-// // async (a) =>
-// // await trpcHelpers.assignment.getAssignment.fetch({
-// // courseName,
-// // moduleName,
-// // assignmentName: a.name,
-// // })
-// // )
-// // );
-// // })
-// // );
-
-// const modulesData = await Promise.all(
-// moduleNames.map((moduleName) => loadAllModuleData(courseName, moduleName))
-// );
-
-// // await queryClient.prefetchQuery(getLecturesQueryConfig(courseName));
-
-// await queryClient.prefetchQuery({
-// queryKey: localCourseKeys.settings(courseName),
-// queryFn: () => courseSettings,
-// });
-// await queryClient.prefetchQuery({
-// queryKey: localCourseKeys.moduleNames(courseName),
-// queryFn: () => moduleNames,
-// });
-
-// await Promise.all(
-// modulesData.map((d) => hydrateModuleData(d, courseName, queryClient))
-// );
-// };
-
-// export const hydrateCanvasCourse = async (
-// canvasCourseId: number,
-// queryClient: QueryClient
-// ) => {
-// await Promise.all([
-// queryClient.prefetchQuery({
-// queryKey: canvasAssignmentKeys.assignments(canvasCourseId),
-// queryFn: async () => await canvasAssignmentService.getAll(canvasCourseId),
-// }),
-// queryClient.prefetchQuery({
-// queryKey: canvasQuizKeys.quizzes(canvasCourseId),
-// queryFn: async () => await canvasQuizService.getAll(canvasCourseId),
-// }),
-// queryClient.prefetchQuery({
-// queryKey: canvasPageKeys.pagesInCourse(canvasCourseId),
-// queryFn: async () => await canvasPageService.getAll(canvasCourseId),
-// }),
-// ]);
-// };
-
-// const loadAllModuleData = async (courseName: string, moduleName: string) => {
-// const [pages, quizzes] = await Promise.all([
-// // await fileStorageService.assignments.getAssignmentNames(
-// // courseName,
-// // moduleName
-// // ),
-// await fileStorageService.pages.getPages(courseName, moduleName),
-// await fileStorageService.quizzes.getQuizzes(courseName, moduleName),
-// ]);
-
-// // const [assignments] = await Promise.all([
-// // await Promise.all(
-// // assignmentNames.map(async (assignmentName) => {
-// // try {
-// // return await fileStorageService.assignments.getAssignment(
-// // courseName,
-// // moduleName,
-// // assignmentName
-// // );
-// // } catch (error) {
-// // console.error(`Error fetching assignment: ${assignmentName}`, error);
-// // return null; // or any other placeholder value
-// // }
-// // })
-// // ),
-// // ]);
-
-// // const assignmentsLoaded = assignments.filter((a) => a !== null);
-// return {
-// moduleName,
-// // assignments: assignmentsLoaded,
-// quizzes,
-// pages,
-// };
-// };
-
-// const hydrateModuleData = async (
-// {
-// moduleName,
-// // assignments,
-// quizzes,
-// pages,
-// }: {
-// moduleName: string;
-// // assignments: LocalAssignment[];
-// quizzes: LocalQuiz[];
-// pages: LocalCoursePage[];
-// },
-// courseName: string,
-// queryClient: QueryClient
-// ) => {
-// // await queryClient.prefetchQuery({
-// // queryKey: localCourseKeys.allItemsOfType(
-// // courseName,
-// // moduleName,
-// // "Assignment"
-// // ),
-// // queryFn: () => assignments,
-// // });
-// await queryClient.prefetchQuery({
-// queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, "Quiz"),
-// queryFn: () => quizzes,
-// });
-// await queryClient.prefetchQuery({
-// queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, "Page"),
-// queryFn: () => pages,
-// });
-// // await Promise.all(
-// // assignments.map(
-// // async (assignment) =>
-// // await queryClient.prefetchQuery({
-// // queryKey: localCourseKeys.itemOfType(
-// // courseName,
-// // moduleName,
-// // assignment.name,
-// // "Assignment"
-// // ),
-// // queryFn: () => assignment,
-// // })
-// // )
-// // );
-// await Promise.all(
-// quizzes.map(
-// async (quiz) =>
-// await queryClient.prefetchQuery({
-// queryKey: localCourseKeys.itemOfType(
-// courseName,
-// moduleName,
-// quiz.name,
-// "Quiz"
-// ),
-// queryFn: () => quiz,
-// })
-// )
-// );
-// await Promise.all(
-// pages.map(
-// async (page) =>
-// await queryClient.prefetchQuery({
-// queryKey: localCourseKeys.itemOfType(
-// courseName,
-// moduleName,
-// page.name,
-// "Page"
-// ),
-// queryFn: () => page,
-// })
-// )
-// );
-// };
diff --git a/nextjs/src/hooks/localCourse/assignmentHooks.ts b/nextjs/src/hooks/localCourse/assignmentHooks.ts
index 5f68633..807a33d 100644
--- a/nextjs/src/hooks/localCourse/assignmentHooks.ts
+++ b/nextjs/src/hooks/localCourse/assignmentHooks.ts
@@ -14,13 +14,18 @@ export const useAssignmentQuery = (
});
};
-export const useAssignmentsQuery = (moduleName: string) => {
+export const useAssignmentNamesQuery = (moduleName: string) => {
const { courseName } = useCourseContext();
console.log("rendering all assignments query");
- return trpc.assignment.getAllAssignments.useSuspenseQuery({
- moduleName,
- courseName,
- });
+ return trpc.assignment.getAllAssignments.useSuspenseQuery(
+ {
+ moduleName,
+ courseName,
+ },
+ {
+ select: (assignments) => assignments.map((a) => a.name),
+ }
+ );
};
export const useUpdateAssignmentMutation = () => {
@@ -57,8 +62,18 @@ export const useCreateAssignmentMutation = () => {
export const useDeleteAssignmentMutation = () => {
const utils = trpc.useUtils();
return trpc.assignment.deleteAssignment.useMutation({
- onSuccess: (_, { courseName, moduleName }) => {
+ onSuccess: (_, { courseName, moduleName, assignmentName }) => {
utils.assignment.getAllAssignments.invalidate({ courseName, moduleName });
+ utils.assignment.getAssignment.invalidate(
+ {
+ courseName,
+ moduleName,
+ assignmentName,
+ },
+ {
+ refetchType: "all",
+ }
+ );
},
});
};
diff --git a/nextjs/src/hooks/localCourse/lectureHooks.ts b/nextjs/src/hooks/localCourse/lectureHooks.ts
index fa481ac..f2d2cc0 100644
--- a/nextjs/src/hooks/localCourse/lectureHooks.ts
+++ b/nextjs/src/hooks/localCourse/lectureHooks.ts
@@ -1,5 +1,11 @@
+import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { trpc } from "@/services/trpc/utils";
+export const useLecturesSuspenseQuery = () => {
+ const { courseName } = useCourseContext();
+ return trpc.lectures.getLectures.useSuspenseQuery({ courseName });
+};
+
export const useLectureUpdateMutation = () => {
const utils = trpc.useUtils();
return trpc.lectures.updateLecture.useMutation({
diff --git a/nextjs/src/hooks/localCourse/pageHooks.ts b/nextjs/src/hooks/localCourse/pageHooks.ts
index 2c23450..1621f11 100644
--- a/nextjs/src/hooks/localCourse/pageHooks.ts
+++ b/nextjs/src/hooks/localCourse/pageHooks.ts
@@ -41,7 +41,12 @@ export const useDeletePageMutation = () => {
const utils = trpc.useUtils();
return trpc.page.deletePage.useMutation({
onSuccess: (_, { courseName, moduleName, pageName }) => {
- utils.page.getAllPages.invalidate({ courseName, moduleName });
+ utils.page.getAllPages.invalidate(
+ { courseName, moduleName },
+ {
+ refetchType: "all",
+ }
+ );
utils.page.getPage.invalidate({ courseName, moduleName, pageName });
},
});
diff --git a/nextjs/src/hooks/localCourse/quizHooks.ts b/nextjs/src/hooks/localCourse/quizHooks.ts
index c1fa248..847fe2a 100644
--- a/nextjs/src/hooks/localCourse/quizHooks.ts
+++ b/nextjs/src/hooks/localCourse/quizHooks.ts
@@ -41,7 +41,10 @@ export const useDeleteQuizMutation = () => {
const utils = trpc.useUtils();
return trpc.quiz.deleteQuiz.useMutation({
onSuccess: (_, { courseName, moduleName, quizName }) => {
- utils.quiz.getAllQuizzes.invalidate({ courseName, moduleName });
+ utils.quiz.getAllQuizzes.invalidate(
+ { courseName, moduleName },
+ { refetchType: "all" }
+ );
utils.quiz.getQuiz.invalidate({ courseName, moduleName, quizName });
},
});
diff --git a/nextjs/src/models/local/semesterTransferUtils.ts b/nextjs/src/models/local/semesterTransferUtils.ts
index 4a4cac7..f113a61 100644
--- a/nextjs/src/models/local/semesterTransferUtils.ts
+++ b/nextjs/src/models/local/semesterTransferUtils.ts
@@ -1,11 +1,10 @@
import { LocalAssignment } from "./assignment/localAssignment";
+import { Lecture } from "./lecture";
import { LocalCoursePage } from "./page/localCoursePage";
import { LocalQuiz } from "./quiz/localQuiz";
import {
dateToMarkdownString,
- getDateFromString,
getDateFromStringOrThrow,
- getDateOnlyMarkdownString,
} from "./timeUtils";
export const prepAssignmentForNewSemester = (
@@ -69,6 +68,24 @@ export const prepPageForNewSemester = (
page.dueAt,
};
};
+export const prepLectureForNewSemester = (
+ lecture: Lecture,
+ oldSemesterStartDate: string,
+ newSemesterStartDate: string
+): Lecture => {
+ const updatedText = replaceClassroomUrl(lecture.content);
+ const newDate = newDateOffset(
+ lecture.date,
+ oldSemesterStartDate,
+ newSemesterStartDate
+ );
+ const newDateOnly = newDate?.split(" ")[0];
+ return {
+ ...lecture,
+ content: updatedText,
+ date: newDateOnly ?? lecture.date,
+ };
+};
const replaceClassroomUrl = (value: string) => {
const classroomPattern =
diff --git a/nextjs/src/models/local/tests/testSemesterImport.test.ts b/nextjs/src/models/local/tests/testSemesterImport.test.ts
index 86bcb20..eacd117 100644
--- a/nextjs/src/models/local/tests/testSemesterImport.test.ts
+++ b/nextjs/src/models/local/tests/testSemesterImport.test.ts
@@ -1,8 +1,14 @@
import { describe, it, expect } from "vitest";
import { LocalAssignment } from "../assignment/localAssignment";
-import { prepAssignmentForNewSemester, prepPageForNewSemester, prepQuizForNewSemester } from "../semesterTransferUtils";
+import {
+ prepAssignmentForNewSemester,
+ prepLectureForNewSemester,
+ prepPageForNewSemester,
+ prepQuizForNewSemester,
+} from "../semesterTransferUtils";
import { LocalQuiz } from "../quiz/localQuiz";
import { LocalCoursePage } from "../page/localCoursePage";
+import { Lecture } from "../lecture";
describe("can take an assignment and template it for a new semester", () => {
it("can sanitize assignment github classroom repo url", () => {
@@ -193,3 +199,24 @@ describe("can prep pages", () => {
expect(sanitizedPage.dueAt).toEqual("01/12/2024 23:59:00");
});
});
+
+describe("can prep lecture", () => {
+ it("lecture gets new date, github url changes", () => {
+ const lecture: Lecture = {
+ name: "test title",
+ date: "08/30/2023",
+ content: "test text content",
+ };
+
+ const oldSemesterStartDate = "08/26/2023 23:59:00";
+ const newSemesterStartDate = "01/08/2024 23:59:00";
+
+ const sanitizedLecture = prepLectureForNewSemester(
+ lecture,
+ oldSemesterStartDate,
+ newSemesterStartDate
+ );
+
+ expect(sanitizedLecture.date).toEqual("01/12/2024");
+ });
+});
diff --git a/nextjs/src/services/fileStorage/lectureFileStorageService.ts b/nextjs/src/services/fileStorage/lectureFileStorageService.ts
index 09e1ca7..dd99273 100644
--- a/nextjs/src/services/fileStorage/lectureFileStorageService.ts
+++ b/nextjs/src/services/fileStorage/lectureFileStorageService.ts
@@ -13,7 +13,6 @@ import {
getDayOfWeek,
LocalCourseSettings,
} from "@/models/local/localCourseSettings";
-import { getWeekNumber } from "@/app/course/[courseName]/calendar/calendarMonthUtils";
import { getDateFromStringOrThrow } from "@/models/local/timeUtils";
export async function getLectures(courseName: string) {
diff --git a/nextjs/src/services/trpc/router/settingsRouter.ts b/nextjs/src/services/trpc/router/settingsRouter.ts
index b09e0df..5f6d9ab 100644
--- a/nextjs/src/services/trpc/router/settingsRouter.ts
+++ b/nextjs/src/services/trpc/router/settingsRouter.ts
@@ -3,6 +3,17 @@ import { z } from "zod";
import { router } from "../trpc";
import { fileStorageService } from "@/services/fileStorage/fileStorageService";
import { zodLocalCourseSettings } from "@/models/local/localCourseSettings";
+import { trpc } from "../utils";
+import {
+ getLectures,
+ updateLecture,
+} from "@/services/fileStorage/lectureFileStorageService";
+import {
+ prepAssignmentForNewSemester,
+ prepLectureForNewSemester,
+ prepPageForNewSemester,
+ prepQuizForNewSemester,
+} from "@/models/local/semesterTransferUtils";
export const settingsRouter = router({
allCoursesSettings: publicProcedure.query(async () => {
@@ -25,6 +36,117 @@ export const settingsRouter = router({
return s;
}),
createCourse: publicProcedure
+ .input(
+ z.object({
+ settings: zodLocalCourseSettings,
+ settingsFromCourseToImport: zodLocalCourseSettings.optional(),
+ })
+ )
+ .mutation(async ({ input: { settings, settingsFromCourseToImport } }) => {
+ await fileStorageService.settings.updateCourseSettings(
+ settings.name,
+ settings
+ );
+
+ if (settingsFromCourseToImport) {
+ const oldCourseName = settingsFromCourseToImport.name;
+ const newCourseName = settings.name;
+ const oldModules = await fileStorageService.modules.getModuleNames(
+ oldCourseName
+ );
+ console.log(
+ "old course name",
+ oldCourseName,
+ "new course name",
+ newCourseName
+ );
+
+ console.log(
+ "old start date",
+ settingsFromCourseToImport.startDate,
+ "new start date",
+ settings.startDate
+ );
+ await Promise.all(
+ oldModules.map(async (moduleName) => {
+ await fileStorageService.modules.createModule(
+ newCourseName,
+ moduleName
+ );
+
+ const [oldAssignments, oldQuizzes, oldPages, oldLecturesByWeek] =
+ await Promise.all([
+ fileStorageService.assignments.getAssignments(
+ oldCourseName,
+ moduleName
+ ),
+ await fileStorageService.quizzes.getQuizzes(
+ oldCourseName,
+ moduleName
+ ),
+ await fileStorageService.pages.getPages(
+ oldCourseName,
+ moduleName
+ ),
+ await getLectures(oldCourseName),
+ ]);
+
+ await Promise.all([
+ ...oldAssignments.map(async (oldAssignment) => {
+ const newAssignment = prepAssignmentForNewSemester(
+ oldAssignment,
+ settingsFromCourseToImport.startDate,
+ settings.startDate,
+ );
+ await fileStorageService.assignments.updateOrCreateAssignment({
+ courseName: newCourseName,
+ moduleName,
+ assignmentName: newAssignment.name,
+ assignment: newAssignment,
+ });
+ }),
+ ...oldQuizzes.map(async (oldQuiz) => {
+ const newQuiz = prepQuizForNewSemester(
+ oldQuiz,
+ settingsFromCourseToImport.startDate,
+ settings.startDate,
+ );
+ await fileStorageService.quizzes.updateQuiz({
+ courseName: newCourseName,
+ moduleName,
+ quizName: newQuiz.name,
+ quiz: newQuiz,
+ });
+ }),
+ ...oldPages.map(async (oldPage) => {
+ const newPage = prepPageForNewSemester(
+ oldPage,
+ settingsFromCourseToImport.startDate,
+ settings.startDate,
+ );
+ await fileStorageService.pages.updatePage({
+ courseName: newCourseName,
+ moduleName,
+ pageName: newPage.name,
+ page: newPage,
+ });
+ }),
+ ...oldLecturesByWeek.flatMap(async (oldLectureByWeek) =>
+ oldLectureByWeek.lectures.map(async (oldLecture) => {
+ const newLecture = prepLectureForNewSemester(
+ oldLecture,
+ settingsFromCourseToImport.startDate,
+ settings.startDate,
+ );
+ await updateLecture(newCourseName, settings, newLecture);
+ })
+ ),
+ ]);
+ })
+ );
+ }
+ }),
+ updateSettings: publicProcedure
.input(
z.object({
settings: zodLocalCourseSettings,
@@ -36,17 +158,4 @@ export const settingsRouter = router({
settings
);
}),
- updateSettings: publicProcedure
- .input(
- z.object({
- settings: zodLocalCourseSettings,
- })
- )
- .mutation(async ({ input: { settings } }) => {
- await fileStorageService.settings.updateCourseSettings(
- settings.name,
- settings
- );
- }),
-
});
diff --git a/requests/assignment.http b/requests/assignment.http
index 0d27ba0..ee14c9e 100644
--- a/requests/assignment.http
+++ b/requests/assignment.http
@@ -5,7 +5,7 @@ Authorization: Bearer {{$dotenv CANVAS_TOKEN}}
###
-GET https://snow.instructure.com/api/v1/courses/871954/assignments
+GET https://snow.instructure.com/api/v1/courses/1013058/assignments
Authorization: Bearer {{$dotenv CANVAS_TOKEN}}
diff --git a/requests/quiz.http b/requests/quiz.http
index 45a175f..03bfdb3 100644
--- a/requests/quiz.http
+++ b/requests/quiz.http
@@ -1,5 +1,5 @@
-GET https://snow.instructure.com/api/v1/courses/958185/quizzes
+GET https://snow.instructure.com/api/v1/courses/1013058/quizzes
Authorization: Bearer {{$dotenv CANVAS_TOKEN}}
###