more refactoring by feature

This commit is contained in:
2025-07-23 09:46:35 -06:00
parent d5a40e52d9
commit 3e371247d6
92 changed files with 159 additions and 158 deletions

View File

@@ -1,7 +1,7 @@
import { z } from "zod";
import { LocalQuizQuestion, zodLocalQuizQuestion } from "./localQuizQuestion";
import { quizMarkdownUtils } from "./utils/quizMarkdownUtils";
import { IModuleItem } from "@/models/local/IModuleItem";
import { IModuleItem } from "@/features/local/modules/IModuleItem";
export interface LocalQuiz extends IModuleItem {
name: string;

View File

@@ -0,0 +1,63 @@
import path from "path";
import { promises as fs } from "fs";
import { courseItemFileStorageService } from "../course/courseItemFileStorageService";
import { getCoursePathByName } from "../../../services/fileStorage/globalSettingsFileStorageService";
import { LocalQuiz } from "@/features/local/quizzes/models/localQuiz";
import { quizMarkdownUtils } from "@/features/local/quizzes/models/utils/quizMarkdownUtils";
export const quizFileStorageService = {
getQuiz: async (courseName: string, moduleName: string, quizName: string) =>
await courseItemFileStorageService.getItem(
courseName,
moduleName,
quizName,
"Quiz"
),
getQuizzes: async (courseName: string, moduleName: string) =>
await courseItemFileStorageService.getItems(courseName, moduleName, "Quiz"),
async updateQuiz({
courseName,
moduleName,
quizName,
quiz,
}: {
courseName: string;
moduleName: string;
quizName: string;
quiz: LocalQuiz;
}) {
const courseDirectory = await getCoursePathByName(courseName);
const folder = path.join(courseDirectory, moduleName, "quizzes");
await fs.mkdir(folder, { recursive: true });
const filePath = path.join(
courseDirectory,
moduleName,
"quizzes",
quizName + ".md"
);
const quizMarkdown = quizMarkdownUtils.toMarkdown(quiz);
console.log(`Saving quiz ${filePath}`);
await fs.writeFile(filePath, quizMarkdown);
},
async delete({
courseName,
moduleName,
quizName,
}: {
courseName: string;
moduleName: string;
quizName: string;
}) {
const courseDirectory = await getCoursePathByName(courseName);
const filePath = path.join(
courseDirectory,
moduleName,
"quizzes",
quizName + ".md"
);
console.log("removing quiz", filePath);
await fs.unlink(filePath);
},
};

View File

@@ -0,0 +1,107 @@
"use client";
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
import { useTRPC } from "@/services/serverFunctions/trpcClient";
import {
useSuspenseQuery,
useMutation,
useQueryClient,
} from "@tanstack/react-query";
export const useQuizQuery = (moduleName: string, quizName: string) => {
const { courseName } = useCourseContext();
const trpc = useTRPC();
return useSuspenseQuery(
trpc.quiz.getQuiz.queryOptions({
courseName,
moduleName,
quizName,
})
);
};
export const useQuizzesQueries = (moduleName: string) => {
const { courseName } = useCourseContext();
const trpc = useTRPC();
return useSuspenseQuery(
trpc.quiz.getAllQuizzes.queryOptions({
courseName,
moduleName,
})
);
};
export const useUpdateQuizMutation = () => {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation(
trpc.quiz.updateQuiz.mutationOptions({
onSuccess: (
_,
{ courseName, moduleName, quizName, previousModuleName }
) => {
if (moduleName !== previousModuleName) {
queryClient.invalidateQueries({
queryKey: trpc.quiz.getAllQuizzes.queryKey({
courseName,
moduleName: previousModuleName,
}),
});
}
queryClient.invalidateQueries({
queryKey: trpc.quiz.getAllQuizzes.queryKey({
courseName,
moduleName,
}),
});
queryClient.invalidateQueries({
queryKey: trpc.quiz.getQuiz.queryKey({
courseName,
moduleName,
quizName,
}),
});
},
})
);
};
export const useCreateQuizMutation = () => {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation(
trpc.quiz.createQuiz.mutationOptions({
onSuccess: (_, { courseName, moduleName }) => {
queryClient.invalidateQueries({
queryKey: trpc.quiz.getAllQuizzes.queryKey({
courseName,
moduleName,
}),
});
},
})
);
};
export const useDeleteQuizMutation = () => {
const trpc = useTRPC();
const queryClient = useQueryClient();
return useMutation(
trpc.quiz.deleteQuiz.mutationOptions({
onSuccess: (_, { courseName, moduleName, quizName }) => {
queryClient.invalidateQueries({
queryKey: trpc.quiz.getAllQuizzes.queryKey({
courseName,
moduleName,
}),
});
queryClient.invalidateQueries({
queryKey: trpc.quiz.getQuiz.queryKey({
courseName,
moduleName,
quizName,
}),
});
},
})
);
};

View File

@@ -0,0 +1,110 @@
import publicProcedure from "../../../services/serverFunctions/procedures/public";
import { z } from "zod";
import { router } from "../../../services/serverFunctions/trpcSetup";
import { fileStorageService } from "@/services/fileStorage/fileStorageService";
import { zodLocalQuiz } from "@/features/local/quizzes/models/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 (
quizName !== previousQuizName ||
moduleName !== previousModuleName
) {
await 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,
});
}),
});