Files
canvasManagement/src/app/course/[courseName]/settings/HolidayConfig.tsx
2025-07-23 09:54:11 -06:00

165 lines
4.0 KiB
TypeScript

"use client";
import TextInput from "@/components/form/TextInput";
import { SuspenseAndErrorHandling } from "@/components/SuspenseAndErrorHandling";
import {
useLocalCourseSettingsQuery,
useUpdateLocalCourseSettingsMutation,
} from "@/features/local/course/localCoursesHooks";
import { getDateFromString } from "@/features/local/utils/timeUtils";
import { useEffect, useState } from "react";
import {
holidaysToString,
parseHolidays,
} from "../../../../features/local/utils/settingsUtils";
import { settingsBox } from "./sharedSettings";
const exampleString = `springBreak:
- 10/12/2024
- 10/13/2024
- 10/14/2024
laborDay:
- 9/1/2024`;
export const holidaysAreEqual = (
holidays1: {
name: string;
days: string[];
}[],
holidays2: {
name: string;
days: string[];
}[]
): boolean => {
if (holidays1.length !== holidays2.length) return false;
const sortedObj1 = [...holidays1].sort((a, b) =>
a.name.localeCompare(b.name)
);
const sortedObj2 = [...holidays2].sort((a, b) =>
a.name.localeCompare(b.name)
);
for (let i = 0; i < sortedObj1.length; i++) {
const holiday1 = sortedObj1[i];
const holiday2 = sortedObj2[i];
if (holiday1.name !== holiday2.name) return false;
const sortedDays1 = [...holiday1.days].sort();
const sortedDays2 = [...holiday2.days].sort();
if (sortedDays1.length !== sortedDays2.length) return false;
for (let j = 0; j < sortedDays1.length; j++) {
if (sortedDays1[j] !== sortedDays2[j]) return false;
}
}
return true;
};
export default function HolidayConfig() {
return (
<SuspenseAndErrorHandling>
<InnerHolidayConfig />
</SuspenseAndErrorHandling>
);
}
function InnerHolidayConfig() {
const { data: settings } = useLocalCourseSettingsQuery();
const updateSettings = useUpdateLocalCourseSettingsMutation();
const [rawText, setRawText] = useState(holidaysToString(settings.holidays));
useEffect(() => {
const id = setTimeout(() => {
try {
const parsed = parseHolidays(rawText);
if (!holidaysAreEqual(settings.holidays, parsed)) {
console.log("different holiday configs", settings.holidays, parsed);
updateSettings.mutate({
settings: {
...settings,
holidays: parsed,
},
});
}
} catch {}
}, 500);
return () => clearTimeout(id);
}, [rawText, settings.holidays, settings, updateSettings]);
return (
<div className={settingsBox}>
<div className="flex flex-row gap-3">
<TextInput
value={rawText}
setValue={setRawText}
label={"Holiday Days"}
isTextArea={true}
/>
<div>
Format your holidays like so:
<pre>
<code>{exampleString}</code>
</pre>
</div>
</div>
<div>
<SuspenseAndErrorHandling>
<ParsedHolidaysDisplay value={rawText} />
</SuspenseAndErrorHandling>
</div>
</div>
);
}
function ParsedHolidaysDisplay({ value }: { value: string }) {
const [parsedHolidays, setParsedHolidays] = useState<
{
name: string;
days: string[];
}[]
>([]);
const [error, setError] = useState("");
useEffect(() => {
try {
const parsed = parseHolidays(value);
setParsedHolidays(parsed);
setError("");
} catch (error) {
setError(error + "");
}
}, [value]);
return (
<div>
<div className="text-rose-500">{error}</div>
{parsedHolidays.map((holiday) => (
<div key={holiday.name}>
<div>{holiday.name}</div>
<div>
{holiday.days.map((day) => {
const date = getDateFromString(day);
return (
<div key={day}>
{date?.toLocaleDateString("en-us", {
weekday: "short",
year: "numeric",
month: "short",
day: "numeric",
})}
</div>
);
})}
</div>
</div>
))}
</div>
);
}