// 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.requiresTransport) { // For Thursday, use the regular transport text (if any) but add a special note indicator let originalNotes = shift.notes || ""; shift.notes = `Специални инструкции ↗ ${originalNotes}
`; } } } // 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`); } }