278 lines
12 KiB
TypeScript
278 lines
12 KiB
TypeScript
// pages/api/shifts.ts
|
||
|
||
import axiosServer from '../../src/axiosServer';
|
||
import { getToken } from "next-auth/jwt";
|
||
|
||
import type { NextApiRequest, NextApiResponse } from "next";
|
||
import { Prisma, PrismaClient, DayOfWeek, Publisher, Shift } from "@prisma/client";
|
||
import { levenshteinEditDistance } from "levenshtein-edit-distance";
|
||
import { filterPublishers, /* other functions */ } from './index';
|
||
|
||
import CAL from "../../src/helpers/calendar";
|
||
//const common = require("@common");
|
||
import common from "../../src/helpers/common";
|
||
import { Axios } from 'axios';
|
||
const path = require("path");
|
||
const fs = require("fs");
|
||
|
||
const generateTemplateFile = async (data, templateSrc) => {
|
||
const handlebars = require("handlebars");
|
||
const htmlDocx = require("html-docx-js");
|
||
|
||
// Compile the Handlebars template
|
||
const template = handlebars.compile(templateSrc);
|
||
|
||
// Generate the HTML output using the template and the events data
|
||
const html = template(data);
|
||
return html;
|
||
}
|
||
|
||
function splitNotes(notes) {
|
||
if (!notes) {
|
||
return { notes: '', notes_bold: '' };
|
||
}
|
||
|
||
// Combine both dash types into a single pattern for the regex
|
||
const dashPattern = /[-–]/g;
|
||
|
||
// Find all occurrences of either dash
|
||
let allDashes = [...notes.matchAll(dashPattern)];
|
||
|
||
if (allDashes.length === 0) {
|
||
// No dash found, return the original notes in both parts
|
||
return { notes: notes, notes_bold: '' };
|
||
}
|
||
|
||
// Get the index of the first and last dash
|
||
const firstDashIndex = allDashes[0].index;
|
||
const lastDashIndex = allDashes[allDashes.length - 1].index;
|
||
|
||
// Extract parts before the first dash and after the last dash
|
||
const notesBeforeFirstDash = notes.substring(0, firstDashIndex + 1);
|
||
const notesAfterLastDash = notes.substring(lastDashIndex + 1);
|
||
|
||
return {
|
||
notes: notesBeforeFirstDash,
|
||
notes_bold: notesAfterLastDash
|
||
};
|
||
}
|
||
|
||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||
console.log(req.url);
|
||
console.log(req.query);
|
||
const prisma = common.getPrismaClient();
|
||
|
||
// If you don't have the NEXTAUTH_SECRET environment variable set,
|
||
// you will have to pass your secret as `secret` to `getToken`
|
||
const axios = await axiosServer({ req: req, res: res });
|
||
const token = await getToken({ req: req });
|
||
if (!token) {
|
||
// If no token or invalid token, return unauthorized status
|
||
return res.status(401).json({ message: "Unauthorized" });
|
||
}
|
||
|
||
|
||
if (req.method === 'GET') {
|
||
const { year, month } = req.query;
|
||
|
||
//ToDo: maybe we don't need that anymore as we are publishing the shifts and show all published shifts
|
||
let fromDate = new Date();
|
||
fromDate.setDate(fromDate.getDate() - 1);
|
||
fromDate.setHours(0, 0, 0, 0);
|
||
if (year && month) {
|
||
fromDate = new Date(parseInt(year as string), parseInt(month as string) - 1, 1);
|
||
}
|
||
const monthInfo = common.getMonthDatesInfo(fromDate);
|
||
//let toDate = new Date(monthInfo.lastSunday);
|
||
if (year && month) {
|
||
fromDate = monthInfo.firstMonday;
|
||
}
|
||
|
||
try {
|
||
|
||
const shifts = await prisma.shift.findMany({
|
||
where: {
|
||
isActive: true,
|
||
isPublished: true,
|
||
// OR: [
|
||
// { isPublished: true },
|
||
// { user: { role: 'admin' } } // Todo: example. fix this
|
||
// ],
|
||
startTime: {
|
||
gte: fromDate,
|
||
//lt: toDate,
|
||
},
|
||
},
|
||
orderBy: {
|
||
startTime: 'asc',
|
||
},
|
||
include: {
|
||
assignments: {
|
||
where: {},
|
||
include: {
|
||
publisher: true,
|
||
},
|
||
},
|
||
cartEvent: {
|
||
include: {
|
||
location: true,
|
||
},
|
||
},
|
||
},
|
||
});
|
||
|
||
let json = JSON.stringify(shifts);
|
||
const groupedShifts = {};
|
||
const startDate = new Date(shifts[0].startTime);
|
||
let i = 0;
|
||
try {
|
||
for (const shift of shifts) {
|
||
i++;
|
||
const date = new Date(shift.startTime);
|
||
const day = common.getISODateOnly(date)
|
||
const time = common.getTimeRange(shift.startTime, shift.endTime); //common.getLocalTime(date);
|
||
if (!groupedShifts[day]) {
|
||
groupedShifts[day] = {};
|
||
}
|
||
if (!groupedShifts[day][time]) {
|
||
groupedShifts[day][time] = [];
|
||
}
|
||
|
||
// let { notes, notes_bold } = splitNotes(shift.notes);//.substring(Math.max(shift.notes.lastIndexOf("-"), shift.notes.lastIndexOf("–")) + 1).trim() || "";
|
||
let notes = "", notes_bold = "";
|
||
|
||
if (shift.assignments.some(a => a.isWithTransport)) {
|
||
if (shift.requiresTransport) {
|
||
notes = "Транспорт: ";
|
||
notes_bold = " " + shift.assignments.filter(a => a.isWithTransport).map(a => common.getInitials(a.publisher.firstName + " " + a.publisher.lastName)).join(", ");
|
||
}
|
||
}
|
||
|
||
let shiftSchedule = {
|
||
date: date,
|
||
placeOfEvent: shift.cartEvent.location.name,
|
||
time: time,
|
||
requiresTransport: shift.requiresTransport,
|
||
//bold the text after - in the notes
|
||
notes: notes,
|
||
notes_bold: notes_bold,
|
||
names: shift.assignments.length > 0
|
||
? shift.assignments
|
||
.map((assignment) => {
|
||
return (
|
||
assignment.publisher.firstName +
|
||
" " +
|
||
assignment.publisher.lastName
|
||
);
|
||
})
|
||
.join(", ")
|
||
: shift.name,
|
||
};
|
||
|
||
if (shiftSchedule.names.length > 0) {
|
||
groupedShifts[day][time].push(shiftSchedule);
|
||
}
|
||
}
|
||
} catch (err) {
|
||
console.log(err + " " + JSON.stringify(shifts[i]));
|
||
}
|
||
|
||
for (const day in groupedShifts) {
|
||
const times = Object.keys(groupedShifts[day]);
|
||
for (const time of times) {
|
||
const shift = groupedShifts[day][time][0];
|
||
if (shift) {
|
||
// Determine the first shift of the day if it requires transport
|
||
if (time === times[0] && shift.requiresTransport) { // Check if this is the first time slot of the day
|
||
shift.notes = "Докарва количка от Склад Сердика -"; // Update the first shift in the first time slot
|
||
}
|
||
|
||
// Determine the last shift of the day if it requires transport
|
||
if (time === times[times.length - 1] && shift.requiresTransport) { // Check if this is the last time slot of the day
|
||
shift.notes = "Прибира количка в Склад Сердика -"; // Update the last shift in the last time slot
|
||
}
|
||
}
|
||
|
||
// if day is thursday, change the note to "Специален текст с линк към снимка" : public/images/cart_EN.jpg - opened in a popup modal
|
||
//check if the day is thursday
|
||
const dayOfWeek = common.getDayOfWeekNameEnEnumForDate(shift.date);
|
||
if (dayOfWeek == "Thursday") {
|
||
shift.notes = `<a href="#" onclick="document.getElementById('cart-image-modal').style.display='block'; return false;" class="text-blue-600 hover:underline">Специален текст с линк към снимка</a>
|
||
<div id="cart-image-modal" style="display: none;">
|
||
<div class="fixed inset-0 flex items-center justify-center z-50">
|
||
<div style="background-color: white; padding: 16px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); position: relative; max-width: fit-content;">
|
||
<span onclick="document.getElementById('cart-image-modal').style.display='none'" style="position: absolute; right: 10px; top: 5px; cursor: pointer; font-size: 24px; color: #6b7280;">×</span>
|
||
<img src="/images/cart_EN.jpg" style="max-height: 80vh; object-fit: contain;" />
|
||
</div>
|
||
<div class="fixed inset-0 bg-black opacity-50" onclick="document.getElementById('cart-image-modal').style.display='none'"></div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Create the output object in the format of the second JSON file
|
||
const monthlySchedule = {
|
||
month: common.getMonthName(shifts[0].startTime.getMonth()),
|
||
year: startDate.getFullYear(),
|
||
events: [],
|
||
};
|
||
|
||
for (const day in groupedShifts) {
|
||
var dayEvent = null;
|
||
|
||
for (const time in groupedShifts[day]) {
|
||
if (dayEvent == null) {
|
||
const shift = groupedShifts[day][time][0];
|
||
if (!shift) {
|
||
console.log("shift is null");
|
||
continue;
|
||
}
|
||
|
||
let weekday = common.getDayOfWeekName(shift.date);
|
||
let monthName = common.getMonthName(shift.date.getMonth());
|
||
weekday = weekday.charAt(0).toUpperCase() + weekday.slice(1);
|
||
let weekNr = common.getWeekNumber(shift.date);
|
||
console.log("weekday = " + weekday, " weekNr = " + weekNr);
|
||
dayEvent = {
|
||
week: weekNr,
|
||
dayOfWeek: weekday,
|
||
dayOfMonth: shift.date.getDate(),
|
||
placeOfEvent: shift.placeOfEvent,
|
||
shifts: [],
|
||
transport: shift.notes,
|
||
monthName: monthName,
|
||
};
|
||
}
|
||
|
||
dayEvent.shifts.push(...groupedShifts[day][time]);
|
||
}
|
||
if (dayEvent) {
|
||
monthlySchedule.events.push(dayEvent);
|
||
}
|
||
}
|
||
|
||
const outputPath = path.join(process.cwd(), 'public', 'content', 'output');
|
||
if (!fs.existsSync(outputPath)) {
|
||
fs.mkdirSync(outputPath, { recursive: true });
|
||
}
|
||
|
||
//fs.writeFileSync(path.join(outputPath, `shifts ${year}.${month}.json`), JSON.stringify(monthlySchedule), 'utf8');
|
||
// Load the Handlebars template from a file
|
||
const template = fs.readFileSync("./src/templates/schedule.hbs", "utf8");
|
||
generateTemplateFile(monthlySchedule, template).then((result) => {
|
||
const filename = path.join(outputPath, `schedule.html`)
|
||
//fs.writeFileSync(filename, result, "utf8");
|
||
res.end(result);
|
||
}
|
||
);
|
||
}
|
||
catch (error) {
|
||
console.log(error);
|
||
res.status(500).json({ error: "Internal Server Error" });
|
||
}
|
||
} else {
|
||
res.setHeader('Allow', ['GET']);
|
||
res.status(405).end(`Method ${req.method} Not Allowed`);
|
||
}
|
||
} |