mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
sort module button
This commit is contained in:
@@ -15,6 +15,8 @@ export default function CourseList() {
|
||||
|
||||
const sortedDates = Object.keys(coursesByStartDate).sort();
|
||||
|
||||
console.log(allSettings, coursesByStartDate);
|
||||
|
||||
return (
|
||||
<div className="flex flex-row ">
|
||||
{sortedDates.map((startDate) => (
|
||||
@@ -29,10 +31,10 @@ export default function CourseList() {
|
||||
href={getCourseUrl(settings.name)}
|
||||
shallow={true}
|
||||
className="
|
||||
font-bold text-xl block
|
||||
transition-all hover:scale-105 hover:underline hover:text-slate-200
|
||||
mb-3
|
||||
"
|
||||
font-bold text-xl block
|
||||
transition-all hover:scale-105 hover:underline hover:text-slate-200
|
||||
mb-3
|
||||
"
|
||||
>
|
||||
{settings.name}
|
||||
</Link>
|
||||
|
||||
@@ -25,6 +25,9 @@ import { useQuizzesQueries } from "@/features/local/quizzes/quizHooks";
|
||||
import { useTRPC } from "@/services/serverFunctions/trpcClient";
|
||||
import { useSuspenseQueries } from "@tanstack/react-query";
|
||||
import { useAssignmentNamesQuery } from "@/features/local/assignments/assignmentHooks";
|
||||
import { useReorderCanvasModuleItemsMutation } from "@/features/canvas/hooks/canvasModuleHooks";
|
||||
import { useCanvasModulesQuery } from "@/features/canvas/hooks/canvasModuleHooks";
|
||||
import { Spinner } from "@/components/Spinner";
|
||||
|
||||
export default function ExpandableModule({
|
||||
moduleName,
|
||||
@@ -50,6 +53,8 @@ export default function ExpandableModule({
|
||||
const { data: quizzes } = useQuizzesQueries(moduleName);
|
||||
const { data: pages } = usePagesQueries(moduleName);
|
||||
const modal = useModal();
|
||||
const reorderMutation = useReorderCanvasModuleItemsMutation();
|
||||
const { data: canvasModules } = useCanvasModulesQuery();
|
||||
|
||||
const moduleItems: {
|
||||
type: "assignment" | "quiz" | "page";
|
||||
@@ -110,6 +115,30 @@ export default function ExpandableModule({
|
||||
)}
|
||||
>
|
||||
<>
|
||||
{!reorderMutation.isPending && (
|
||||
<button
|
||||
className=" me-3"
|
||||
onClick={() => {
|
||||
const canvasModuleId = canvasModules?.find(
|
||||
(m) => m.name === moduleName
|
||||
)?.id;
|
||||
if (!canvasModuleId) {
|
||||
console.error(
|
||||
"Canvas module ID not found for",
|
||||
moduleName
|
||||
);
|
||||
return;
|
||||
}
|
||||
reorderMutation.mutate({
|
||||
moduleId: canvasModuleId,
|
||||
items: moduleItems.map((item) => item.item),
|
||||
});
|
||||
}}
|
||||
>
|
||||
Sort by Due Date
|
||||
</button>
|
||||
)}
|
||||
{reorderMutation.isPending && <Spinner />}
|
||||
<Modal
|
||||
modalControl={modal}
|
||||
buttonText="New Item"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { CanvasModuleItem } from "@/features/canvas/models/modules/canvasModuleItems";
|
||||
import { useLocalCourseSettingsQuery } from "@/features/local/course/localCoursesHooks";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { canvasModuleService } from "../services/canvasModuleService";
|
||||
import { IModuleItem } from "@/features/local/modules/IModuleItem";
|
||||
|
||||
export const canvasCourseModuleKeys = {
|
||||
modules: (canvasId: number) => ["canvas", canvasId, "module list"] as const,
|
||||
@@ -28,3 +30,54 @@ export const useAddCanvasModuleMutation = () => {
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useReorderCanvasModuleItemsMutation = () => {
|
||||
const { data: settings } = useLocalCourseSettingsQuery();
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
moduleId,
|
||||
items,
|
||||
}: {
|
||||
moduleId: number;
|
||||
items: IModuleItem[];
|
||||
}) => {
|
||||
if (!settings?.canvasId) throw new Error("No canvasId in settings");
|
||||
|
||||
const canvasModule = await canvasModuleService.getModuleWithItems(
|
||||
settings.canvasId,
|
||||
moduleId
|
||||
);
|
||||
if (!canvasModule.items) {
|
||||
throw new Error(
|
||||
"cannot sort canvas module items, no items found in module"
|
||||
);
|
||||
}
|
||||
const canvasItems = canvasModule.items;
|
||||
|
||||
// Sort IModuleItems by dueAt
|
||||
const sorted = [...items].sort((a, b) => {
|
||||
const aDate = a.dueAt ? new Date(a.dueAt).getTime() : 0;
|
||||
const bDate = b.dueAt ? new Date(b.dueAt).getTime() : 0;
|
||||
return aDate - bDate;
|
||||
});
|
||||
|
||||
// Map sorted IModuleItems to CanvasModuleItem ids by matching name/title
|
||||
const orderedIds = sorted
|
||||
.map((localItem) => canvasItems.find((canvasItem) => canvasItem.title === localItem.name)?.id)
|
||||
.filter((id): id is number => typeof id === "number");
|
||||
|
||||
return await canvasModuleService.reorderModuleItems(
|
||||
settings.canvasId,
|
||||
moduleId,
|
||||
orderedIds
|
||||
);
|
||||
},
|
||||
onSuccess: (_data) => {
|
||||
if (!settings?.canvasId) return;
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: canvasCourseModuleKeys.modules(settings.canvasId),
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -20,6 +20,13 @@ export const canvasModuleService = {
|
||||
if (!data) throw new Error("Something went wrong updating module item");
|
||||
},
|
||||
|
||||
async getModuleWithItems(canvasCourseId: number, moduleId: number) {
|
||||
const url = `${canvasApi}/courses/${canvasCourseId}/modules/${moduleId}`;
|
||||
const params = { include: ["items"] };
|
||||
const response = await axiosClient.get<CanvasModule>(url, { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async createModuleItem(
|
||||
canvasCourseId: number,
|
||||
canvasModuleId: number,
|
||||
@@ -63,4 +70,21 @@ export const canvasModuleService = {
|
||||
const response = await axiosClient.post<CanvasModule>(url, body);
|
||||
return response.data.id;
|
||||
},
|
||||
|
||||
async reorderModuleItems(
|
||||
canvasCourseId: number,
|
||||
canvasModuleId: number,
|
||||
itemIds: number[]
|
||||
) {
|
||||
for (let i = 0; i < itemIds.length; i++) {
|
||||
const itemId = itemIds[i];
|
||||
const url = `${canvasApi}/courses/${canvasCourseId}/modules/${canvasModuleId}/items/${itemId}`;
|
||||
const body = {
|
||||
module_item: {
|
||||
position: i + 1,
|
||||
},
|
||||
};
|
||||
await axiosClient.put(url, body);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ import { GlobalSettingsCourse } from "../globalSettings/globalSettingsModels";
|
||||
const getCourseSettings = async (
|
||||
course: GlobalSettingsCourse
|
||||
): Promise<LocalCourseSettings> => {
|
||||
const courseDirectory = await getCoursePathByName(course.name);
|
||||
const courseDirectory = path.join(basePath, course.path);
|
||||
const settingsPath = path.join(courseDirectory, "settings.yml");
|
||||
if (!(await directoryOrFileExists(settingsPath))) {
|
||||
const errorMessage = `could not find settings for ${course.name}, settings file ${settingsPath}`;
|
||||
|
||||
Reference in New Issue
Block a user