Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion components/form/CheckboxInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { InformationCircleIcon } from "@heroicons/react/24/outline";

interface CheckboxOption {
Expand All @@ -14,12 +14,18 @@ interface Props {
required?: boolean;
order: number;
info?: string;
checkedItems?: string[];
}

const CheckboxInput = (props: Props) => {
const [checkedItems, setCheckedItems] = useState<string[]>([]);
const [showInfo, setShowInfo] = useState(false);

useEffect(() => {
if (!props.checkedItems) return;
setCheckedItems(props.checkedItems);
}, [props.checkedItems]);

const handleInputChange = (e: React.BaseSyntheticEvent) => {
const value = e.target.value;
const isChecked = e.target.checked;
Expand Down
18 changes: 6 additions & 12 deletions components/form/DatePickerInput.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import { useEffect, useState } from "react";
interface Props {
label?: string;
fromDate?: string;
toDate?: string;
updateDates: (dates: { start: string; end: string }) => void;
}

const DatePickerInput = (props: Props) => {
const [fromDate, setFromDate] = useState("");
const [toDate, setToDate] = useState("");

useEffect(() => {
const startDate = fromDate ? `${fromDate}T00:00` : "";
const endDate = toDate ? `${toDate}T23:59` : "";
props.updateDates({ start: startDate, end: endDate });
}, [fromDate, toDate]);

return (
<div className="w-full max-w-xs mx-auto my-3 ">
Expand All @@ -24,17 +18,17 @@ const DatePickerInput = (props: Props) => {
type="date"
id={`${props.label}-from`}
name={`${props.label}-from`}
value={fromDate}
onChange={(e) => setFromDate(e.target.value)}
value={props.fromDate ?? ""}
onChange={(e) => props.updateDates({start: `${e.target.value}T00:00`, end: props.toDate ? `${props.toDate}T23:59` : ""})}
className="border text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 border-gray-300 text-gray-900 dark:border-gray-600 dark:bg-online-darkBlue dark:text-gray-200"
/>
<span className="mx-4 text-gray-500 dark:text-gray-300">til</span>
<input
type="date"
id={`${props.label}-to`}
name={`${props.label}-to`}
value={toDate}
onChange={(e) => setToDate(e.target.value)}
value={props.toDate ?? ""}
onChange={(e) => props.updateDates({start: props.fromDate ? `${props.fromDate}T00:00` : "", end: `${e.target.value}T23:59`})}
className="border text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 border-gray-300 text-gray-900 dark:border-gray-600 dark:bg-online-darkBlue dark:text-gray-200"
/>
</div>
Expand Down
8 changes: 8 additions & 0 deletions lib/api/committeesApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,11 @@ export const fetchCommitteeTimes = async (context: QueryFunctionContext) => {
res.json(),
);
};

export const fetchCommitteesByPeriodId = async (context: QueryFunctionContext) => {
const periodId = context.queryKey[1];

return fetch(`/api/committees/times/${periodId}`).then((res) =>
res.json(),
);
}
10 changes: 10 additions & 0 deletions lib/api/periodApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,13 @@ export const createPeriod = async (period: periodType) => {
},
});
};

export const editPeriod = async (updatedFields : Partial<periodType>) => {
return fetch(`/api/periods/${updatedFields._id}`, {
method: "PATCH",
body: JSON.stringify(updatedFields),
headers: {
"Content-Type": "application/json",
},
});
};
23 changes: 23 additions & 0 deletions lib/mongo/periods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,29 @@ export const deletePeriodById = async (periodId: string | ObjectId) => {
}
};

export const editPeriodById = async (
periodId: string | ObjectId,
updatedFields: Partial<periodType>
) => {
try {
if (!periods) await init();
delete updatedFields._id;

const result = await periods.updateOne(
{ _id: new ObjectId(periodId) },
{ $set: updatedFields }
);

if (result.matchedCount === 0) {
return { error: "Period not found" };
}

return { message: "Period updated successfully" };
} catch (error) {
return { error: "Failed to update period" };
}
};

export const markMatchedInterviewsByPeriodId = async (periodId: string) => {
try {
if (!periods) await init();
Expand Down
114 changes: 114 additions & 0 deletions lib/utils/validateEditedPeriod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { DeepPartial, periodType } from "../../lib/types/types";

export const validateChangedInterviewPeriod = (
changed: DeepPartial<periodType>,
applicantsData: any,
owCommitteesData: any
): boolean => {
let earliest = new Date(8640000000000000);
let latest = new Date(0);
for (const application of applicantsData.applications) {
if (earliest > new Date(application.selectedTimes[0].start)) {
earliest = new Date(application.selectedTimes[0].start);
}
if (latest < new Date(application.selectedTimes.at(-1).end)) {
latest = new Date(application.selectedTimes.at(-1).end);
}
}

if ((changed.interviewPeriod?.start && earliest < changed.interviewPeriod.start) || (changed.interviewPeriod?.end && latest > changed.interviewPeriod.end)) {
return window.confirm("Du har fjernet intervjutider som minst en søker har markert. Dette kan skape problemer. Er du sikker på at du vil fortsette?")
}

earliest = new Date(8640000000000000);
latest = new Date(0);
for (const committee of owCommitteesData.result) {
if (earliest > new Date(committee.availabletimes.at(0).start)) {
earliest = new Date(committee.availabletimes.at(0).start);
}
if (latest < new Date(committee.availabletimes.at(-1).end)) {
latest = new Date(committee.availabletimes.at(-1).end);
}
}

if ((changed.interviewPeriod?.start && earliest < changed.interviewPeriod.start) || (changed.interviewPeriod?.end && latest > changed.interviewPeriod.end)) {
return window.confirm("Du har fjernet intervjutider som minst en komite har markert. Dette kan skape problemer. Er du sikker på at du vil fortsette?")
}

return true;
}

export const validateChangedCommittees = (
original: periodType,
changed: DeepPartial<periodType>,
applicantsData: any
): boolean => {
const illegalRemovals: string[] = []
const removedLowerCase: string[] = [];
original.committees.map((committee) => {
if (!changed.committees?.includes(committee)) {
removedLowerCase.push(committee.toLowerCase());
}
})

for (const application of applicantsData.applications) {
if (removedLowerCase && application.preferences.first != '' && removedLowerCase.includes(application.preferences.first) && !illegalRemovals.includes(application.preferences.first)) {
illegalRemovals.push(application.preferences.first);
}
if (removedLowerCase && application.preferences.second != '' && removedLowerCase.includes(application.preferences.second) && !illegalRemovals.includes(application.preferences.second)) {
illegalRemovals.push(application.preferences.second);
}
if (removedLowerCase && application.preferences.third != '' && removedLowerCase.includes(application.preferences.third) && !illegalRemovals.includes(application.preferences.third)) {
illegalRemovals.push(application.preferences.third);
}
}

if (illegalRemovals.length > 0) {
const formattedCommittees = illegalRemovals
.map(c => c.charAt(0).toUpperCase() + c.slice(1))
.join("\n");

const confirmMessage =
"Følgende komiteer du har fjernet har minst en søker:\n" +
formattedCommittees +
"\n\nDette kan skape problemer. Ønsker du å fortsette?";

return window.confirm(confirmMessage);
}
return true;
}

export const validateChangedOptionalCommittees = (
original: periodType,
changed: DeepPartial<periodType>,
applicantsData: any
): boolean => {
const illegalRemovals: string[] = []
const removedLowerCase: string[] = [];
original.optionalCommittees.map((committee) => {
if (!changed.optionalCommittees?.includes(committee)) {
removedLowerCase.push(committee.toLowerCase());
}
});
for (const application of applicantsData.applications) {
for (const committee of application.optionalCommittees) {
if (removedLowerCase.includes(committee.toLowerCase()) && !illegalRemovals.includes(committee.toLowerCase())) {
illegalRemovals.push(committee.toLowerCase());
}
}
}

if (illegalRemovals.length > 0) {
const formattedCommittees = illegalRemovals
.map(c => c.charAt(0).toUpperCase() + c.slice(1))
.join("\n");

const confirmMessage =
"Følgende valgfrie komiteer du har fjernet har minst en søker:\n" +
formattedCommittees +
"\n\nDette kan skape problemer. Ønsker du å fortsette?";

return window.confirm(confirmMessage);
}
return true;
}
10 changes: 9 additions & 1 deletion pages/admin/[period-id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import { periodType } from "../../../lib/types/types";
import NotFound from "../../404";
import ApplicantsOverview from "../../../components/applicantoverview/ApplicantsOverview";
import { Tabs } from "../../../components/Tabs";
import { CalendarIcon, InboxIcon } from "@heroicons/react/24/solid";
import { CalendarIcon, CogIcon, InboxIcon } from "@heroicons/react/24/solid";
import Button from "../../../components/Button";
import { useQuery } from "@tanstack/react-query";
import { fetchPeriodById } from "../../../lib/api/periodApi";
import LoadingPage from "../../../components/LoadingPage";
import ErrorPage from "../../../components/ErrorPage";
import toast from "react-hot-toast";
import PeriodSettings from "../period-settings";

const Admin = () => {
const { data: session } = useSession();
Expand Down Expand Up @@ -119,6 +120,13 @@ const Admin = () => {
/>
),
},
{
title: "Instillinger",
icon: <CogIcon className="w-5 h-5" />,
content: (
<PeriodSettings period={period}/>
)
},
//Super admin :)
...(session?.user?.email &&
[
Expand Down
2 changes: 1 addition & 1 deletion pages/admin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const Admin = () => {
<Button
title="Ny opptaksperiode"
color="blue"
href="/admin/new-period"
href="/admin/period-settings"
/>
</div>

Expand Down
Loading