linting more trpc

This commit is contained in:
2024-11-11 13:20:08 -07:00
parent cc8d004aa4
commit 61359a5e7d
36 changed files with 1076 additions and 662 deletions

View File

@@ -16,8 +16,8 @@ import {
import { Dispatch, SetStateAction, useCallback, DragEvent } from "react";
import { DraggableItem } from "./draggingContext";
import { getNewLockDate } from "./getNewLockDate";
import { useUpdateItemMutation } from "@/hooks/localCourse/courseItemHooks";
import { trpc } from "@/services/trpc/utils";
import { useUpdateQuizMutation } from "@/hooks/localCourse/quizHooks";
export function useItemDropOnDay({
setIsDragging,
@@ -37,7 +37,7 @@ export function useItemDropOnDay({
const [weeks] = trpc.lectures.getLectures.useSuspenseQuery({
courseName: settings.name,
});
const updateQuizMutation = useUpdateItemMutation("Quiz");
const updateQuizMutation = useUpdateQuizMutation();
const updateLectureMutation = useLectureUpdateMutation();
const updateAssignmentMutation = useUpdateAssignmentMutation();
const updatePageMutation = useUpdatePageMutation();
@@ -132,11 +132,12 @@ export function useItemDropOnDay({
),
};
updateQuizMutation.mutate({
item: quiz,
itemName: quiz.name,
quiz,
quizName: quiz.name,
moduleName: itemBeingDragged.sourceModuleName,
previousModuleName: itemBeingDragged.sourceModuleName,
previousItemName: quiz.name,
previousQuizName: quiz.name,
courseName: settings.name,
});
}
function updatePage(dayAsDate: Date) {
@@ -152,11 +153,12 @@ export function useItemDropOnDay({
dueAt: dateToMarkdownString(dayAsDate),
};
updatePageMutation.mutate({
item: page,
page,
moduleName: itemBeingDragged.sourceModuleName,
itemName: page.name,
previousItemName: page.name,
pageName: page.name,
previousPageName: page.name,
previousModuleName: itemBeingDragged.sourceModuleName,
courseName: settings.name,
});
}
function updateAssignment(dayAsDate: Date) {
@@ -177,11 +179,12 @@ export function useItemDropOnDay({
),
};
updateAssignmentMutation.mutate({
item: assignment,
assignment,
previousModuleName: itemBeingDragged.sourceModuleName,
moduleName: itemBeingDragged.sourceModuleName,
itemName: assignment.name,
previousItemName: assignment.name,
assignmentName: assignment.name,
previousAssignmentName: assignment.name,
courseName: settings.name,
});
}
},

View File

@@ -6,16 +6,18 @@ import { LocalCoursePage } from "@/models/local/page/localCoursePage";
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
import { Dispatch, SetStateAction, useCallback, DragEvent } from "react";
import { DraggableItem } from "./draggingContext";
import { useUpdateItemMutation } from "@/hooks/localCourse/courseItemHooks";
import { useCourseContext } from "../courseContext";
import { useUpdateQuizMutation } from "@/hooks/localCourse/quizHooks";
export function useItemDropOnModule({
setIsDragging,
}: {
setIsDragging: Dispatch<SetStateAction<boolean>>;
}) {
const updateQuizMutation = useUpdateItemMutation("Quiz");
const updateQuizMutation = useUpdateQuizMutation();
const updateAssignmentMutation = useUpdateAssignmentMutation();
const updatePageMutation = useUpdatePageMutation();
const { courseName } = useCourseContext();
return useCallback(
(e: DragEvent, dropModuleName: string) => {
@@ -41,11 +43,12 @@ export function useItemDropOnModule({
const quiz = itemBeingDragged.item as LocalQuiz;
if (itemBeingDragged.sourceModuleName) {
updateQuizMutation.mutate({
item: quiz,
itemName: quiz.name,
quiz,
quizName: quiz.name,
moduleName: dropModuleName,
previousModuleName: itemBeingDragged.sourceModuleName,
previousItemName: quiz.name,
previousQuizName: quiz.name,
courseName,
});
} else {
console.error(
@@ -58,11 +61,12 @@ export function useItemDropOnModule({
const assignment = itemBeingDragged.item as LocalAssignment;
if (itemBeingDragged.sourceModuleName) {
updateAssignmentMutation.mutate({
item: assignment,
assignment,
previousModuleName: itemBeingDragged.sourceModuleName,
moduleName: dropModuleName,
itemName: assignment.name,
previousItemName: assignment.name,
assignmentName: assignment.name,
previousAssignmentName: assignment.name,
courseName,
});
} else {
console.error(
@@ -75,11 +79,12 @@ export function useItemDropOnModule({
const page = itemBeingDragged.item as LocalCoursePage;
if (itemBeingDragged.sourceModuleName) {
updatePageMutation.mutate({
item: page,
page,
moduleName: dropModuleName,
itemName: page.name,
previousItemName: page.name,
pageName: page.name,
previousPageName: page.name,
previousModuleName: itemBeingDragged.sourceModuleName,
courseName,
});
} else {
console.error(
@@ -90,6 +95,7 @@ export function useItemDropOnModule({
}
},
[
courseName,
setIsDragging,
updateAssignmentMutation,
updatePageMutation,

View File

@@ -21,8 +21,8 @@ import { getModuleItemUrl } from "@/services/urlUtils";
import { useCourseContext } from "../context/courseContext";
import { Expandable } from "../../../../components/Expandable";
import { useDragStyleContext } from "../context/drag/dragStyleContext";
import { useItemsQueries } from "@/hooks/localCourse/courseItemHooks";
import { useAssignmentsQuery } from "@/hooks/localCourse/assignmentHooks";
import { useQuizzesQueries } from "@/hooks/localCourse/quizHooks";
export default function ExpandableModule({
moduleName,
@@ -31,9 +31,9 @@ export default function ExpandableModule({
}) {
const { itemDropOnModule } = useDraggingContext();
const { data: assignments } = useAssignmentsQuery(moduleName);
// const { data: quizzes } = useItemsQueries(moduleName, "Quiz");
const { data: pages } = usePagesQueries(moduleName);
const [assignments ] = useAssignmentsQuery(moduleName);
const [quizzes] = useQuizzesQueries(moduleName);
const [pages] = usePagesQueries(moduleName);
const modal = useModal();
const moduleItems: {
@@ -51,7 +51,7 @@ export default function ExpandableModule({
item: a,
})
)
// .concat(quizzes.map((q) => ({ type: "quiz", item: q })))
.concat(quizzes.map((q) => ({ type: "quiz", item: q })))
.concat(pages.map((p) => ({ type: "page", item: p })))
.sort(
(a, b) =>

View File

@@ -4,7 +4,6 @@ import SelectInput from "@/components/form/SelectInput";
import TextInput from "@/components/form/TextInput";
import { Spinner } from "@/components/Spinner";
import { useCreateAssignmentMutation } from "@/hooks/localCourse/assignmentHooks";
import { useCreateItemMutation } from "@/hooks/localCourse/courseItemHooks";
import { useModuleNamesQuery } from "@/hooks/localCourse/localCourseModuleHooks";
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
import { useCreatePageMutation } from "@/hooks/localCourse/pageHooks";
@@ -14,9 +13,9 @@ import {
getDateFromString,
getDateFromStringOrThrow,
} from "@/models/local/timeUtils";
import { trpc } from "@/services/trpc/utils";
import React, { useState } from "react";
import { useCourseContext } from "../context/courseContext";
import { useCreateQuizMutation } from "@/hooks/localCourse/quizHooks";
export default function NewItemForm({
moduleName: defaultModuleName,
@@ -33,10 +32,6 @@ export default function NewItemForm({
const [type, setType] = useState<"Assignment" | "Quiz" | "Page">(
"Assignment"
);
const assignmentCreationMutation = useCreateAssignmentMutation({
courseName,
moduleName: defaultModuleName ?? "",
});
const [moduleName, setModuleName] = useState<string | undefined>(
defaultModuleName
@@ -58,12 +53,11 @@ export default function NewItemForm({
useState<LocalAssignmentGroup>();
const createPage = useCreatePageMutation();
const createQuiz = useCreateItemMutation("Quiz");
const createQuiz = useCreateQuizMutation();
const createAssignment = useCreateAssignmentMutation();
const isPending =
assignmentCreationMutation.isPending ||
createPage.isPending ||
createQuiz.isPending;
createAssignment.isPending || createPage.isPending || createQuiz.isPending;
return (
<form
@@ -87,26 +81,11 @@ export default function NewItemForm({
)
);
console.log("submitting");
if (!moduleName) {
return;
}
if (type === "Assignment") {
// createAssignment.mutate({
// item: {
// name,
// description: "",
// localAssignmentGroupName: assignmentGroup?.name ?? "",
// dueAt,
// lockAt,
// submissionTypes: settings.defaultAssignmentSubmissionTypes,
// allowedFileUploadExtensions: settings.defaultFileUploadTypes,
// rubric: [],
// },
// moduleName: moduleName,
// itemName: name,
// });
assignmentCreationMutation.mutate({
createAssignment.mutate({
assignment: {
name,
description: "",
@@ -123,7 +102,7 @@ export default function NewItemForm({
});
} else if (type === "Quiz") {
createQuiz.mutate({
item: {
quiz: {
name,
description: "",
localAssignmentGroupName: assignmentGroup?.name ?? "",
@@ -136,17 +115,19 @@ export default function NewItemForm({
questions: [],
},
moduleName: moduleName,
itemName: name,
quizName: name,
courseName,
});
} else if (type === "Page") {
createPage.mutate({
item: {
page: {
name,
text: "",
dueAt,
},
moduleName: moduleName,
itemName: name,
pageName: name,
courseName,
});
}
onCreate();

View File

@@ -35,11 +35,7 @@ export function AssignmentButtons({
isPending: canvasIsPending,
isRefetching: canvasIsRefetching,
} = useCanvasAssignmentsQuery();
const {
data: assignment,
isPending: assignmentIsPending,
isRefetching,
} = useAssignmentQuery(moduleName, assignmentName);
const [assignment] = useAssignmentQuery(moduleName, assignmentName);
const addToCanvas = useAddAssignmentToCanvasMutation();
const deleteFromCanvas = useDeleteAssignmentFromCanvasMutation();
const updateAssignment = useUpdateAssignmentInCanvasMutation();
@@ -54,8 +50,6 @@ export function AssignmentButtons({
const anythingIsLoading =
addToCanvas.isPending ||
canvasIsPending ||
assignmentIsPending ||
isRefetching ||
canvasIsRefetching ||
deleteFromCanvas.isPending ||
updateAssignment.isPending;
@@ -135,7 +129,8 @@ export function AssignmentButtons({
router.push(getCourseUrl(courseName));
await deleteLocal.mutateAsync({
moduleName,
itemName: assignmentName,
assignmentName,
courseName,
});
router.refresh();
// setIsLoading(false); //refreshing the router will make spinner go away

View File

@@ -4,7 +4,10 @@ import {
useAssignmentQuery,
useUpdateAssignmentMutation,
} from "@/hooks/localCourse/assignmentHooks";
import { localAssignmentMarkdown } from "@/models/local/assignment/localAssignment";
import {
LocalAssignment,
localAssignmentMarkdown,
} from "@/models/local/assignment/localAssignment";
import { useEffect, useState } from "react";
import AssignmentPreview from "./AssignmentPreview";
import { getModuleItemUrl } from "@/services/urlUtils";
@@ -41,7 +44,7 @@ export default function EditAssignment({
const delay = 500;
const handler = setTimeout(() => {
try {
const updatedAssignment =
const updatedAssignment: LocalAssignment =
localAssignmentMarkdown.parseMarkdown(assignmentText);
if (
localAssignmentMarkdown.toMarkdown(assignment) !==
@@ -50,11 +53,12 @@ export default function EditAssignment({
console.log("updating assignment");
updateAssignment
.mutateAsync({
item: updatedAssignment,
assignment: updatedAssignment,
moduleName,
itemName: updatedAssignment.name,
assignmentName: updatedAssignment.name,
previousModuleName: moduleName,
previousItemName: assignmentName,
previousAssignmentName: assignmentName,
courseName,
})
.then(() => {
if (updatedAssignment.name !== assignmentName)

View File

@@ -24,7 +24,7 @@ export default function EditPage({
}) {
const router = useRouter();
const { courseName } = useCourseContext();
const { data: page } = usePageQuery(moduleName, pageName);
const [page] = usePageQuery(moduleName, pageName);
const updatePage = useUpdatePageMutation();
const [pageText, setPageText] = useState(
localPageMarkdownUtils.toMarkdown(page)
@@ -44,11 +44,12 @@ export default function EditPage({
console.log("updating page");
updatePage
.mutateAsync({
item: updatedPage,
page: updatedPage,
moduleName,
itemName: updatedPage.name,
pageName: updatedPage.name,
previousModuleName: moduleName,
previousItemName: pageName,
previousPageName: pageName,
courseName,
})
.then(() => {
if (updatedPage.name !== pageName)

View File

@@ -28,7 +28,7 @@ export default function EditPageButtons({
const router = useRouter();
const { courseName } = useCourseContext();
const [settings] = useLocalCourseSettingsQuery();
const { data: page } = usePageQuery(moduleName, pageName);
const [page] = usePageQuery(moduleName, pageName);
const { data: canvasPages } = useCanvasPagesQuery();
const createPageInCanvas = useCreateCanvasPageMutation();
const updatePageInCanvas = useUpdateCanvasPageMutation();
@@ -105,7 +105,8 @@ export default function EditPageButtons({
router.push(getCourseUrl(courseName));
deletePageLocal.mutate({
moduleName,
itemName: pageName,
pageName,
courseName,
});
}}
className="btn-danger"

View File

@@ -9,7 +9,10 @@ import { SuspenseAndErrorHandling } from "@/components/SuspenseAndErrorHandling"
import { useRouter } from "next/navigation";
import { getModuleItemUrl } from "@/services/urlUtils";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { useItemQuery, useUpdateItemMutation } from "@/hooks/localCourse/courseItemHooks";
import {
useQuizQuery,
useUpdateQuizMutation,
} from "@/hooks/localCourse/quizHooks";
const helpString = `QUESTION REFERENCE
---
@@ -61,8 +64,8 @@ export default function EditQuiz({
}) {
const router = useRouter();
const { courseName } = useCourseContext();
const { data: quiz } = useItemQuery(moduleName, quizName, "Quiz");
const updateQuizMutation = useUpdateItemMutation("Quiz");
const [quiz] = useQuizQuery(moduleName, quizName);
const updateQuizMutation = useUpdateQuizMutation();
const [quizText, setQuizText] = useState(quizMarkdownUtils.toMarkdown(quiz));
const [error, setError] = useState("");
const [showHelp, setShowHelp] = useState(false);
@@ -81,11 +84,12 @@ export default function EditQuiz({
const updatedQuiz = quizMarkdownUtils.parseMarkdown(quizText);
updateQuizMutation
.mutateAsync({
item: updatedQuiz,
quiz: updatedQuiz,
moduleName,
itemName: updatedQuiz.name,
quizName: updatedQuiz.name,
previousModuleName: moduleName,
previousItemName: quizName,
previousQuizName: quizName,
courseName,
})
.then(() => {
if (updatedQuiz.name !== quizName)

View File

@@ -6,11 +6,11 @@ import {
useAddQuizToCanvasMutation,
useDeleteQuizFromCanvasMutation,
} from "@/hooks/canvas/canvasQuizHooks";
import {
useDeleteItemMutation,
useItemQuery,
} from "@/hooks/localCourse/courseItemHooks";
import { useLocalCourseSettingsQuery } from "@/hooks/localCourse/localCoursesHooks";
import {
useDeleteQuizMutation,
useQuizQuery,
} from "@/hooks/localCourse/quizHooks";
import { baseCanvasUrl } from "@/services/canvas/canvasServiceUtils";
import { getCourseUrl } from "@/services/urlUtils";
import Link from "next/link";
@@ -29,10 +29,11 @@ export function QuizButtons({
const { courseName } = useCourseContext();
const [settings] = useLocalCourseSettingsQuery();
const { data: canvasQuizzes } = useCanvasQuizzesQuery();
const { data: quiz } = useItemQuery(moduleName, quizName, "Quiz");
const [quiz] = useQuizQuery(moduleName, quizName);
const addToCanvas = useAddQuizToCanvasMutation();
const deleteFromCanvas = useDeleteQuizFromCanvasMutation();
const deleteLocal = useDeleteItemMutation("Quiz");
const deleteLocal = useDeleteQuizMutation();
const modal = useModal();
const quizInCanvas = canvasQuizzes.find((c) => c.title === quizName);
@@ -90,7 +91,7 @@ export function QuizButtons({
<button
onClick={async () => {
router.push(getCourseUrl(courseName));
deleteLocal.mutate({ moduleName, itemName: quizName });
deleteLocal.mutate({ moduleName, quizName, courseName });
}}
className="btn-danger"
>

View File

@@ -1,5 +1,5 @@
import CheckIcon from "@/components/icons/CheckIcon";
import { useItemQuery } from "@/hooks/localCourse/courseItemHooks";
import { useQuizQuery } from "@/hooks/localCourse/quizHooks";
import {
LocalQuizQuestion,
QuestionType,
@@ -13,7 +13,7 @@ export default function QuizPreview({
quizName: string;
moduleName: string;
}) {
const { data: quiz } = useItemQuery(moduleName, quizName, "Quiz");
const [quiz] = useQuizQuery(moduleName, quizName);
return (
<div style={{ overflow: "scroll", height: "100%" }}>
<div className="columns-2">

View File

@@ -25,8 +25,10 @@ export default function AssignmentGroupManagement() {
!areAssignmentGroupsEqual(assignmentGroups, settings.assignmentGroups)
) {
updateSettings.mutate({
settings: {
...settings,
assignmentGroups,
},
});
}
}, delay);

View File

@@ -17,11 +17,14 @@ export default function DaysOfWeekSettings() {
selectedDays={settings.daysOfWeek}
updateSettings={(day) => {
const hasDay = settings.daysOfWeek.includes(day);
updateSettings.mutate({
settings: {
...settings,
daysOfWeek: hasDay
? settings.daysOfWeek.filter((d) => d !== day)
: [day, ...settings.daysOfWeek],
},
});
}}
/>

View File

@@ -23,8 +23,10 @@ export default function DefaultDueTime() {
setChosenTime={(simpleTime) => {
console.log(simpleTime);
updateSettings.mutate({
settings: {
...settings,
defaultDueTime: simpleTime,
},
});
}}
/>
@@ -33,8 +35,10 @@ export default function DefaultDueTime() {
<button
onClick={async () => {
await updateSettings.mutateAsync({
settings: {
...settings,
defaultLockHoursOffset: 0,
},
});
setHaveLockOffset(true);
}}
@@ -50,8 +54,10 @@ export default function DefaultDueTime() {
className="btn-danger"
onClick={async () => {
await updateSettings.mutateAsync({
settings: {
...settings,
defaultLockHoursOffset: undefined,
},
});
setHaveLockOffset(false);
}}

View File

@@ -20,8 +20,10 @@ export default function DefaultFileUploadTypes() {
JSON.stringify(defaultFileUploadTypes)
) {
updateSettings.mutate({
settings: {
...settings,
defaultFileUploadTypes: defaultFileUploadTypes,
},
});
}
}, 500);

View File

@@ -23,8 +23,10 @@ export default function DefaultLockOffset() {
hoursNumber !== settings.defaultLockHoursOffset
) {
updateSettings.mutate({
settings: {
...settings,
defaultLockHoursOffset: hoursNumber,
},
});
}
} catch {}

View File

@@ -75,9 +75,12 @@ function InnerHolidayConfig() {
if (!holidaysAreEqual(settings.holidays, parsed)) {
console.log("different holiday configs", settings.holidays, parsed);
updateSettings.mutate({
settings: {
...settings,
holidays: parsed,
},
});
}
} catch (error: any) {}

View File

@@ -23,8 +23,10 @@ export default function SubmissionDefaults() {
JSON.stringify(defaultSubmissionTypes)
) {
updateSettings.mutate({
settings: {
...settings,
defaultAssignmentSubmissionTypes: defaultSubmissionTypes,
},
});
}
}, [defaultSubmissionTypes, settings, updateSettings]);

View File

@@ -2,18 +2,14 @@ import type { Metadata } from "next";
import "./globals.css";
import Providers from "./providers";
import { Suspense } from "react";
import { getQueryClient } from "./providersQueryClientUtils";
import { hydrateCourses } from "@/hooks/hookHydration";
import { dehydrate, hydrate, HydrationBoundary } from "@tanstack/react-query";
import { dehydrate, HydrationBoundary } from "@tanstack/react-query";
import { MyToaster } from "./MyToaster";
import { cookies } from "next/headers";
import { createServerSideHelpers } from "@trpc/react-query/server";
import { trpcAppRouter } from "@/services/trpc/router/app";
import { createTrpcContext } from "@/services/trpc/context";
import superjson from "superjson";
import { fileStorageService } from "@/services/fileStorage/fileStorageService";
import ClientOnly from "@/components/ClientOnly";
import { createTRPCQueryUtils } from "@trpc/react-query";
export const dynamic = "force-dynamic";
export const metadata: Metadata = {
@@ -60,35 +56,35 @@ async function DataHydration({
},
},
});
const allSettings = await fileStorageService.settings.getAllCoursesSettings();
await Promise.all(
allSettings.map(async (settings) => {
const courseName = settings.name;
const moduleNames = await fileStorageService.modules.getModuleNames(
courseName
);
await Promise.all(
moduleNames.map(
async (moduleName) =>
await trpcHelper.assignment.getAllAssignments.fetch({
courseName,
moduleName,
})
)
);
})
);
// const allSettings = await fileStorageService.settings.getAllCoursesSettings();
// await Promise.all(
// allSettings.map(async (settings) => {
// const courseName = settings.name;
// const moduleNames = await fileStorageService.modules.getModuleNames(
// courseName
// );
// await Promise.all(
// moduleNames.map(
// async (moduleName) =>
// await trpcHelper.assignment.getAllAssignments.fetch({
// courseName,
// moduleName,
// })
// )
// );
// })
// );
await Promise.all(
allSettings.map(
async (settings) =>
await trpcHelper.lectures.getLectures.fetch({
courseName: settings.name,
})
)
);
// await Promise.all(
// allSettings.map(
// async (settings) =>
// await trpcHelper.lectures.getLectures.fetch({
// courseName: settings.name,
// })
// )
// );
await hydrateCourses(trpcHelper.queryClient);
// await hydrateCourses(trpcHelper.queryClient);
const dehydratedState = dehydrate(trpcHelper.queryClient);
console.log("ran hydration");

View File

@@ -1,13 +1,5 @@
"use client";
import { trpc } from "@/services/trpc/utils";
import {
getAllItemsQueryConfig,
getItemQueryConfig,
useDeleteItemMutation,
useItemQuery,
useItemsQueries,
useUpdateItemMutation,
} from "./courseItemHooks";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
// export const getAllAssignmentsQueryConfig = (
@@ -36,31 +28,31 @@ export const useAssignmentQuery = (
export const useAssignmentsQuery = (moduleName: string) => {
const { courseName } = useCourseContext();
console.log("rendering all assignments query");
return trpc.assignment.getAllAssignments.useQuery({
return trpc.assignment.getAllAssignments.useSuspenseQuery({
moduleName,
courseName,
});
};
// useItemsQueries(moduleName, "Assignment");
export const useUpdateAssignmentMutation = () =>
useUpdateItemMutation("Assignment");
export const useUpdateAssignmentMutation = () => {
return trpc.assignment.updateAssignment.useMutation();
};
export const useCreateAssignmentMutation = ({
courseName,
moduleName,
}: {
courseName: string;
moduleName: string;
}) => {
export const useCreateAssignmentMutation = () => {
const utils = trpc.useUtils();
return trpc.assignment.createAssignment.useMutation({
onSuccess: () => {
onSuccess: (_, { courseName, moduleName }) => {
utils.assignment.getAllAssignments.invalidate({ courseName, moduleName });
},
});
};
// useCreateItemMutation("Assignment");
export const useDeleteAssignmentMutation = () =>
useDeleteItemMutation("Assignment");
export const useDeleteAssignmentMutation = () => {
const utils = trpc.useUtils();
return trpc.assignment.deleteAssignment.useMutation({
onSuccess: (_, { courseName, moduleName }) => {
utils.assignment.getAllAssignments.invalidate({ courseName, moduleName });
},
});
};

View File

@@ -1,233 +1,233 @@
import { localCourseKeys } from "./localCourseKeys";
import {
CourseItemReturnType,
CourseItemType,
} from "@/models/local/courseItemTypes";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import {
useMutation,
useQueryClient,
useSuspenseQueries,
useSuspenseQuery,
} from "@tanstack/react-query";
import {
createItemOnServer,
deleteItemOnServer,
getAllItemsFromServer,
getItemFromServer,
updateItemOnServer,
} from "./courseItemServerActions";
// import { localCourseKeys } from "./localCourseKeys";
// import {
// CourseItemReturnType,
// CourseItemType,
// } from "@/models/local/courseItemTypes";
// import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
// import {
// useMutation,
// useQueryClient,
// useSuspenseQueries,
// useSuspenseQuery,
// } from "@tanstack/react-query";
// // import {
// // createItemOnServer,
// // deleteItemOnServer,
// // getAllItemsFromServer,
// // getItemFromServer,
// // updateItemOnServer,
// // } from "./courseItemServerActions";
export const getAllItemsQueryConfig = <T extends CourseItemType>(
courseName: string,
moduleName: string,
type: T
) => ({
queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
queryFn: async (): Promise<CourseItemReturnType<T>[]> => {
return await getAllItemsFromServer({
courseName,
moduleName,
type,
});
},
});
// export const getAllItemsQueryConfig = <T extends CourseItemType>(
// courseName: string,
// moduleName: string,
// type: T
// ) => ({
// queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
// queryFn: async (): Promise<CourseItemReturnType<T>[]> => {
// return await getAllItemsFromServer({
// courseName,
// moduleName,
// type,
// });
// },
// });
export const getItemQueryConfig = <T extends CourseItemType>(
courseName: string,
moduleName: string,
name: string,
type: T
) => {
return {
queryKey: localCourseKeys.itemOfType(courseName, moduleName, name, type),
queryFn: async () => {
return await getItemFromServer({
moduleName,
courseName,
itemName: name,
type,
});
},
};
};
// export const getItemQueryConfig = <T extends CourseItemType>(
// courseName: string,
// moduleName: string,
// name: string,
// type: T
// ) => {
// return {
// queryKey: localCourseKeys.itemOfType(courseName, moduleName, name, type),
// queryFn: async () => {
// return await getItemFromServer({
// moduleName,
// courseName,
// itemName: name,
// type,
// });
// },
// };
// };
export const useItemQuery = <T extends CourseItemType>(
moduleName: string,
name: string,
type: T
) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(
getItemQueryConfig(courseName, moduleName, name, type)
);
};
// export const useItemQuery = <T extends CourseItemType>(
// moduleName: string,
// name: string,
// type: T
// ) => {
// const { courseName } = useCourseContext();
// return useSuspenseQuery(
// getItemQueryConfig(courseName, moduleName, name, type)
// );
// };
const useAllItemsQuery = <T extends CourseItemType>(
moduleName: string,
type: T
) => {
const { courseName } = useCourseContext();
return useSuspenseQuery(getAllItemsQueryConfig(courseName, moduleName, type));
};
// const useAllItemsQuery = <T extends CourseItemType>(
// moduleName: string,
// type: T
// ) => {
// const { courseName } = useCourseContext();
// return useSuspenseQuery(getAllItemsQueryConfig(courseName, moduleName, type));
// };
export const useItemsQueries = <T extends CourseItemType>(
moduleName: string,
type: T
) => {
const { data: allItems } = useAllItemsQuery(moduleName, type);
const { courseName } = useCourseContext();
return useSuspenseQueries({
queries: allItems.map((item) => ({
...getItemQueryConfig(courseName, moduleName, item.name, type),
})),
combine: (results) => ({
data: results.map((r) => r.data),
pending: results.some((r) => r.isPending),
}),
});
};
// export const useItemsQueries = <T extends CourseItemType>(
// moduleName: string,
// type: T
// ) => {
// const { data: allItems } = useAllItemsQuery(moduleName, type);
// const { courseName } = useCourseContext();
// return useSuspenseQueries({
// queries: allItems.map((item) => ({
// ...getItemQueryConfig(courseName, moduleName, item.name, type),
// })),
// combine: (results) => ({
// data: results.map((r) => r.data),
// pending: results.some((r) => r.isPending),
// }),
// });
// };
export const useUpdateItemMutation = <T extends CourseItemType>(type: T) => {
const { courseName } = useCourseContext();
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
item,
moduleName,
previousModuleName,
previousItemName,
itemName,
}: {
item: CourseItemReturnType<T>;
moduleName: string;
previousModuleName: string;
previousItemName: string;
itemName: string;
}) => {
if (previousItemName !== item.name || previousModuleName !== moduleName) {
queryClient.removeQueries({
queryKey: localCourseKeys.itemOfType(
courseName,
previousModuleName,
previousItemName,
type
),
});
queryClient.removeQueries({
queryKey: localCourseKeys.allItemsOfType(
courseName,
previousModuleName,
type
),
});
}
// export const useUpdateItemMutation = <T extends CourseItemType>(type: T) => {
// const { courseName } = useCourseContext();
// const queryClient = useQueryClient();
// return useMutation({
// mutationFn: async ({
// item,
// moduleName,
// previousModuleName,
// previousItemName,
// itemName,
// }: {
// item: CourseItemReturnType<T>;
// moduleName: string;
// previousModuleName: string;
// previousItemName: string;
// itemName: string;
// }) => {
// if (previousItemName !== item.name || previousModuleName !== moduleName) {
// queryClient.removeQueries({
// queryKey: localCourseKeys.itemOfType(
// courseName,
// previousModuleName,
// previousItemName,
// type
// ),
// });
// queryClient.removeQueries({
// queryKey: localCourseKeys.allItemsOfType(
// courseName,
// previousModuleName,
// type
// ),
// });
// }
queryClient.setQueryData(
localCourseKeys.itemOfType(courseName, moduleName, itemName, type),
item
);
await updateItemOnServer({
courseName,
moduleName,
item,
type,
previousItemName,
previousModuleName,
itemName,
});
},
onSuccess: async (_, { moduleName, itemName }) => {
await queryClient.invalidateQueries({
queryKey: localCourseKeys.itemOfType(
courseName,
moduleName,
itemName,
type
),
refetchType: "all",
});
await queryClient.invalidateQueries({
queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
refetchType: "all",
});
},
});
};
export const useCreateItemMutation = <T extends CourseItemType>(type: T) => {
const { courseName } = useCourseContext();
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
item,
moduleName,
itemName,
}: {
item: CourseItemReturnType<T>;
moduleName: string;
itemName: string;
}) => {
queryClient.setQueryData(
localCourseKeys.itemOfType(courseName, moduleName, itemName, type),
item
);
await createItemOnServer({
courseName,
moduleName,
item,
type,
itemName,
});
},
onSuccess: async (_, { moduleName, itemName }) => {
await queryClient.invalidateQueries({
queryKey: localCourseKeys.itemOfType(
courseName,
moduleName,
itemName,
type
),
});
await queryClient.invalidateQueries({
queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
});
},
});
};
export const useDeleteItemMutation = <T extends CourseItemType>(type: T) => {
const { courseName } = useCourseContext();
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
moduleName,
itemName,
}: {
moduleName: string;
itemName: string;
}) => {
await deleteItemOnServer({
courseName,
itemName,
moduleName,
type,
});
},
onSuccess: async (_, { moduleName, itemName }) => {
await queryClient.invalidateQueries({
queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
// queryClient.setQueryData(
// localCourseKeys.itemOfType(courseName, moduleName, itemName, type),
// item
// );
// await updateItemOnServer({
// courseName,
// moduleName,
// item,
// type,
// previousItemName,
// previousModuleName,
// itemName,
// });
// },
// onSuccess: async (_, { moduleName, itemName }) => {
// await queryClient.invalidateQueries({
// queryKey: localCourseKeys.itemOfType(
// courseName,
// moduleName,
// itemName,
// type
// ),
// refetchType: "all",
});
await queryClient.invalidateQueries({
queryKey: localCourseKeys.itemOfType(
courseName,
moduleName,
itemName,
type
),
refetchType: "none",
});
},
});
};
// });
// await queryClient.invalidateQueries({
// queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
// refetchType: "all",
// });
// },
// });
// };
// export const useCreateItemMutation = <T extends CourseItemType>(type: T) => {
// const { courseName } = useCourseContext();
// const queryClient = useQueryClient();
// return useMutation({
// mutationFn: async ({
// item,
// moduleName,
// itemName,
// }: {
// item: CourseItemReturnType<T>;
// moduleName: string;
// itemName: string;
// }) => {
// queryClient.setQueryData(
// localCourseKeys.itemOfType(courseName, moduleName, itemName, type),
// item
// );
// await createItemOnServer({
// courseName,
// moduleName,
// item,
// type,
// itemName,
// });
// },
// onSuccess: async (_, { moduleName, itemName }) => {
// await queryClient.invalidateQueries({
// queryKey: localCourseKeys.itemOfType(
// courseName,
// moduleName,
// itemName,
// type
// ),
// });
// await queryClient.invalidateQueries({
// queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
// });
// },
// });
// };
// export const useDeleteItemMutation = <T extends CourseItemType>(type: T) => {
// const { courseName } = useCourseContext();
// const queryClient = useQueryClient();
// return useMutation({
// mutationFn: async ({
// moduleName,
// itemName,
// }: {
// moduleName: string;
// itemName: string;
// }) => {
// await deleteItemOnServer({
// courseName,
// itemName,
// moduleName,
// type,
// });
// },
// onSuccess: async (_, { moduleName, itemName }) => {
// await queryClient.invalidateQueries({
// queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
// // refetchType: "all",
// });
// await queryClient.invalidateQueries({
// queryKey: localCourseKeys.itemOfType(
// courseName,
// moduleName,
// itemName,
// type
// ),
// refetchType: "none",
// });
// },
// });
// };

View File

@@ -1,237 +1,237 @@
"use server";
// "use server";
import { ItemInDay } from "@/app/course/[courseName]/calendar/day/ItemInDay";
import { LocalAssignment } from "@/models/local/assignment/localAssignment";
import {
CourseItemReturnType,
CourseItemType,
} from "@/models/local/courseItemTypes";
import { LocalCoursePage } from "@/models/local/page/localCoursePage";
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
import { fileStorageService } from "@/services/fileStorage/fileStorageService";
// import { ItemInDay } from "@/app/course/[courseName]/calendar/day/ItemInDay";
// import { LocalAssignment } from "@/models/local/assignment/localAssignment";
// import {
// CourseItemReturnType,
// CourseItemType,
// } from "@/models/local/courseItemTypes";
// import { LocalCoursePage } from "@/models/local/page/localCoursePage";
// import { LocalQuiz } from "@/models/local/quiz/localQuiz";
// import { fileStorageService } from "@/services/fileStorage/fileStorageService";
export async function getAllItemsFromServer<T extends CourseItemType>({
courseName,
moduleName,
type,
}: {
courseName: string;
moduleName: string;
type: T;
}): Promise<CourseItemReturnType<T>[]> {
if (type === "Assignment") {
const assignments = await fileStorageService.assignments.getAssignments(
courseName,
moduleName
);
return assignments as CourseItemReturnType<T>[];
}
if (type === "Quiz") {
const quizzes = await fileStorageService.quizzes.getQuizzes(
courseName,
moduleName
);
return quizzes as CourseItemReturnType<T>[];
}
if (type === "Page") {
const pages = await fileStorageService.pages.getPages(
courseName,
moduleName
);
return pages as CourseItemReturnType<T>[];
}
// export async function getAllItemsFromServer<T extends CourseItemType>({
// courseName,
// moduleName,
// type,
// }: {
// courseName: string;
// moduleName: string;
// type: T;
// }): Promise<CourseItemReturnType<T>[]> {
// if (type === "Assignment") {
// const assignments = await fileStorageService.assignments.getAssignments(
// courseName,
// moduleName
// );
// return assignments as CourseItemReturnType<T>[];
// }
// if (type === "Quiz") {
// const quizzes = await fileStorageService.quizzes.getQuizzes(
// courseName,
// moduleName
// );
// return quizzes as CourseItemReturnType<T>[];
// }
// if (type === "Page") {
// const pages = await fileStorageService.pages.getPages(
// courseName,
// moduleName
// );
// return pages as CourseItemReturnType<T>[];
// }
throw Error(`cannot get item from server, invalid type: ${type}`)
}
// throw Error(`cannot get item from server, invalid type: ${type}`)
// }
export async function getItemFromServer<T extends CourseItemType>({
courseName,
moduleName,
type,
itemName,
}: {
courseName: string;
moduleName: string;
type: T;
itemName: string;
}): Promise<CourseItemReturnType<T>> {
if (type === "Assignment") {
const assignment = await fileStorageService.assignments.getAssignment(
courseName,
moduleName,
itemName
);
return assignment as CourseItemReturnType<T>;
}
if (type === "Assignment") {
const quiz = await fileStorageService.quizzes.getQuiz(
courseName,
moduleName,
itemName
);
return quiz as CourseItemReturnType<T>;
}
const page = await fileStorageService.pages.getPage(
courseName,
moduleName,
itemName
);
return page as CourseItemReturnType<T>;
}
// export async function getItemFromServer<T extends CourseItemType>({
// courseName,
// moduleName,
// type,
// itemName,
// }: {
// courseName: string;
// moduleName: string;
// type: T;
// itemName: string;
// }): Promise<CourseItemReturnType<T>> {
// if (type === "Assignment") {
// const assignment = await fileStorageService.assignments.getAssignment(
// courseName,
// moduleName,
// itemName
// );
// return assignment as CourseItemReturnType<T>;
// }
// if (type === "Assignment") {
// const quiz = await fileStorageService.quizzes.getQuiz(
// courseName,
// moduleName,
// itemName
// );
// return quiz as CourseItemReturnType<T>;
// }
// const page = await fileStorageService.pages.getPage(
// courseName,
// moduleName,
// itemName
// );
// return page as CourseItemReturnType<T>;
// }
export async function createItemOnServer<T extends CourseItemType>({
courseName,
moduleName,
type,
item,
itemName,
}: {
courseName: string;
moduleName: string;
type: T;
item: CourseItemReturnType<T>;
itemName: string;
}) {
if (type === "Assignment") {
const assignment = item as LocalAssignment;
await fileStorageService.assignments.updateOrCreateAssignment({
courseName,
moduleName,
assignmentName: itemName,
assignment,
});
}
if (type === "Quiz") {
const quiz = item as LocalQuiz;
await fileStorageService.quizzes.updateQuiz(
courseName,
moduleName,
itemName,
quiz
);
}
if (type === "Page") {
const page = item as LocalCoursePage;
await fileStorageService.pages.updatePage(
courseName,
moduleName,
itemName,
page
);
}
}
// export async function createItemOnServer<T extends CourseItemType>({
// courseName,
// moduleName,
// type,
// item,
// itemName,
// }: {
// courseName: string;
// moduleName: string;
// type: T;
// item: CourseItemReturnType<T>;
// itemName: string;
// }) {
// if (type === "Assignment") {
// const assignment = item as LocalAssignment;
// await fileStorageService.assignments.updateOrCreateAssignment({
// courseName,
// moduleName,
// assignmentName: itemName,
// assignment,
// });
// }
// if (type === "Quiz") {
// const quiz = item as LocalQuiz;
// await fileStorageService.quizzes.updateQuiz(
// courseName,
// moduleName,
// itemName,
// quiz
// );
// }
// if (type === "Page") {
// const page = item as LocalCoursePage;
// await fileStorageService.pages.updatePage(
// courseName,
// moduleName,
// itemName,
// page
// );
// }
// }
export async function updateItemOnServer<T extends CourseItemType>({
item,
courseName,
moduleName,
previousModuleName,
previousItemName,
itemName,
type,
}: {
item: CourseItemReturnType<T>;
courseName: string;
moduleName: string;
previousModuleName: string;
previousItemName: string;
itemName: string;
type: T;
}) {
if (type === "Assignment") {
const assignment = item as LocalAssignment;
await fileStorageService.assignments.updateOrCreateAssignment({
courseName,
moduleName,
assignmentName: itemName,
assignment,
});
// export async function updateItemOnServer<T extends CourseItemType>({
// item,
// courseName,
// moduleName,
// previousModuleName,
// previousItemName,
// itemName,
// type,
// }: {
// item: CourseItemReturnType<T>;
// courseName: string;
// moduleName: string;
// previousModuleName: string;
// previousItemName: string;
// itemName: string;
// type: T;
// }) {
// if (type === "Assignment") {
// const assignment = item as LocalAssignment;
// await fileStorageService.assignments.updateOrCreateAssignment({
// courseName,
// moduleName,
// assignmentName: itemName,
// assignment,
// });
if (
assignment.name !== previousItemName ||
moduleName !== previousModuleName
) {
fileStorageService.assignments.delete({
courseName,
moduleName: previousModuleName,
assignmentName: previousItemName,
});
}
}
if (type === "Quiz") {
const quiz = item as LocalQuiz;
await fileStorageService.quizzes.updateQuiz(
courseName,
moduleName,
itemName,
quiz
);
// if (
// assignment.name !== previousItemName ||
// moduleName !== previousModuleName
// ) {
// fileStorageService.assignments.delete({
// courseName,
// moduleName: previousModuleName,
// assignmentName: previousItemName,
// });
// }
// }
// if (type === "Quiz") {
// const quiz = item as LocalQuiz;
// await fileStorageService.quizzes.updateQuiz(
// courseName,
// moduleName,
// itemName,
// quiz
// );
if (
previousModuleName &&
previousItemName &&
(quiz.name !== previousItemName || moduleName !== previousModuleName)
) {
fileStorageService.quizzes.delete({
courseName,
moduleName: previousModuleName,
quizName: previousItemName,
});
}
}
if (type === "Page") {
const page = item as LocalCoursePage;
await fileStorageService.pages.updatePage(
courseName,
moduleName,
itemName,
page
);
// if (
// previousModuleName &&
// previousItemName &&
// (quiz.name !== previousItemName || moduleName !== previousModuleName)
// ) {
// fileStorageService.quizzes.delete({
// courseName,
// moduleName: previousModuleName,
// quizName: previousItemName,
// });
// }
// }
// if (type === "Page") {
// const page = item as LocalCoursePage;
// await fileStorageService.pages.updatePage(
// courseName,
// moduleName,
// itemName,
// page
// );
if (
previousModuleName &&
previousItemName &&
(page.name !== previousItemName || moduleName !== previousModuleName)
) {
fileStorageService.pages.delete({
courseName,
moduleName: previousModuleName,
pageName: previousItemName,
});
}
}
}
// if (
// previousModuleName &&
// previousItemName &&
// (page.name !== previousItemName || moduleName !== previousModuleName)
// ) {
// fileStorageService.pages.delete({
// courseName,
// moduleName: previousModuleName,
// pageName: previousItemName,
// });
// }
// }
// }
export async function deleteItemOnServer<T extends CourseItemType>({
courseName,
moduleName,
itemName,
type,
}: {
courseName: string;
moduleName: string;
itemName: string;
type: T;
}) {
if (type === "Assignment") {
await fileStorageService.assignments.delete({
courseName,
moduleName,
assignmentName: itemName,
});
}
if (type === "Quiz") {
await fileStorageService.quizzes.delete({
courseName,
moduleName,
quizName: itemName,
});
}
if (type === "Page") {
await fileStorageService.pages.delete({
courseName,
moduleName,
pageName: itemName,
});
}
}
// export async function deleteItemOnServer<T extends CourseItemType>({
// courseName,
// moduleName,
// itemName,
// type,
// }: {
// courseName: string;
// moduleName: string;
// itemName: string;
// type: T;
// }) {
// if (type === "Assignment") {
// await fileStorageService.assignments.delete({
// courseName,
// moduleName,
// assignmentName: itemName,
// });
// }
// if (type === "Quiz") {
// await fileStorageService.quizzes.delete({
// courseName,
// moduleName,
// quizName: itemName,
// });
// }
// if (type === "Page") {
// await fileStorageService.pages.delete({
// courseName,
// moduleName,
// pageName: itemName,
// });
// }
// }

View File

@@ -2,11 +2,9 @@ import { useCourseContext } from "@/app/course/[courseName]/context/courseContex
import {
useMutation,
useQueryClient,
useSuspenseQueries,
useSuspenseQuery,
} from "@tanstack/react-query";
import { localCourseKeys } from "./localCourseKeys";
import { getAllItemsQueryConfig } from "./courseItemHooks";
import {
createModuleOnServer,
getModuleNamesFromServer,

View File

@@ -1,18 +1,48 @@
"use client";
import {
useCreateItemMutation,
useDeleteItemMutation,
useItemQuery,
useItemsQueries,
useUpdateItemMutation,
} from "./courseItemHooks";
export const usePageQuery = (moduleName: string, pageName: string) =>
useItemQuery(moduleName, pageName, "Page");
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { trpc } from "@/services/trpc/utils";
export const usePagesQueries = (moduleName: string) =>
useItemsQueries(moduleName, "Page");
export const usePageQuery = (moduleName: string, pageName: string) => {
const { courseName } = useCourseContext();
return trpc.page.getPage.useSuspenseQuery({
courseName,
moduleName,
pageName,
});
};
export const useUpdatePageMutation = () => useUpdateItemMutation("Page");
export const useCreatePageMutation = () => useCreateItemMutation("Page");
export const useDeletePageMutation = () => useDeleteItemMutation("Page");
export const usePagesQueries = (moduleName: string) => {
const { courseName } = useCourseContext();
return trpc.page.getAllPages.useSuspenseQuery({
courseName,
moduleName,
});
};
export const useUpdatePageMutation = () => {
const utils = trpc.useUtils();
return trpc.page.updatePage.useMutation({
onSuccess: (_, { courseName, moduleName, pageName }) => {
utils.page.getAllPages.invalidate({ courseName, moduleName });
utils.page.getPage.invalidate({ courseName, moduleName, pageName });
},
});
};
export const useCreatePageMutation = () => {
const utils = trpc.useUtils();
return trpc.page.createPage.useMutation({
onSuccess: (_, { courseName, moduleName }) => {
utils.page.getAllPages.invalidate({ courseName, moduleName });
},
});
};
export const useDeletePageMutation = () => {
const utils = trpc.useUtils();
return trpc.page.deletePage.useMutation({
onSuccess: (_, { courseName, moduleName, pageName }) => {
utils.page.getAllPages.invalidate({ courseName, moduleName });
utils.page.getPage.invalidate({ courseName, moduleName, pageName });
},
});
};

View File

@@ -0,0 +1,48 @@
"use client";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { trpc } from "@/services/trpc/utils";
export const useQuizQuery = (moduleName: string, quizName: string) => {
const { courseName } = useCourseContext();
return trpc.quiz.getQuiz.useSuspenseQuery({
courseName,
moduleName,
quizName,
});
};
export const useQuizzesQueries = (moduleName: string) => {
const { courseName } = useCourseContext();
return trpc.quiz.getAllQuizzes.useSuspenseQuery({
courseName,
moduleName,
});
};
export const useUpdateQuizMutation = () => {
const utils = trpc.useUtils();
return trpc.quiz.updateQuiz.useMutation({
onSuccess: (_, { courseName, moduleName, quizName }) => {
utils.quiz.getAllQuizzes.invalidate({ courseName, moduleName });
utils.quiz.getQuiz.invalidate({ courseName, moduleName, quizName });
},
});
};
export const useCreateQuizMutation = () => {
const utils = trpc.useUtils();
return trpc.quiz.createQuiz.useMutation({
onSuccess: (_, { courseName, moduleName }) => {
utils.quiz.getAllQuizzes.invalidate({ courseName, moduleName });
},
});
};
export const useDeleteQuizMutation = () => {
const utils = trpc.useUtils();
return trpc.quiz.deleteQuiz.useMutation({
onSuccess: (_, { courseName, moduleName, quizName }) => {
utils.quiz.getAllQuizzes.invalidate({ courseName, moduleName });
utils.quiz.getQuiz.invalidate({ courseName, moduleName, quizName });
},
});
};

View File

@@ -24,7 +24,7 @@ export const zodLocalAssignment = z.object({
description: z.string(),
lockAt: z.string().optional(),
dueAt: z.string(),
localAssignmentGroupName: z.string(),
localAssignmentGroupName: z.string().optional(),
submissionTypes: zodAssignmentSubmissionType.array(),
allowedFileUploadExtensions: z.string().array(),
rubric: zodRubricItem.array(),

View File

@@ -1,3 +1,4 @@
import { z } from "zod";
import { extractLabelValue } from "../assignment/utils/markdownUtils";
import { IModuleItem } from "../IModuleItem";
import { verifyDateOrThrow } from "../timeUtils";
@@ -8,9 +9,18 @@ export interface LocalCoursePage extends IModuleItem {
dueAt: string;
}
export const zodLocalCoursePage = z.object({
name: z.string(),
text: z.string(),
dueAt: z.string(), // ISO 8601 date string
});
export const localPageMarkdownUtils = {
toMarkdown: (page: LocalCoursePage) => {
const printableDueDate = verifyDateOrThrow(page.dueAt, "page DueDateForOrdering")
const printableDueDate = verifyDateOrThrow(
page.dueAt,
"page DueDateForOrdering"
);
const settingsMarkdown = `Name: ${page.name}\nDueDateForOrdering: ${printableDueDate}\n---\n`;
return settingsMarkdown + page.text;
},

View File

@@ -1,5 +1,6 @@
import { z } from "zod";
import { IModuleItem } from "../IModuleItem";
import { LocalQuizQuestion } from "./localQuizQuestion";
import { LocalQuizQuestion, zodLocalQuizQuestion } from "./localQuizQuestion";
import { quizMarkdownUtils } from "./utils/quizMarkdownUtils";
export interface LocalQuiz extends IModuleItem {
@@ -16,6 +17,20 @@ export interface LocalQuiz extends IModuleItem {
questions: LocalQuizQuestion[];
}
export const zodLocalQuiz = z.object({
name: z.string(),
description: z.string(),
password: z.string().optional(),
lockAt: z.string().optional(),
dueAt: z.string(),
shuffleAnswers: z.boolean(),
showCorrectAnswers: z.boolean(),
oneQuestionAtATime: z.boolean(),
localAssignmentGroupName: z.string().optional(),
allowedAttempts: z.number(),
questions: zodLocalQuizQuestion.array(),
});
export const localQuizMarkdownUtils = {
parseMarkdown: quizMarkdownUtils.parseMarkdown,
toMarkdown: quizMarkdownUtils.toMarkdown,

View File

@@ -1,12 +1,8 @@
import { LocalQuizQuestionAnswer } from "./localQuizQuestionAnswer";
export interface LocalQuizQuestion {
text: string;
questionType: QuestionType;
points: number;
answers: LocalQuizQuestionAnswer[];
matchDistractors: string[];
}
import { z } from "zod";
import {
LocalQuizQuestionAnswer,
zodLocalQuizQuestionAnswer,
} from "./localQuizQuestionAnswer";
export enum QuestionType {
MULTIPLE_ANSWERS = "multiple_answers",
@@ -16,3 +12,27 @@ export enum QuestionType {
MATCHING = "matching",
NONE = "",
}
export const zodQuestionType = z.enum([
QuestionType.MULTIPLE_ANSWERS,
QuestionType.MULTIPLE_CHOICE,
QuestionType.ESSAY,
QuestionType.SHORT_ANSWER,
QuestionType.MATCHING,
QuestionType.NONE,
]);
export interface LocalQuizQuestion {
text: string;
questionType: QuestionType;
points: number;
answers: LocalQuizQuestionAnswer[];
matchDistractors: string[];
}
export const zodLocalQuizQuestion = z.object({
text: z.string(),
questionType: zodQuestionType,
points: z.number(),
answers: zodLocalQuizQuestionAnswer.array(),
matchDistractors: z.array(z.string()),
});

View File

@@ -1,5 +1,13 @@
import { z } from "zod";
export interface LocalQuizQuestionAnswer {
correct: boolean;
text: string;
matchedText?: string;
}
export const zodLocalQuizQuestionAnswer = z.object({
correct: z.boolean(),
text: z.string(),
matchedText: z.string().optional(),
});

View File

@@ -18,12 +18,17 @@ export const pageFileStorageService = {
getPages: async (courseName: string, moduleName: string) =>
await courseItemFileStorageService.getItems(courseName, moduleName, "Page"),
async updatePage(
courseName: string,
moduleName: string,
pageName: string,
page: LocalCoursePage
) {
async updatePage({
courseName,
moduleName,
pageName,
page,
}: {
courseName: string;
moduleName: string;
pageName: string;
page: LocalCoursePage;
}) {
const folder = path.join(basePath, courseName, moduleName, "pages");
await fs.mkdir(folder, { recursive: true });

View File

@@ -1,13 +1,10 @@
import {
LocalQuiz,
} from "@/models/local/quiz/localQuiz";
import { LocalQuiz } from "@/models/local/quiz/localQuiz";
import { quizMarkdownUtils } from "@/models/local/quiz/utils/quizMarkdownUtils";
import path from "path";
import { basePath } from "./utils/fileSystemUtils";
import { promises as fs } from "fs";
import { courseItemFileStorageService } from "./courseItemFileStorageService";
export const quizFileStorageService = {
getQuiz: async (courseName: string, moduleName: string, quizName: string) =>
await courseItemFileStorageService.getItem(
@@ -19,12 +16,17 @@ export const quizFileStorageService = {
getQuizzes: async (courseName: string, moduleName: string) =>
await courseItemFileStorageService.getItems(courseName, moduleName, "Quiz"),
async updateQuiz(
courseName: string,
moduleName: string,
quizName: string,
quiz: LocalQuiz
) {
async updateQuiz({
courseName,
moduleName,
quizName,
quiz,
}: {
courseName: string;
moduleName: string;
quizName: string;
quiz: LocalQuiz;
}) {
const folder = path.join(basePath, courseName, moduleName, "quizzes");
await fs.mkdir(folder, { recursive: true });
const filePath = path.join(

View File

@@ -3,6 +3,8 @@ import publicProcedure from "../procedures/public";
import { createCallerFactory, router } from "../trpc";
import { assignmentRouter } from "./assignmentRouter";
import { lectureRouter } from "./lectureRouter";
import { pageRouter } from "./pageRouter";
import { quizRouter } from "./quizRouter";
import { settingsRouter } from "./settingsRouter";
export const helloRouter = router({
@@ -18,6 +20,8 @@ export const trpcAppRouter = router({
assignment: assignmentRouter,
lectures: lectureRouter,
settings: settingsRouter,
quiz: quizRouter,
page: pageRouter,
});
export const createCaller = createCallerFactory(trpcAppRouter);

View File

@@ -45,7 +45,36 @@ export const assignmentRouter = router({
.mutation(
async ({
input: { courseName, moduleName, assignmentName, assignment },
ctx,
}) => {
await fileStorageService.assignments.updateOrCreateAssignment({
courseName,
moduleName,
assignmentName,
assignment,
});
}
),
updateAssignment: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
previousModuleName: z.string(),
previousAssignmentName: z.string(),
assignmentName: z.string(),
assignment: zodLocalAssignment,
})
)
.mutation(
async ({
input: {
courseName,
moduleName,
assignmentName,
assignment,
previousModuleName,
previousAssignmentName,
},
}) => {
await fileStorageService.assignments.updateOrCreateAssignment({
courseName,
@@ -54,7 +83,31 @@ export const assignmentRouter = router({
assignment,
});
ctx;
if (
assignment.name !== previousAssignmentName ||
moduleName !== previousModuleName
) {
fileStorageService.assignments.delete({
courseName,
moduleName: previousModuleName,
assignmentName: previousAssignmentName,
});
}
}
),
deleteAssignment: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
assignmentName: z.string(),
})
)
.mutation(async ({ input: { courseName, moduleName, assignmentName } }) => {
await fileStorageService.assignments.delete({
courseName,
moduleName,
assignmentName,
});
}),
});

View File

@@ -0,0 +1,107 @@
import publicProcedure from "../procedures/public";
import { z } from "zod";
import { router } from "../trpc";
import { fileStorageService } from "@/services/fileStorage/fileStorageService";
import { zodLocalCoursePage } from "@/models/local/page/localCoursePage";
export const pageRouter = router({
getPage: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
pageName: z.string(),
})
)
.query(async ({ input: { courseName, moduleName, pageName } }) => {
return await fileStorageService.pages.getPage(
courseName,
moduleName,
pageName
);
}),
getAllPages: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
})
)
.query(async ({ input: { courseName, moduleName } }) => {
return await fileStorageService.pages.getPages(courseName, moduleName);
}),
createPage: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
pageName: z.string(),
page: zodLocalCoursePage,
})
)
.mutation(async ({ input: { courseName, moduleName, pageName, page } }) => {
await fileStorageService.pages.updatePage({
courseName,
moduleName,
pageName,
page,
});
}),
updatePage: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
previousModuleName: z.string(),
previousPageName: z.string(),
pageName: z.string(),
page: zodLocalCoursePage,
})
)
.mutation(
async ({
input: {
courseName,
moduleName,
pageName,
page,
previousModuleName,
previousPageName,
},
}) => {
await fileStorageService.pages.updatePage({
courseName,
moduleName,
pageName,
page,
});
if (
page.name !== previousPageName ||
moduleName !== previousModuleName
) {
fileStorageService.pages.delete({
courseName,
moduleName: previousModuleName,
pageName: previousPageName,
});
}
}
),
deletePage: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
pageName: z.string(),
})
)
.mutation(async ({ input: { courseName, moduleName, pageName } }) => {
await fileStorageService.pages.delete({
courseName,
moduleName,
pageName,
});
}),
});

View File

@@ -0,0 +1,110 @@
import publicProcedure from "../procedures/public";
import { z } from "zod";
import { router } from "../trpc";
import { fileStorageService } from "@/services/fileStorage/fileStorageService";
import { zodLocalQuiz } from "@/models/local/quiz/localQuiz";
export const quizRouter = router({
getQuiz: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
quizName: z.string(),
})
)
.query(async ({ input: { courseName, moduleName, quizName } }) => {
return await fileStorageService.quizzes.getQuiz(
courseName,
moduleName,
quizName
);
}),
getAllQuizzes: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
})
)
.query(async ({ input: { courseName, moduleName } }) => {
return await fileStorageService.quizzes.getQuizzes(
courseName,
moduleName
);
}),
createQuiz: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
quizName: z.string(),
quiz: zodLocalQuiz,
})
)
.mutation(async ({ input: { courseName, moduleName, quizName, quiz } }) => {
await fileStorageService.quizzes.updateQuiz({
courseName,
moduleName,
quizName,
quiz,
});
}),
updateQuiz: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
previousModuleName: z.string(),
previousQuizName: z.string(),
quizName: z.string(),
quiz: zodLocalQuiz,
})
)
.mutation(
async ({
input: {
courseName,
moduleName,
quizName,
quiz,
previousModuleName,
previousQuizName,
},
}) => {
await fileStorageService.quizzes.updateQuiz({
courseName,
moduleName,
quizName,
quiz,
});
if (
quiz.name !== previousQuizName ||
moduleName !== previousModuleName
) {
fileStorageService.quizzes.delete({
courseName,
moduleName: previousModuleName,
quizName: previousQuizName,
});
}
}
),
deleteQuiz: publicProcedure
.input(
z.object({
courseName: z.string(),
moduleName: z.string(),
quizName: z.string(),
})
)
.mutation(async ({ input: { courseName, moduleName, quizName } }) => {
await fileStorageService.quizzes.delete({
courseName,
moduleName,
quizName,
});
}),
});