mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-26 23:58:31 -06:00
more configs for default types
This commit is contained in:
@@ -30,24 +30,32 @@ function createCalendarMonth(year: number, month: number): CalendarMonthModel {
|
|||||||
let currentDay = 1;
|
let currentDay = 1;
|
||||||
const firstDayOfMonth = new Date(year, month - 1, 1).getDay();
|
const firstDayOfMonth = new Date(year, month - 1, 1).getDay();
|
||||||
|
|
||||||
const daysByWeek = Array.from({ length: weeksNumber }).map((_, weekIndex) =>
|
const daysByWeek = Array.from({ length: weeksNumber })
|
||||||
Array.from({ length: 7 }).map((_, dayIndex) => {
|
.map((_, weekIndex) =>
|
||||||
if (weekIndex === 0 && dayIndex < firstDayOfMonth) {
|
Array.from({ length: 7 }).map((_, dayIndex) => {
|
||||||
return dateToMarkdownString(
|
if (weekIndex === 0 && dayIndex < firstDayOfMonth) {
|
||||||
new Date(year, month - 1, dayIndex - firstDayOfMonth + 1, 12, 0, 0)
|
return dateToMarkdownString(
|
||||||
);
|
new Date(year, month - 1, dayIndex - firstDayOfMonth + 1, 12, 0, 0)
|
||||||
} else if (currentDay <= daysInMonth) {
|
);
|
||||||
return dateToMarkdownString(
|
} else if (currentDay <= daysInMonth) {
|
||||||
new Date(year, month - 1, currentDay++, 12, 0, 0)
|
return dateToMarkdownString(
|
||||||
);
|
new Date(year, month - 1, currentDay++, 12, 0, 0)
|
||||||
} else {
|
);
|
||||||
currentDay++;
|
} else {
|
||||||
return dateToMarkdownString(
|
currentDay++;
|
||||||
new Date(year, month, currentDay - daysInMonth - 1, 12, 0, 0)
|
return dateToMarkdownString(
|
||||||
);
|
new Date(year, month, currentDay - daysInMonth - 1, 12, 0, 0)
|
||||||
}
|
);
|
||||||
})
|
}
|
||||||
);
|
})
|
||||||
|
)
|
||||||
|
.filter((week) => {
|
||||||
|
const lastDate = getDateFromStringOrThrow(
|
||||||
|
week.at(-1)!,
|
||||||
|
"filtering out last week of month"
|
||||||
|
);
|
||||||
|
return lastDate.getMonth() <= month - 1;
|
||||||
|
});
|
||||||
|
|
||||||
const weeks = daysByWeek.map((week) =>
|
const weeks = daysByWeek.map((week) =>
|
||||||
week.map((day) =>
|
week.map((day) =>
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ export default function EditAssignment({
|
|||||||
const [assignmentText, setAssignmentText] = useState(
|
const [assignmentText, setAssignmentText] = useState(
|
||||||
localAssignmentMarkdown.toMarkdown(assignment)
|
localAssignmentMarkdown.toMarkdown(assignment)
|
||||||
);
|
);
|
||||||
console.log("assignment text render");
|
|
||||||
|
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [showHelp, setShowHelp] = useState(false);
|
const [showHelp, setShowHelp] = useState(false);
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ export default function QuizPreview({
|
|||||||
<div className="text-end">Name</div>
|
<div className="text-end">Name</div>
|
||||||
<div>{quiz.name}</div>
|
<div>{quiz.name}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="columns-2">
|
||||||
|
<div className="text-end">Points</div>
|
||||||
|
<div>
|
||||||
|
{quiz.questions.reduce((sum, question) => sum + question.points, 0)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="columns-2">
|
<div className="columns-2">
|
||||||
<div className="text-end">Due Date</div>
|
<div className="text-end">Due Date</div>
|
||||||
<div>{quiz.dueAt}</div>
|
<div>{quiz.dueAt}</div>
|
||||||
@@ -46,9 +52,12 @@ export default function QuizPreview({
|
|||||||
<div className="text-end">Assignment Group Name</div>
|
<div className="text-end">Assignment Group Name</div>
|
||||||
<div>{quiz.localAssignmentGroupName}</div>
|
<div>{quiz.localAssignmentGroupName}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-3" style={{ whiteSpace: "pre-wrap" }}>
|
<div
|
||||||
{quiz.description}
|
className="p-3 markdownPreview"
|
||||||
</div>
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: markdownToHTMLSafe(quiz.description),
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
<div className="p-3 rounded-md bg-slate-950 m-5 flex flex-col gap-3">
|
<div className="p-3 rounded-md bg-slate-950 m-5 flex flex-col gap-3">
|
||||||
{quiz.questions.map((question, i) => (
|
{quiz.questions.map((question, i) => (
|
||||||
<QuizQuestionPreview key={i} question={question} />
|
<QuizQuestionPreview key={i} question={question} />
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export default function AssignmentGroupManagement() {
|
|||||||
<button
|
<button
|
||||||
className="btn-danger"
|
className="btn-danger"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setAssignmentGroups((oldGroups) => oldGroups.slice(1));
|
setAssignmentGroups((oldGroups) => oldGroups.slice(0, -1));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Remove Assignment Group
|
Remove Assignment Group
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
"use client";
|
||||||
|
import TextInput from "@/components/form/TextInput";
|
||||||
|
import {
|
||||||
|
useLocalCourseSettingsQuery,
|
||||||
|
useUpdateLocalCourseSettingsMutation,
|
||||||
|
} from "@/hooks/localCourse/localCoursesHooks";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
export default function DefaultFileUploadTypes() {
|
||||||
|
const { data: settings } = useLocalCourseSettingsQuery();
|
||||||
|
const [defaultFileUploadTypes, setDefaultFileUploadTypes] = useState<
|
||||||
|
string[]
|
||||||
|
>(settings.defaultFileUploadTypes);
|
||||||
|
const updateSettings = useUpdateLocalCourseSettingsMutation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const id = setTimeout(() => {
|
||||||
|
if (
|
||||||
|
JSON.stringify(settings.defaultFileUploadTypes) !==
|
||||||
|
JSON.stringify(defaultFileUploadTypes)
|
||||||
|
) {
|
||||||
|
updateSettings.mutate({
|
||||||
|
...settings,
|
||||||
|
defaultFileUploadTypes: defaultFileUploadTypes,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
return () => clearTimeout(id);
|
||||||
|
}, [defaultFileUploadTypes, settings, updateSettings]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="border w-fit p-3 m-3 rounded-md">
|
||||||
|
<div className="text-center">Default File Upload Types</div>
|
||||||
|
|
||||||
|
{defaultFileUploadTypes.map((type, index) => (
|
||||||
|
<div key={index} className="flex flex-row gap-3">
|
||||||
|
<TextInput
|
||||||
|
value={type}
|
||||||
|
setValue={(newValue) =>
|
||||||
|
setDefaultFileUploadTypes((oldTypes) =>
|
||||||
|
oldTypes.map((t, i) => (i === index ? newValue : t))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
label={"Default Type " + index}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div className="flex gap-3 mt-3">
|
||||||
|
<button
|
||||||
|
className="btn-danger"
|
||||||
|
onClick={() => {
|
||||||
|
setDefaultFileUploadTypes((old) => old.slice(0, -1));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remove Default File Upload Type
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setDefaultFileUploadTypes((old) => [...old, ""])}
|
||||||
|
>
|
||||||
|
Add Default File Upload Type
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
"use client";
|
||||||
|
import SelectInput from "@/components/form/SelectInput";
|
||||||
|
import {
|
||||||
|
useLocalCourseSettingsQuery,
|
||||||
|
useUpdateLocalCourseSettingsMutation,
|
||||||
|
} from "@/hooks/localCourse/localCoursesHooks";
|
||||||
|
import {
|
||||||
|
AssignmentSubmissionType,
|
||||||
|
AssignmentSubmissionTypeList,
|
||||||
|
} from "@/models/local/assignment/assignmentSubmissionType";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export default function SubmissionDefaults() {
|
||||||
|
const { data: settings } = useLocalCourseSettingsQuery();
|
||||||
|
const [defaultSubmissionTypes, setDefaultSubmissionTypes] = useState<
|
||||||
|
AssignmentSubmissionType[]
|
||||||
|
>(settings.defaultAssignmentSubmissionTypes);
|
||||||
|
const updateSettings = useUpdateLocalCourseSettingsMutation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
JSON.stringify(settings.defaultAssignmentSubmissionTypes) !==
|
||||||
|
JSON.stringify(defaultSubmissionTypes)
|
||||||
|
) {
|
||||||
|
updateSettings.mutate({
|
||||||
|
...settings,
|
||||||
|
defaultAssignmentSubmissionTypes: defaultSubmissionTypes,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [defaultSubmissionTypes, settings, updateSettings]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="border w-fit p-3 m-3 rounded-md">
|
||||||
|
<div className="text-center">Default Assignment Submission Type</div>
|
||||||
|
|
||||||
|
{defaultSubmissionTypes.map((type, index) => (
|
||||||
|
<div key={index} className="flex flex-row gap-3">
|
||||||
|
<SelectInput
|
||||||
|
value={type}
|
||||||
|
setValue={(newType) => {
|
||||||
|
if (newType)
|
||||||
|
setDefaultSubmissionTypes((oldTypes) =>
|
||||||
|
oldTypes.map((t, i) => (i === index ? newType : t))
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
label={""}
|
||||||
|
options={AssignmentSubmissionTypeList}
|
||||||
|
getOptionName={(t) => t}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div className="flex gap-3 mt-3">
|
||||||
|
<button
|
||||||
|
className="btn-danger"
|
||||||
|
onClick={() => {
|
||||||
|
setDefaultSubmissionTypes((old) => old.slice(0, -1));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remove Default Type
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
setDefaultSubmissionTypes((old) => [
|
||||||
|
...old,
|
||||||
|
AssignmentSubmissionType.NONE,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Add Default Type
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ import SettingsHeader from "./SettingsHeader";
|
|||||||
import DefaultDueTime from "./DefaultDueTime";
|
import DefaultDueTime from "./DefaultDueTime";
|
||||||
import DaysOfWeekSettings from "./DaysOfWeekSettings";
|
import DaysOfWeekSettings from "./DaysOfWeekSettings";
|
||||||
import AssignmentGroupManagement from "./AssignmentGroupManagement";
|
import AssignmentGroupManagement from "./AssignmentGroupManagement";
|
||||||
|
import SubmissionDefaults from "./SubmissionDefaults";
|
||||||
|
import DefaultFileUploadTypes from "./DefaultFileUploadTypes";
|
||||||
|
|
||||||
export default function page() {
|
export default function page() {
|
||||||
return (
|
return (
|
||||||
@@ -13,6 +15,8 @@ export default function page() {
|
|||||||
<SettingsHeader />
|
<SettingsHeader />
|
||||||
<DaysOfWeekSettings />
|
<DaysOfWeekSettings />
|
||||||
<StartAndEndDate />
|
<StartAndEndDate />
|
||||||
|
<SubmissionDefaults />
|
||||||
|
<DefaultFileUploadTypes />
|
||||||
<DefaultDueTime />
|
<DefaultDueTime />
|
||||||
<AssignmentGroupManagement />
|
<AssignmentGroupManagement />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
import { useEmptyDirectoriesQuery } from "@/hooks/localCourse/storageDirectoryHooks";
|
import { useEmptyDirectoriesQuery } from "@/hooks/localCourse/storageDirectoryHooks";
|
||||||
import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel";
|
import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel";
|
||||||
import { CanvasEnrollmentTermModel } from "@/models/canvas/enrollmentTerms/canvasEnrollmentTermModel";
|
import { CanvasEnrollmentTermModel } from "@/models/canvas/enrollmentTerms/canvasEnrollmentTermModel";
|
||||||
|
import { AssignmentSubmissionType } from "@/models/local/assignment/assignmentSubmissionType";
|
||||||
import { DayOfWeek } from "@/models/local/localCourse";
|
import { DayOfWeek } from "@/models/local/localCourse";
|
||||||
import { getCourseUrl } from "@/services/urlUtils";
|
import { getCourseUrl } from "@/services/urlUtils";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
@@ -89,6 +90,10 @@ export default function NewCourseForm() {
|
|||||||
startDate: selectedTerm.start_at ?? "",
|
startDate: selectedTerm.start_at ?? "",
|
||||||
endDate: selectedTerm.end_at ?? "",
|
endDate: selectedTerm.end_at ?? "",
|
||||||
defaultDueTime: { hour: 23, minute: 59 },
|
defaultDueTime: { hour: 23, minute: 59 },
|
||||||
|
defaultAssignmentSubmissionTypes: [
|
||||||
|
AssignmentSubmissionType.ONLINE_TEXT_ENTRY,
|
||||||
|
AssignmentSubmissionType.ONLINE_UPLOAD,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ export function DayOfWeekInput({
|
|||||||
key={day}
|
key={day}
|
||||||
className={
|
className={
|
||||||
hasDay
|
hasDay
|
||||||
? "bg-blue-300 text-blue-950 border-blue-500 border"
|
? ""
|
||||||
: "bg-slate-900 border-blue-900 border "
|
: "unstyled btn-outline "
|
||||||
}
|
}
|
||||||
onClick={() => updateSettings(day)}
|
onClick={() => updateSettings(day)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -6,3 +6,12 @@ export enum AssignmentSubmissionType {
|
|||||||
ONLINE_URL = "online_url",
|
ONLINE_URL = "online_url",
|
||||||
NONE = "none",
|
NONE = "none",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const AssignmentSubmissionTypeList: AssignmentSubmissionType[] = [
|
||||||
|
AssignmentSubmissionType.ONLINE_TEXT_ENTRY,
|
||||||
|
AssignmentSubmissionType.ONLINE_UPLOAD,
|
||||||
|
AssignmentSubmissionType.ONLINE_QUIZ,
|
||||||
|
AssignmentSubmissionType.DISCUSSION_TOPIC,
|
||||||
|
AssignmentSubmissionType.ONLINE_URL,
|
||||||
|
AssignmentSubmissionType.NONE,
|
||||||
|
] as const;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { AssignmentSubmissionType } from "./assignment/assignmentSubmissionType";
|
||||||
import { LocalAssignmentGroup } from "./assignment/localAssignmentGroup";
|
import { LocalAssignmentGroup } from "./assignment/localAssignmentGroup";
|
||||||
import { LocalModule } from "./localModules";
|
import { LocalModule } from "./localModules";
|
||||||
import { parse, stringify } from "yaml";
|
import { parse, stringify } from "yaml";
|
||||||
@@ -20,6 +21,8 @@ export interface LocalCourseSettings {
|
|||||||
startDate: string;
|
startDate: string;
|
||||||
endDate: string;
|
endDate: string;
|
||||||
defaultDueTime: SimpleTimeOnly;
|
defaultDueTime: SimpleTimeOnly;
|
||||||
|
defaultAssignmentSubmissionTypes: AssignmentSubmissionType[];
|
||||||
|
defaultFileUploadTypes: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DayOfWeek {
|
export enum DayOfWeek {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
directoryOrFileExists,
|
directoryOrFileExists,
|
||||||
getCourseNames,
|
getCourseNames,
|
||||||
} from "./utils/fileSystemUtils";
|
} from "./utils/fileSystemUtils";
|
||||||
|
import { AssignmentSubmissionType } from "@/models/local/assignment/assignmentSubmissionType";
|
||||||
|
|
||||||
const getCourseSettings = async (
|
const getCourseSettings = async (
|
||||||
courseName: string
|
courseName: string
|
||||||
@@ -22,7 +23,24 @@ const getCourseSettings = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const settingsString = await fs.readFile(settingsPath, "utf-8");
|
const settingsString = await fs.readFile(settingsPath, "utf-8");
|
||||||
const settings = localCourseYamlUtils.parseSettingYaml(settingsString);
|
|
||||||
|
const settingsFromFile =
|
||||||
|
localCourseYamlUtils.parseSettingYaml(settingsString);
|
||||||
|
|
||||||
|
const defaultSubmissionType = [
|
||||||
|
AssignmentSubmissionType.ONLINE_TEXT_ENTRY,
|
||||||
|
AssignmentSubmissionType.ONLINE_UPLOAD,
|
||||||
|
];
|
||||||
|
const defaultFileUploadTypes = ["pdf", "jpg", "jpeg", "pdf"];
|
||||||
|
|
||||||
|
const settings: LocalCourseSettings = {
|
||||||
|
...settingsFromFile,
|
||||||
|
defaultAssignmentSubmissionTypes:
|
||||||
|
settingsFromFile.defaultAssignmentSubmissionTypes ||
|
||||||
|
defaultSubmissionType,
|
||||||
|
defaultFileUploadTypes:
|
||||||
|
settingsFromFile.defaultFileUploadTypes || defaultFileUploadTypes,
|
||||||
|
};
|
||||||
|
|
||||||
const folderName = path.basename(courseDirectory);
|
const folderName = path.basename(courseDirectory);
|
||||||
return { ...settings, name: folderName };
|
return { ...settings, name: folderName };
|
||||||
@@ -54,4 +72,3 @@ export const settingsFileStorageService = {
|
|||||||
await fs.writeFile(settingsPath, settingsMarkdown);
|
await fs.writeFile(settingsPath, settingsMarkdown);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user