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 { Dispatch, SetStateAction, useCallback, DragEvent } from "react";
import { DraggableItem } from "./draggingContext"; import { DraggableItem } from "./draggingContext";
import { getNewLockDate } from "./getNewLockDate"; import { getNewLockDate } from "./getNewLockDate";
import { useUpdateItemMutation } from "@/hooks/localCourse/courseItemHooks";
import { trpc } from "@/services/trpc/utils"; import { trpc } from "@/services/trpc/utils";
import { useUpdateQuizMutation } from "@/hooks/localCourse/quizHooks";
export function useItemDropOnDay({ export function useItemDropOnDay({
setIsDragging, setIsDragging,
@@ -37,7 +37,7 @@ export function useItemDropOnDay({
const [weeks] = trpc.lectures.getLectures.useSuspenseQuery({ const [weeks] = trpc.lectures.getLectures.useSuspenseQuery({
courseName: settings.name, courseName: settings.name,
}); });
const updateQuizMutation = useUpdateItemMutation("Quiz"); const updateQuizMutation = useUpdateQuizMutation();
const updateLectureMutation = useLectureUpdateMutation(); const updateLectureMutation = useLectureUpdateMutation();
const updateAssignmentMutation = useUpdateAssignmentMutation(); const updateAssignmentMutation = useUpdateAssignmentMutation();
const updatePageMutation = useUpdatePageMutation(); const updatePageMutation = useUpdatePageMutation();
@@ -132,11 +132,12 @@ export function useItemDropOnDay({
), ),
}; };
updateQuizMutation.mutate({ updateQuizMutation.mutate({
item: quiz, quiz,
itemName: quiz.name, quizName: quiz.name,
moduleName: itemBeingDragged.sourceModuleName, moduleName: itemBeingDragged.sourceModuleName,
previousModuleName: itemBeingDragged.sourceModuleName, previousModuleName: itemBeingDragged.sourceModuleName,
previousItemName: quiz.name, previousQuizName: quiz.name,
courseName: settings.name,
}); });
} }
function updatePage(dayAsDate: Date) { function updatePage(dayAsDate: Date) {
@@ -152,11 +153,12 @@ export function useItemDropOnDay({
dueAt: dateToMarkdownString(dayAsDate), dueAt: dateToMarkdownString(dayAsDate),
}; };
updatePageMutation.mutate({ updatePageMutation.mutate({
item: page, page,
moduleName: itemBeingDragged.sourceModuleName, moduleName: itemBeingDragged.sourceModuleName,
itemName: page.name, pageName: page.name,
previousItemName: page.name, previousPageName: page.name,
previousModuleName: itemBeingDragged.sourceModuleName, previousModuleName: itemBeingDragged.sourceModuleName,
courseName: settings.name,
}); });
} }
function updateAssignment(dayAsDate: Date) { function updateAssignment(dayAsDate: Date) {
@@ -177,11 +179,12 @@ export function useItemDropOnDay({
), ),
}; };
updateAssignmentMutation.mutate({ updateAssignmentMutation.mutate({
item: assignment, assignment,
previousModuleName: itemBeingDragged.sourceModuleName, previousModuleName: itemBeingDragged.sourceModuleName,
moduleName: itemBeingDragged.sourceModuleName, moduleName: itemBeingDragged.sourceModuleName,
itemName: assignment.name, assignmentName: assignment.name,
previousItemName: 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 { LocalQuiz } from "@/models/local/quiz/localQuiz";
import { Dispatch, SetStateAction, useCallback, DragEvent } from "react"; import { Dispatch, SetStateAction, useCallback, DragEvent } from "react";
import { DraggableItem } from "./draggingContext"; import { DraggableItem } from "./draggingContext";
import { useUpdateItemMutation } from "@/hooks/localCourse/courseItemHooks"; import { useCourseContext } from "../courseContext";
import { useUpdateQuizMutation } from "@/hooks/localCourse/quizHooks";
export function useItemDropOnModule({ export function useItemDropOnModule({
setIsDragging, setIsDragging,
}: { }: {
setIsDragging: Dispatch<SetStateAction<boolean>>; setIsDragging: Dispatch<SetStateAction<boolean>>;
}) { }) {
const updateQuizMutation = useUpdateItemMutation("Quiz"); const updateQuizMutation = useUpdateQuizMutation();
const updateAssignmentMutation = useUpdateAssignmentMutation(); const updateAssignmentMutation = useUpdateAssignmentMutation();
const updatePageMutation = useUpdatePageMutation(); const updatePageMutation = useUpdatePageMutation();
const { courseName } = useCourseContext();
return useCallback( return useCallback(
(e: DragEvent, dropModuleName: string) => { (e: DragEvent, dropModuleName: string) => {
@@ -41,11 +43,12 @@ export function useItemDropOnModule({
const quiz = itemBeingDragged.item as LocalQuiz; const quiz = itemBeingDragged.item as LocalQuiz;
if (itemBeingDragged.sourceModuleName) { if (itemBeingDragged.sourceModuleName) {
updateQuizMutation.mutate({ updateQuizMutation.mutate({
item: quiz, quiz,
itemName: quiz.name, quizName: quiz.name,
moduleName: dropModuleName, moduleName: dropModuleName,
previousModuleName: itemBeingDragged.sourceModuleName, previousModuleName: itemBeingDragged.sourceModuleName,
previousItemName: quiz.name, previousQuizName: quiz.name,
courseName,
}); });
} else { } else {
console.error( console.error(
@@ -58,11 +61,12 @@ export function useItemDropOnModule({
const assignment = itemBeingDragged.item as LocalAssignment; const assignment = itemBeingDragged.item as LocalAssignment;
if (itemBeingDragged.sourceModuleName) { if (itemBeingDragged.sourceModuleName) {
updateAssignmentMutation.mutate({ updateAssignmentMutation.mutate({
item: assignment, assignment,
previousModuleName: itemBeingDragged.sourceModuleName, previousModuleName: itemBeingDragged.sourceModuleName,
moduleName: dropModuleName, moduleName: dropModuleName,
itemName: assignment.name, assignmentName: assignment.name,
previousItemName: assignment.name, previousAssignmentName: assignment.name,
courseName,
}); });
} else { } else {
console.error( console.error(
@@ -75,11 +79,12 @@ export function useItemDropOnModule({
const page = itemBeingDragged.item as LocalCoursePage; const page = itemBeingDragged.item as LocalCoursePage;
if (itemBeingDragged.sourceModuleName) { if (itemBeingDragged.sourceModuleName) {
updatePageMutation.mutate({ updatePageMutation.mutate({
item: page, page,
moduleName: dropModuleName, moduleName: dropModuleName,
itemName: page.name, pageName: page.name,
previousItemName: page.name, previousPageName: page.name,
previousModuleName: itemBeingDragged.sourceModuleName, previousModuleName: itemBeingDragged.sourceModuleName,
courseName,
}); });
} else { } else {
console.error( console.error(
@@ -90,6 +95,7 @@ export function useItemDropOnModule({
} }
}, },
[ [
courseName,
setIsDragging, setIsDragging,
updateAssignmentMutation, updateAssignmentMutation,
updatePageMutation, updatePageMutation,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,5 @@
"use client"; "use client";
import { trpc } from "@/services/trpc/utils"; import { trpc } from "@/services/trpc/utils";
import {
getAllItemsQueryConfig,
getItemQueryConfig,
useDeleteItemMutation,
useItemQuery,
useItemsQueries,
useUpdateItemMutation,
} from "./courseItemHooks";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext"; import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
// export const getAllAssignmentsQueryConfig = ( // export const getAllAssignmentsQueryConfig = (
@@ -36,31 +28,31 @@ export const useAssignmentQuery = (
export const useAssignmentsQuery = (moduleName: string) => { export const useAssignmentsQuery = (moduleName: string) => {
const { courseName } = useCourseContext(); const { courseName } = useCourseContext();
console.log("rendering all assignments query"); console.log("rendering all assignments query");
return trpc.assignment.getAllAssignments.useQuery({ return trpc.assignment.getAllAssignments.useSuspenseQuery({
moduleName, moduleName,
courseName, courseName,
}); });
}; };
// useItemsQueries(moduleName, "Assignment");
export const useUpdateAssignmentMutation = () => export const useUpdateAssignmentMutation = () => {
useUpdateItemMutation("Assignment"); return trpc.assignment.updateAssignment.useMutation();
};
export const useCreateAssignmentMutation = ({ export const useCreateAssignmentMutation = () => {
courseName,
moduleName,
}: {
courseName: string;
moduleName: string;
}) => {
const utils = trpc.useUtils(); const utils = trpc.useUtils();
return trpc.assignment.createAssignment.useMutation({ return trpc.assignment.createAssignment.useMutation({
onSuccess: () => { onSuccess: (_, { courseName, moduleName }) => {
utils.assignment.getAllAssignments.invalidate({ courseName, moduleName }); utils.assignment.getAllAssignments.invalidate({ courseName, moduleName });
}, },
}); });
}; };
// useCreateItemMutation("Assignment"); // useCreateItemMutation("Assignment");
export const useDeleteAssignmentMutation = () => export const useDeleteAssignmentMutation = () => {
useDeleteItemMutation("Assignment"); 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 { localCourseKeys } from "./localCourseKeys";
import { // import {
CourseItemReturnType, // CourseItemReturnType,
CourseItemType, // CourseItemType,
} from "@/models/local/courseItemTypes"; // } from "@/models/local/courseItemTypes";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext"; // import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { // import {
useMutation, // useMutation,
useQueryClient, // useQueryClient,
useSuspenseQueries, // useSuspenseQueries,
useSuspenseQuery, // useSuspenseQuery,
} from "@tanstack/react-query"; // } from "@tanstack/react-query";
import { // // import {
createItemOnServer, // // createItemOnServer,
deleteItemOnServer, // // deleteItemOnServer,
getAllItemsFromServer, // // getAllItemsFromServer,
getItemFromServer, // // getItemFromServer,
updateItemOnServer, // // updateItemOnServer,
} from "./courseItemServerActions"; // // } from "./courseItemServerActions";
export const getAllItemsQueryConfig = <T extends CourseItemType>( // export const getAllItemsQueryConfig = <T extends CourseItemType>(
courseName: string, // courseName: string,
moduleName: string, // moduleName: string,
type: T // type: T
) => ({ // ) => ({
queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type), // queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
queryFn: async (): Promise<CourseItemReturnType<T>[]> => { // queryFn: async (): Promise<CourseItemReturnType<T>[]> => {
return await getAllItemsFromServer({ // return await getAllItemsFromServer({
courseName, // courseName,
moduleName, // moduleName,
type, // type,
}); // });
}, // },
}); // });
export const getItemQueryConfig = <T extends CourseItemType>( // export const getItemQueryConfig = <T extends CourseItemType>(
courseName: string, // courseName: string,
moduleName: string, // moduleName: string,
name: string, // name: string,
type: T // type: T
) => { // ) => {
return { // return {
queryKey: localCourseKeys.itemOfType(courseName, moduleName, name, type), // queryKey: localCourseKeys.itemOfType(courseName, moduleName, name, type),
queryFn: async () => { // queryFn: async () => {
return await getItemFromServer({ // return await getItemFromServer({
moduleName, // moduleName,
courseName, // courseName,
itemName: name, // itemName: name,
type, // type,
}); // });
}, // },
}; // };
}; // };
export const useItemQuery = <T extends CourseItemType>( // export const useItemQuery = <T extends CourseItemType>(
moduleName: string, // moduleName: string,
name: string, // name: string,
type: T // type: T
) => { // ) => {
const { courseName } = useCourseContext(); // const { courseName } = useCourseContext();
return useSuspenseQuery( // return useSuspenseQuery(
getItemQueryConfig(courseName, moduleName, name, type) // getItemQueryConfig(courseName, moduleName, name, type)
); // );
}; // };
const useAllItemsQuery = <T extends CourseItemType>( // const useAllItemsQuery = <T extends CourseItemType>(
moduleName: string, // moduleName: string,
type: T // type: T
) => { // ) => {
const { courseName } = useCourseContext(); // const { courseName } = useCourseContext();
return useSuspenseQuery(getAllItemsQueryConfig(courseName, moduleName, type)); // return useSuspenseQuery(getAllItemsQueryConfig(courseName, moduleName, type));
}; // };
export const useItemsQueries = <T extends CourseItemType>( // export const useItemsQueries = <T extends CourseItemType>(
moduleName: string, // moduleName: string,
type: T // type: T
) => { // ) => {
const { data: allItems } = useAllItemsQuery(moduleName, type); // const { data: allItems } = useAllItemsQuery(moduleName, type);
const { courseName } = useCourseContext(); // const { courseName } = useCourseContext();
return useSuspenseQueries({ // return useSuspenseQueries({
queries: allItems.map((item) => ({ // queries: allItems.map((item) => ({
...getItemQueryConfig(courseName, moduleName, item.name, type), // ...getItemQueryConfig(courseName, moduleName, item.name, type),
})), // })),
combine: (results) => ({ // combine: (results) => ({
data: results.map((r) => r.data), // data: results.map((r) => r.data),
pending: results.some((r) => r.isPending), // pending: results.some((r) => r.isPending),
}), // }),
}); // });
}; // };
export const useUpdateItemMutation = <T extends CourseItemType>(type: T) => { // export const useUpdateItemMutation = <T extends CourseItemType>(type: T) => {
const { courseName } = useCourseContext(); // const { courseName } = useCourseContext();
const queryClient = useQueryClient(); // const queryClient = useQueryClient();
return useMutation({ // return useMutation({
mutationFn: async ({ // mutationFn: async ({
item, // item,
moduleName, // moduleName,
previousModuleName, // previousModuleName,
previousItemName, // previousItemName,
itemName, // itemName,
}: { // }: {
item: CourseItemReturnType<T>; // item: CourseItemReturnType<T>;
moduleName: string; // moduleName: string;
previousModuleName: string; // previousModuleName: string;
previousItemName: string; // previousItemName: string;
itemName: string; // itemName: string;
}) => { // }) => {
if (previousItemName !== item.name || previousModuleName !== moduleName) { // if (previousItemName !== item.name || previousModuleName !== moduleName) {
queryClient.removeQueries({ // queryClient.removeQueries({
queryKey: localCourseKeys.itemOfType( // queryKey: localCourseKeys.itemOfType(
courseName, // courseName,
previousModuleName, // previousModuleName,
previousItemName, // previousItemName,
type // type
), // ),
}); // });
queryClient.removeQueries({ // queryClient.removeQueries({
queryKey: localCourseKeys.allItemsOfType( // queryKey: localCourseKeys.allItemsOfType(
courseName, // courseName,
previousModuleName, // previousModuleName,
type // type
), // ),
}); // });
} // }
queryClient.setQueryData( // queryClient.setQueryData(
localCourseKeys.itemOfType(courseName, moduleName, itemName, type), // localCourseKeys.itemOfType(courseName, moduleName, itemName, type),
item // item
); // );
await updateItemOnServer({ // await updateItemOnServer({
courseName, // courseName,
moduleName, // moduleName,
item, // item,
type, // type,
previousItemName, // previousItemName,
previousModuleName, // previousModuleName,
itemName, // itemName,
}); // });
}, // },
onSuccess: async (_, { moduleName, itemName }) => { // onSuccess: async (_, { moduleName, itemName }) => {
await queryClient.invalidateQueries({ // await queryClient.invalidateQueries({
queryKey: localCourseKeys.itemOfType( // queryKey: localCourseKeys.itemOfType(
courseName, // courseName,
moduleName, // moduleName,
itemName, // itemName,
type // 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),
// refetchType: "all", // refetchType: "all",
}); // });
await queryClient.invalidateQueries({ // await queryClient.invalidateQueries({
queryKey: localCourseKeys.itemOfType( // queryKey: localCourseKeys.allItemsOfType(courseName, moduleName, type),
courseName, // refetchType: "all",
moduleName, // });
itemName, // },
type // });
), // };
refetchType: "none",
}); // 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 { ItemInDay } from "@/app/course/[courseName]/calendar/day/ItemInDay";
import { LocalAssignment } from "@/models/local/assignment/localAssignment"; // import { LocalAssignment } from "@/models/local/assignment/localAssignment";
import { // import {
CourseItemReturnType, // CourseItemReturnType,
CourseItemType, // CourseItemType,
} from "@/models/local/courseItemTypes"; // } from "@/models/local/courseItemTypes";
import { LocalCoursePage } from "@/models/local/page/localCoursePage"; // import { LocalCoursePage } from "@/models/local/page/localCoursePage";
import { LocalQuiz } from "@/models/local/quiz/localQuiz"; // import { LocalQuiz } from "@/models/local/quiz/localQuiz";
import { fileStorageService } from "@/services/fileStorage/fileStorageService"; // import { fileStorageService } from "@/services/fileStorage/fileStorageService";
export async function getAllItemsFromServer<T extends CourseItemType>({ // export async function getAllItemsFromServer<T extends CourseItemType>({
courseName, // courseName,
moduleName, // moduleName,
type, // type,
}: { // }: {
courseName: string; // courseName: string;
moduleName: string; // moduleName: string;
type: T; // type: T;
}): Promise<CourseItemReturnType<T>[]> { // }): Promise<CourseItemReturnType<T>[]> {
if (type === "Assignment") { // if (type === "Assignment") {
const assignments = await fileStorageService.assignments.getAssignments( // const assignments = await fileStorageService.assignments.getAssignments(
courseName, // courseName,
moduleName // moduleName
); // );
return assignments as CourseItemReturnType<T>[]; // return assignments as CourseItemReturnType<T>[];
} // }
if (type === "Quiz") { // if (type === "Quiz") {
const quizzes = await fileStorageService.quizzes.getQuizzes( // const quizzes = await fileStorageService.quizzes.getQuizzes(
courseName, // courseName,
moduleName // moduleName
); // );
return quizzes as CourseItemReturnType<T>[]; // return quizzes as CourseItemReturnType<T>[];
} // }
if (type === "Page") { // if (type === "Page") {
const pages = await fileStorageService.pages.getPages( // const pages = await fileStorageService.pages.getPages(
courseName, // courseName,
moduleName // moduleName
); // );
return pages as CourseItemReturnType<T>[]; // 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>({ // export async function getItemFromServer<T extends CourseItemType>({
courseName, // courseName,
moduleName, // moduleName,
type, // type,
itemName, // itemName,
}: { // }: {
courseName: string; // courseName: string;
moduleName: string; // moduleName: string;
type: T; // type: T;
itemName: string; // itemName: string;
}): Promise<CourseItemReturnType<T>> { // }): Promise<CourseItemReturnType<T>> {
if (type === "Assignment") { // if (type === "Assignment") {
const assignment = await fileStorageService.assignments.getAssignment( // const assignment = await fileStorageService.assignments.getAssignment(
courseName, // courseName,
moduleName, // moduleName,
itemName // itemName
); // );
return assignment as CourseItemReturnType<T>; // return assignment as CourseItemReturnType<T>;
} // }
if (type === "Assignment") { // if (type === "Assignment") {
const quiz = await fileStorageService.quizzes.getQuiz( // const quiz = await fileStorageService.quizzes.getQuiz(
courseName, // courseName,
moduleName, // moduleName,
itemName // itemName
); // );
return quiz as CourseItemReturnType<T>; // return quiz as CourseItemReturnType<T>;
} // }
const page = await fileStorageService.pages.getPage( // const page = await fileStorageService.pages.getPage(
courseName, // courseName,
moduleName, // moduleName,
itemName // itemName
); // );
return page as CourseItemReturnType<T>; // return page as CourseItemReturnType<T>;
} // }
export async function createItemOnServer<T extends CourseItemType>({ // export async function createItemOnServer<T extends CourseItemType>({
courseName, // courseName,
moduleName, // moduleName,
type, // type,
item, // item,
itemName, // itemName,
}: { // }: {
courseName: string; // courseName: string;
moduleName: string; // moduleName: string;
type: T; // type: T;
item: CourseItemReturnType<T>; // item: CourseItemReturnType<T>;
itemName: string; // itemName: string;
}) { // }) {
if (type === "Assignment") { // if (type === "Assignment") {
const assignment = item as LocalAssignment; // const assignment = item as LocalAssignment;
await fileStorageService.assignments.updateOrCreateAssignment({ // await fileStorageService.assignments.updateOrCreateAssignment({
courseName, // courseName,
moduleName, // moduleName,
assignmentName: itemName, // assignmentName: itemName,
assignment, // assignment,
}); // });
} // }
if (type === "Quiz") { // if (type === "Quiz") {
const quiz = item as LocalQuiz; // const quiz = item as LocalQuiz;
await fileStorageService.quizzes.updateQuiz( // await fileStorageService.quizzes.updateQuiz(
courseName, // courseName,
moduleName, // moduleName,
itemName, // itemName,
quiz // quiz
); // );
} // }
if (type === "Page") { // if (type === "Page") {
const page = item as LocalCoursePage; // const page = item as LocalCoursePage;
await fileStorageService.pages.updatePage( // await fileStorageService.pages.updatePage(
courseName, // courseName,
moduleName, // moduleName,
itemName, // itemName,
page // page
); // );
} // }
} // }
export async function updateItemOnServer<T extends CourseItemType>({ // export async function updateItemOnServer<T extends CourseItemType>({
item, // item,
courseName, // courseName,
moduleName, // moduleName,
previousModuleName, // previousModuleName,
previousItemName, // previousItemName,
itemName, // itemName,
type, // type,
}: { // }: {
item: CourseItemReturnType<T>; // item: CourseItemReturnType<T>;
courseName: string; // courseName: string;
moduleName: string; // moduleName: string;
previousModuleName: string; // previousModuleName: string;
previousItemName: string; // previousItemName: string;
itemName: string; // itemName: string;
type: T; // type: T;
}) { // }) {
if (type === "Assignment") { // if (type === "Assignment") {
const assignment = item as LocalAssignment; // const assignment = item as LocalAssignment;
await fileStorageService.assignments.updateOrCreateAssignment({ // await fileStorageService.assignments.updateOrCreateAssignment({
courseName, // courseName,
moduleName, // moduleName,
assignmentName: itemName, // assignmentName: itemName,
assignment, // assignment,
}); // });
if ( // if (
assignment.name !== previousItemName || // assignment.name !== previousItemName ||
moduleName !== previousModuleName // moduleName !== previousModuleName
) { // ) {
fileStorageService.assignments.delete({ // fileStorageService.assignments.delete({
courseName, // courseName,
moduleName: previousModuleName, // moduleName: previousModuleName,
assignmentName: previousItemName, // assignmentName: previousItemName,
}); // });
} // }
} // }
if (type === "Quiz") { // if (type === "Quiz") {
const quiz = item as LocalQuiz; // const quiz = item as LocalQuiz;
await fileStorageService.quizzes.updateQuiz( // await fileStorageService.quizzes.updateQuiz(
courseName, // courseName,
moduleName, // moduleName,
itemName, // itemName,
quiz // quiz
); // );
if ( // if (
previousModuleName && // previousModuleName &&
previousItemName && // previousItemName &&
(quiz.name !== previousItemName || moduleName !== previousModuleName) // (quiz.name !== previousItemName || moduleName !== previousModuleName)
) { // ) {
fileStorageService.quizzes.delete({ // fileStorageService.quizzes.delete({
courseName, // courseName,
moduleName: previousModuleName, // moduleName: previousModuleName,
quizName: previousItemName, // quizName: previousItemName,
}); // });
} // }
} // }
if (type === "Page") { // if (type === "Page") {
const page = item as LocalCoursePage; // const page = item as LocalCoursePage;
await fileStorageService.pages.updatePage( // await fileStorageService.pages.updatePage(
courseName, // courseName,
moduleName, // moduleName,
itemName, // itemName,
page // page
); // );
if ( // if (
previousModuleName && // previousModuleName &&
previousItemName && // previousItemName &&
(page.name !== previousItemName || moduleName !== previousModuleName) // (page.name !== previousItemName || moduleName !== previousModuleName)
) { // ) {
fileStorageService.pages.delete({ // fileStorageService.pages.delete({
courseName, // courseName,
moduleName: previousModuleName, // moduleName: previousModuleName,
pageName: previousItemName, // pageName: previousItemName,
}); // });
} // }
} // }
} // }
export async function deleteItemOnServer<T extends CourseItemType>({ // export async function deleteItemOnServer<T extends CourseItemType>({
courseName, // courseName,
moduleName, // moduleName,
itemName, // itemName,
type, // type,
}: { // }: {
courseName: string; // courseName: string;
moduleName: string; // moduleName: string;
itemName: string; // itemName: string;
type: T; // type: T;
}) { // }) {
if (type === "Assignment") { // if (type === "Assignment") {
await fileStorageService.assignments.delete({ // await fileStorageService.assignments.delete({
courseName, // courseName,
moduleName, // moduleName,
assignmentName: itemName, // assignmentName: itemName,
}); // });
} // }
if (type === "Quiz") { // if (type === "Quiz") {
await fileStorageService.quizzes.delete({ // await fileStorageService.quizzes.delete({
courseName, // courseName,
moduleName, // moduleName,
quizName: itemName, // quizName: itemName,
}); // });
} // }
if (type === "Page") { // if (type === "Page") {
await fileStorageService.pages.delete({ // await fileStorageService.pages.delete({
courseName, // courseName,
moduleName, // moduleName,
pageName: itemName, // pageName: itemName,
}); // });
} // }
} // }

View File

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

View File

@@ -1,18 +1,48 @@
"use client"; "use client";
import {
useCreateItemMutation,
useDeleteItemMutation,
useItemQuery,
useItemsQueries,
useUpdateItemMutation,
} from "./courseItemHooks";
export const usePageQuery = (moduleName: string, pageName: string) => import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
useItemQuery(moduleName, pageName, "Page"); import { trpc } from "@/services/trpc/utils";
export const usePagesQueries = (moduleName: string) => export const usePageQuery = (moduleName: string, pageName: string) => {
useItemsQueries(moduleName, "Page"); const { courseName } = useCourseContext();
return trpc.page.getPage.useSuspenseQuery({
courseName,
moduleName,
pageName,
});
};
export const useUpdatePageMutation = () => useUpdateItemMutation("Page"); export const usePagesQueries = (moduleName: string) => {
export const useCreatePageMutation = () => useCreateItemMutation("Page"); const { courseName } = useCourseContext();
export const useDeletePageMutation = () => useDeleteItemMutation("Page"); 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(), description: z.string(),
lockAt: z.string().optional(), lockAt: z.string().optional(),
dueAt: z.string(), dueAt: z.string(),
localAssignmentGroupName: z.string(), localAssignmentGroupName: z.string().optional(),
submissionTypes: zodAssignmentSubmissionType.array(), submissionTypes: zodAssignmentSubmissionType.array(),
allowedFileUploadExtensions: z.string().array(), allowedFileUploadExtensions: z.string().array(),
rubric: zodRubricItem.array(), rubric: zodRubricItem.array(),

View File

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

View File

@@ -1,5 +1,6 @@
import { z } from "zod";
import { IModuleItem } from "../IModuleItem"; import { IModuleItem } from "../IModuleItem";
import { LocalQuizQuestion } from "./localQuizQuestion"; import { LocalQuizQuestion, zodLocalQuizQuestion } from "./localQuizQuestion";
import { quizMarkdownUtils } from "./utils/quizMarkdownUtils"; import { quizMarkdownUtils } from "./utils/quizMarkdownUtils";
export interface LocalQuiz extends IModuleItem { export interface LocalQuiz extends IModuleItem {
@@ -16,6 +17,20 @@ export interface LocalQuiz extends IModuleItem {
questions: LocalQuizQuestion[]; 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 = { export const localQuizMarkdownUtils = {
parseMarkdown: quizMarkdownUtils.parseMarkdown, parseMarkdown: quizMarkdownUtils.parseMarkdown,
toMarkdown: quizMarkdownUtils.toMarkdown, toMarkdown: quizMarkdownUtils.toMarkdown,

View File

@@ -1,12 +1,8 @@
import { LocalQuizQuestionAnswer } from "./localQuizQuestionAnswer"; import { z } from "zod";
import {
export interface LocalQuizQuestion { LocalQuizQuestionAnswer,
text: string; zodLocalQuizQuestionAnswer,
questionType: QuestionType; } from "./localQuizQuestionAnswer";
points: number;
answers: LocalQuizQuestionAnswer[];
matchDistractors: string[];
}
export enum QuestionType { export enum QuestionType {
MULTIPLE_ANSWERS = "multiple_answers", MULTIPLE_ANSWERS = "multiple_answers",
@@ -16,3 +12,27 @@ export enum QuestionType {
MATCHING = "matching", MATCHING = "matching",
NONE = "", 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 { export interface LocalQuizQuestionAnswer {
correct: boolean; correct: boolean;
text: string; text: string;
matchedText?: 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) => getPages: async (courseName: string, moduleName: string) =>
await courseItemFileStorageService.getItems(courseName, moduleName, "Page"), await courseItemFileStorageService.getItems(courseName, moduleName, "Page"),
async updatePage( async updatePage({
courseName: string, courseName,
moduleName: string, moduleName,
pageName: string, pageName,
page: LocalCoursePage page,
) { }: {
courseName: string;
moduleName: string;
pageName: string;
page: LocalCoursePage;
}) {
const folder = path.join(basePath, courseName, moduleName, "pages"); const folder = path.join(basePath, courseName, moduleName, "pages");
await fs.mkdir(folder, { recursive: true }); await fs.mkdir(folder, { recursive: true });

View File

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

View File

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

View File

@@ -45,7 +45,36 @@ export const assignmentRouter = router({
.mutation( .mutation(
async ({ async ({
input: { courseName, moduleName, assignmentName, assignment }, 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({ await fileStorageService.assignments.updateOrCreateAssignment({
courseName, courseName,
@@ -54,7 +83,31 @@ export const assignmentRouter = router({
assignment, 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,
});
}),
});