Sith/counter/static/webpack/graph-index.ts

134 lines
4.0 KiB
TypeScript
Raw Normal View History

2024-10-13 23:42:38 +00:00
import { paginated } from "#core:utils/api";
import { exportToHtml } from "#core:utils/globals";
2024-10-15 19:41:18 +00:00
import { Calendar } from "@fullcalendar/core";
import timeGridPlugin from "@fullcalendar/timegrid";
2024-10-13 23:42:38 +00:00
import {
type PermanencyFetchPermananciesData,
2024-10-15 16:33:25 +00:00
type PermanencySchema,
2024-10-13 23:42:38 +00:00
permanencyFetchPermanancies,
} from "#openapi";
2024-10-12 15:30:19 +00:00
2024-10-13 23:42:38 +00:00
interface ActivityChartConfig {
canvas: HTMLCanvasElement;
startDate: Date;
counterId: number;
}
2024-10-15 16:33:25 +00:00
interface OpeningTime {
start: Date;
end: Date;
}
2024-10-13 23:42:38 +00:00
2024-10-15 19:41:18 +00:00
interface EventInput {
start: Date;
end: Date;
backgroundColor: string;
}
2024-10-16 20:43:05 +00:00
// TODO: Semaines passées
2024-10-20 13:53:02 +00:00
// TODO: Manage locales
2024-10-15 19:41:18 +00:00
2024-10-13 23:42:38 +00:00
exportToHtml("loadChart", loadChart);
async function loadChart(options: ActivityChartConfig) {
2024-10-15 16:33:25 +00:00
const permanancies = await paginated(permanencyFetchPermanancies, {
2024-10-13 23:42:38 +00:00
query: {
counter: [options.counterId],
// biome-ignore lint/style/useNamingConvention: backend API uses snake_case
2024-10-20 13:53:02 +00:00
end_after: options.startDate.toISOString(),
2024-10-13 23:42:38 +00:00
},
2024-10-15 16:33:25 +00:00
} as PermanencyFetchPermananciesData);
const events = getEvents(permanancies);
const calendar = new Calendar(options.canvas, {
plugins: [timeGridPlugin],
initialView: "timeGridWeek",
locale: "fr",
2024-10-15 19:41:18 +00:00
slotLabelFormat: { hour: "2-digit", minute: "2-digit", hour12: false },
dayHeaderFormat: { weekday: "long" },
2024-10-15 16:33:25 +00:00
firstDay: 1,
2024-10-15 19:41:18 +00:00
views: { timeGrid: { allDaySlot: false } },
2024-10-15 16:33:25 +00:00
scrollTime: "09:00:00",
2024-10-15 19:41:18 +00:00
headerToolbar: { left: "", center: "", right: "" },
2024-10-15 16:33:25 +00:00
events: events,
nowIndicator: true,
height: 600,
2024-10-13 23:42:38 +00:00
});
2024-10-15 16:33:25 +00:00
calendar.render();
2024-10-12 15:30:19 +00:00
}
2024-10-16 20:43:05 +00:00
function roundToQuarter(date: Date, ceil: boolean) {
const result = date;
const minutes = date.getMinutes();
// removes minutes exceeding the lower quarter and adds 15 minutes if rounded to ceiling
result.setMinutes(minutes + +ceil * 15 - (minutes % 15), 0, 0);
return result;
}
function convertPermanancyToOpeningTime(permanancy: PermanencySchema): OpeningTime {
return {
start: roundToQuarter(new Date(permanancy.start), false),
end: roundToQuarter(new Date(permanancy.end ?? Date.now()), true),
};
}
2024-10-15 16:33:25 +00:00
function getOpeningTimes(rawPermanancies: PermanencySchema[]) {
const permanancies = rawPermanancies
.map(convertPermanancyToOpeningTime)
.sort((a, b) => a.start.getTime() - b.start.getTime());
const openingTimes: OpeningTime[] = [];
for (const permanancy of permanancies) {
// if there are no opening times, add the first one
if (openingTimes.length === 0) {
openingTimes.push(permanancy);
} else {
const lastPermanancy = openingTimes[openingTimes.length - 1];
2024-10-15 19:41:18 +00:00
// if the new permanancy starts before the 15 minutes following the end of the last one, merge them
2024-10-16 20:43:05 +00:00
if (permanancy.start <= lastPermanancy.end) {
2024-10-15 16:33:25 +00:00
lastPermanancy.end = new Date(
Math.max(lastPermanancy.end.getTime(), permanancy.end.getTime()),
);
} else {
openingTimes.push(permanancy);
}
}
}
return openingTimes;
}
function getEvents(permanancies: PermanencySchema[]) {
const openingTimes = getOpeningTimes(permanancies);
2024-10-15 19:41:18 +00:00
const events: EventInput[] = [];
2024-10-15 16:33:25 +00:00
for (const openingTime of openingTimes) {
2024-10-15 19:41:18 +00:00
const lastMonday = getLastMonday();
const shift = openingTime.end < lastMonday;
// if permanancies took place last week (=before monday),
// -> display them in lightblue as part of the current week
events.push({
start: shift ? shiftDateByDays(openingTime.start, 7) : openingTime.start,
end: shift ? shiftDateByDays(openingTime.end, 7) : openingTime.end,
backgroundColor: shift ? "lightblue" : "green",
});
2024-10-15 16:33:25 +00:00
}
return events;
}
2024-10-15 19:41:18 +00:00
// Function to get last Monday at 00:00
function getLastMonday(): Date {
const now = new Date();
const dayOfWeek = now.getDay();
const lastMonday = new Date(now);
lastMonday.setDate(now.getDate() - ((dayOfWeek + 6) % 7)); // Adjust for Monday as day 1
lastMonday.setHours(0, 0, 0, 0);
return lastMonday;
}
function shiftDateByDays(date: Date, days: number): Date {
const newDate = new Date(date);
newDate.setDate(date.getDate() + days);
return newDate;
}