Files
mwitnessing/pages/api/index.ts

890 lines
33 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { getToken } from "next-auth/jwt";
import { NextApiRequest, NextApiResponse } from 'next'
import { DayOfWeek, AvailabilityType } from '@prisma/client';
const common = require('../../src/helpers/common');
const data = require('../../src/helpers/data');
const subq = require('../../prisma/bl/subqueries');
import fs from 'fs';
import path from 'path';
import { all } from "axios";
/**
*
* @param req import { NextApiRequest, NextApiResponse } from 'next'
* @param res import { NextApiRequest, NextApiResponse } from 'next'
*/
export default async function handler(req, res) {
const prisma = common.getPrismaClient();
// Retrieve and validate the JWT token
const token = await getToken({ req: req });
if (!token) {
// If no token or invalid token, return unauthorized status
return res.status(401).json({ message: "Unauthorized to call this API endpoint" });
}
else {
// If token is valid, log the user
//console.log("JWT | User: " + token.email);
}
var action = req.query.action;
var filter = req.query.filter;
let day: Date;
let isExactTime;
if (req.query.date) {
day = new Date(req.query.date);
//date.setDate(date.getDate()); // Subtract one day to get the correct date, as calendar sends wrong date (one day ahead)
//date.setHours(0, 0, 0, 0);
}
if (req.query.filterDate) {
day = new Date(req.query.filterDate);
isExactTime = true;
}
let monthInfo = common.getMonthDatesInfo(day);
const searchText = req.query.searchText?.normalize('NFC');
try {
switch (action) {
case "initDb":
// Read the SQL script from the file
const sqlFilePath = path.join(process.cwd(), 'prisma', 'data.sql');
const sql = fs.readFileSync(sqlFilePath, 'utf8');
// Execute the SQL script
await prisma.$executeRawUnsafe(sql);
res.status(200).json({ message: "SQL script executed successfully" });
break;
case "deleteAllPublishers":
//get filter and delete all publishers containing that in first name or last name
await prisma.publisher.deleteMany({
where: {
OR: [
{ firstName: { contains: filter } },
{ lastName: { contains: filter } },
],
},
});
res.status(200).json({ "message": "ok" });
break;
case "deleteAllAvailabilities":
//get filter and delete all publishers containing that in first name or last name
await prisma.availability.deleteMany({
where: filter ? {
OR: [
// { name: { contains: filter } },
{ starTime: { lte: day } }
]
} : {}
});
res.status(200).json({ "message": "ok" });
break;
//gets publisher by names with availabilities and assignments
case "deleteAvailabilityForPublisher":
let publisherId = req.query.publisherId;
let dateFor;
if (req.query.date) {
dateFor = new Date(req.query.date);
//get month info from date
monthInfo = common.getMonthDatesInfo(dateFor);
}
const deleteFromPreviousAssignments = common.parseBool(req.query.deleteFromPreviousAssignments);
// if datefor is not null/undefined, delete availabilities for that month
try {
await prisma.availability.deleteMany({
where: {
publisherId: publisherId,
startTime: { gte: monthInfo?.firstMonday },
endTime: { lte: monthInfo?.lastSunday }
}
});
if (deleteFromPreviousAssignments) {
await prisma.availability.deleteMany({
where: {
publisherId: publisherId,
isFromPreviousAssignment: true
}
});
}
// await prisma.availability.deleteMany({
// where: {
// publisherId: publisherId
// }
// });
res.status(200).json({ "message": "ok" });
} catch (error) {
console.error("Error deleting availability for publisher: " + publisherId + " error: " + error);
res.status(500).json({ error });
}
break;
case "createAvailabilities": {
const availabilities = req.body;
//! console.log("createAvailabilities: " + JSON.stringify(availabilities));
try {
let createResults = await prisma.availability.createMany({
data: availabilities
});
res.status(200).json({ "message": "ok", "results": createResults });
} catch (error) {
console.error("Error creating availabilities: " + error);
res.status(500).json({ error });
}
}
break;
case "getCalendarEvents":
let events = await getCalendarEvents(req.query.publisherId, day);
res.status(200).json(events);
case "getPublisherInfo":
let pubs = await filterPublishers("id,firstName,lastName,email".split(","), "", null, req.query.assignments || true, req.query.availabilities || true, false, req.query.id);
res.status(200).json(pubs[0]);
break;
case "getMonthlyStatistics":
let allpubs = await getMonthlyStatistics("id,firstName,lastName,email", day);
res.status(200).json(allpubs);
break;
case "getUnassignedPublishers":
//let monthInfo = common.getMonthDatesInfo(date);
let allPubs = await filterPublishers("id,firstName,lastName,email,isActive".split(","), "", day, true, true, false);
let unassignedPubs = allPubs.filter(pub => pub.currentMonthAssignments == 0 && pub.availabilities.length > 0);
res.status(200).json(unassignedPubs);
break;
case "filterPublishers":
const fetchAssignments = common.parseBool(req.query.assignments);
const fetchAvailabilities = common.parseBool(req.query.availabilities);
let publishers = await filterPublishers(req.query.select, searchText, day, fetchAssignments, fetchAvailabilities);
//!console.log("publishers: (" + publishers.length + ") " + JSON.stringify(publishers.map(pub => pub.firstName + " " + pub.lastName)));
res.status(200).json(publishers);
break;
case "filterPublishersNew":
let includeOldAvailabilities = common.parseBool(req.query.includeOldAvailabilities);
let results = await filterPublishersNew_Available(req.query.select, day,
common.parseBool(req.query.isExactTime), common.parseBool(req.query.isForTheMonth), includeOldAvailabilities);
res.status(200).json(results);
break;
// find publisher by full name or email
case "findPublisher":
const getAll = common.parseBool(req.query.all) || false;
let publisher = await data.findPublisher(filter, req.query.email, req.query.select, getAll);
res.status(200).json(publisher);
break;
case "getShiftsForDay":
// Setting the range for a day: starting from the beginning of the date and ending just before the next date.
let startOfDay = new Date(day.getFullYear(), day.getMonth(), day.getDate());
let endOfDay = new Date(day.getFullYear(), day.getMonth(), day.getDate(), 23, 59, 59, 999);
const pubAvCount = await prisma.publisher.findMany({
select: {
id: true,
firstName: true,
lastName: true,
_count: {
select: {
availabilities: true,
}
}
}
});
let shiftsForDate = await prisma.shift.findMany({
where: {
startTime: {
gte: startOfDay,
lt: endOfDay
},
},
include: {
assignments: {
include: {
publisher: subq.publisherSelect
},
},
},
});
shiftsForDate.forEach(shift => {
shift.assignments.forEach(assignment => {
assignment.publisher.availabilityCount = pubAvCount.find(pub => pub.id === assignment.publisher.id)?._count?.availabilities || 0;
});
}
);
console.log("shiftsForDate(" + day + ") - " + shiftsForDate.length + " : " + JSON.stringify(shiftsForDate.map(shift => shift.id)));
res.status(200).json(shiftsForDate);
break;
case "copyOldAvailabilities":
//get all publishers that don't have availabilities for the current month
monthInfo = common.getMonthDatesInfo(day);
// await prisma.availability.deleteMany({
// where: {
// startTime: {
// gte: monthInfo.firstMonday,
// },
// isFromPreviousMonth: true
// }
// });
let outdatedPubs = await prisma.publisher.findMany({
where: {
availabilities: {
none: {
startTime: {
gte: monthInfo.firstMonday,
}
}
}
},
select: {
id: true,
firstName: true,
lastName: true,
availabilities: true
}
});
outdatedPubs.forEach(async pub => {
// avail.startTime >= monthInfo.firstMonday
//get prev month date:
let prevMonth = new Date(monthInfo.firstMonday);
prevMonth.setMonth(prevMonth.getMonth() - 1);
let prevMonthInfo = common.getMonthDatesInfo(prevMonth);
pub.availabilities = pub.availabilities.filter(avail => avail.startTime > prevMonthInfo.firstMonday);
console.log("" + pub.firstName + " " + pub.lastName + " copying " + pub.availabilities.length + " availabilities from previous months.");
pub.availabilities.forEach(async avail => {
//get the new date based on the day of week and week of month
if (!avail.weekOfMonth) {
avail.weekOfMonth = common.getWeekOfMonth(avail.startTime)
}
let origMonthInfo = common.getMonthDatesInfo(avail.startTime);
let newStart = common.getDateFromWeekNrAndDayOfWeek(monthInfo.firstMonday, avail.weekOfMonth, avail.dayofweek, avail.startTime);
//ToDo: fix double check. also check if we're in 5th week and the month has 4 weeks
// const availability = await data.findPublisherAvailability(publisher.id, newStart);
// if (availability) {
// return;
// }
let newEnd = new Date(newStart.getTime());
newEnd.setHours(avail.endTime.getHours(), avail.endTime.getMinutes(), 0, 0);
let data = {
publisherId: pub.id,
dayOfMonth: null,
dayofweek: avail.dayofweek || common.getDayOfWeekNameEnEnumForDate(avail.startTime),
weekOfMonth: avail.weekofMonth || common.getWeekOfMonth(avail.startTime),
// null for auto generated availabilities
//dateOfEntry: new Date(), //avail.dateOfEntry || avail.startTime,
startTime: newStart,
endTime: newEnd,
type: AvailabilityType.Monthly,
isFromPreviousMonth: true,
name: avail.name || "старо предпочитание",
parentAvailabilityId: avail.id,
// parentAvailability: {
// connect: {
// id: avail.id
// }
// },
}
await prisma.availability.create({ data: data });
//if month has 5 weeks and the monthInfo has 4 weeks copy the availabilities also from the 1st week to the 5th week
if (monthInfo.nrOfWeeks == 5 && avail.weekOfMonth == 1 && origMonthInfo.nrOfWeeks == 4) {
newStart = common.getDateFromWeekNrAndDayOfWeek(monthInfo.firstMonday, 5, avail.dayofweek, avail.startTime);
newEnd = new Date(newStart.getTime());
newEnd.setHours(avail.endTime.getHours(), avail.endTime.getMinutes(), 0, 0);
data.weekOfMonth = 5;
data.startTime = newStart;
data.endTime = newEnd;
await prisma.availability.create({ data: data });
}
});
});
//convert old assignments to availabilities
res.status(200).json({ "message": "ok" });
break;
case "deleteCopiedAvailabilities":
//delete all availabilities that are copied from previous months
monthInfo = common.getMonthDatesInfo(day);
await prisma.availability.deleteMany({
where: {
startTime: {
gte: monthInfo.firstMonday,
},
isFromPreviousMonth: true
}
});
case "replaceInAssignment":
const { oldPublisherId, newPublisherId, shiftId } = req.method === "POST" ? req.body : req.query;
const result = await replaceInAssignment(oldPublisherId, newPublisherId, shiftId);
res.status(200).json(result);
break;
case "updateShifts":
//get all shifts for the month and publish them (we pass date )
let isPublished = common.parseBool(req.query.isPublished);
let updated = await prisma.shift.updateMany({
where: {
startTime: {
gte: new Date(monthInfo.firstMonday.getFullYear(), monthInfo.firstMonday.getMonth(), 1),
lt: new Date(monthInfo.lastSunday.getFullYear(), monthInfo.lastSunday.getMonth() + 1, 1),
}
},
data: {
isPublished: isPublished
}
});
console.log("Updated shifts: " + updated.count);
res.status(200).json({ "message": "ok" });
break;
case "getPossibleShiftPublisherEmails":
const subscribedPublishers = await prisma.publisher.findMany({
where: {
isSubscribedToCoverMe: true
},
select: {
id: true,
firstName: true,
lastName: true,
email: true
}
}).then(pubs => {
return pubs.map(pub => {
return {
id: pub.id,
name: pub.firstName + " " + pub.lastName,
email: pub.email
}
});
});
let shift = await prisma.shift.findUnique({
where: {
id: parseInt(req.query.shiftId)
}
});
let availablePublishers = await filterPublishersNew_Available("id,firstName,lastName,email", new Date(shift.startTime), true, false);
//return names and email info only
availablePublishers = availablePublishers.map(pub => {
return {
id: pub.id,
name: pub.firstName + " " + pub.lastName,
email: pub.email
}
});
res.status(200).json({ shift, availablePublishers: availablePublishers, subscribedPublishers });
break;
default:
res.status(200).json({
"message": "no action '" + action + "' found"
});
break;
}
} catch (error) {
console.error("API: Error executing action: " + action + " with filter: " + filter + " error: " + error);
res.status(500).json({ error });
}
}
export async function getMonthlyStatistics(selectFields, filterDate) {
let publishers = [];
selectFields = selectFields?.split(",");
let selectBase = selectFields.reduce((acc, curr) => {
acc[curr] = true;
return acc;
}, {});
selectBase.assignments = {
select: {
id: true,
shift: {
select: {
id: true,
startTime: true,
endTime: true
}
}
}
};
let currentWeekStart: Date, currentWeekEnd: Date,
currentMonthStart: Date, currentMonthEnd: Date,
previousMonthStart: Date, previousMonthEnd: Date;
let date = new Date(filterDate);
date.setDate(filterDate.getDate());
currentWeekStart = common.getStartOfWeek(date);
currentWeekEnd = common.getEndOfWeek(date);
var monthInfo = common.getMonthDatesInfo(date);
currentMonthStart = monthInfo.firstMonday;
currentMonthEnd = monthInfo.lastSunday;
date.setMonth(date.getMonth() - 1);
monthInfo = common.getMonthDatesInfo(date);
previousMonthStart = monthInfo.firstMonday;
previousMonthEnd = monthInfo.lastSunday;
const prisma = common.getPrismaClient();
publishers = await prisma.publisher.findMany({
select: {
...selectBase,
}
});
publishers.forEach(pub => {
// Debug logs to help identify issues
pub.currentWeekAssignments = pub.assignments.filter(assignment => {
return assignment.shift.startTime >= currentWeekStart && assignment.shift.startTime <= currentWeekEnd;
}).length;
pub.currentMonthAssignments = pub.assignments.filter(assignment => {
return assignment.shift.startTime >= currentMonthStart && assignment.shift.startTime <= currentMonthEnd;
}).length;
pub.previousMonthAssignments = pub.assignments.filter(assignment => {
return assignment.shift.startTime >= previousMonthStart && assignment.shift.startTime <= previousMonthEnd;
}).length;
});
return publishers;
}
export async function filterPublishersNew_Available(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isWithStats = true, includeOldAvailabilities = false) {
return data.filterPublishersNew(selectFields, filterDate, isExactTime, isForTheMonth, isWithStats, includeOldAvailabilities);
}
// availabilites filter:
// 1. if dayOfMonth is null, match by day of week (enum)
// 2. if dayOfMonth is not null, match by date
// 3. if date is 00:00:00, match by date only (without time)
// 4. if date is not 00:00:00, it should be in the range of start and end times
// this way we distinguish between weekly availabiillities (entered without dayOfMonth) and old availabilities from previous months (entered with dayOfMonth, but we set it to null),
// (To validate) we use useDateFilter in combination with the filterDate to get publishers without availabilities for the day:
// 1: useDateFilter = false, filterDate = null - get all publishers with availabilities for the current month
// 2: useDateFilter = false, filterDate = date - get all publishers with availabilities for the current month
// 3: useDateFilter = true, filterDate = null - get all publishers with availabilities for the current month
// 4: useDateFilter = true, filterDate = date - get all publishers with availabilities for the current month and filter by date
export async function filterPublishers(selectFields, searchText, filterDate, fetchAssignments: boolean = true, fetchAvailabilities: boolean = true, useDateFilter = true, id = null) {
let currentWeekStart: Date, currentWeekEnd: Date,
currentMonthStart: Date, currentMonthEnd: Date,
previousMonthStart: Date, previousMonthEnd: Date,
filterDateEnd: Date,
publishers = [];
if (!filterDate) {
useDateFilter = false;
previousMonthStart = new Date();
previousMonthStart.setDate(1);
previousMonthStart.setMonth(previousMonthStart.getMonth() - 1);
}
else {
let date = new Date(filterDate.getTime());
//date.setDate(filterDate.getDate());
currentWeekStart = common.getStartOfWeek(date);
currentWeekEnd = common.getEndOfWeek(date);
var monthInfo = common.getMonthDatesInfo(date);
currentMonthStart = monthInfo.firstMonday;
currentMonthEnd = monthInfo.lastSunday;
date.setMonth(date.getMonth() - 1);
monthInfo = common.getMonthDatesInfo(date);
previousMonthStart = monthInfo.firstMonday;
previousMonthEnd = monthInfo.lastSunday;
filterDateEnd = new Date(filterDate);
filterDateEnd.setHours(23, 59, 59, 999);
}
let whereClause = {};
if (id) {
whereClause = {
id: String(id)
}
}
const searchTextString = String(searchText || "").trim();
if (searchTextString !== "") {
whereClause = {
OR: [
{ firstName: { contains: searchTextString } },
{ lastName: { contains: searchTextString } },
],
};
}
// Base select fields
// Only attempt to split if selectFields is a string; otherwise, use it as it is.
selectFields = typeof selectFields === 'string' ? selectFields.split(",") : selectFields;
let selectBase = selectFields.reduce((acc, curr) => {
acc[curr] = true;
return acc;
}, {});
// If assignments flag is true, fetch assignments
if (fetchAssignments) {
//!! WORKING CODE, but heavy on the DB !!
selectBase.assignments = {
select: {
id: true,
shift: {
select: {
id: true,
startTime: true,
endTime: true
}
}
},
where: {
shift: {
OR: [
// {
// startTime: {
// gte: currentWeekStart,
// lte: currentWeekEnd
// }
// },
// {
// startTime: {
// gte: currentMonthStart,
// lte: currentMonthEnd
// }
// },
{
startTime: {
gte: previousMonthStart,
// lte: previousMonthEnd
}
},
]
}
}
};
//selectBase.assignments = true;
}
let dayOfWeekEnum: DayOfWeek
if (filterDate) {
// Determine day of week using common function
dayOfWeekEnum = common.getDayOfWeekNameEnEnumForDate(filterDate);
if (filterDate.getHours() > 21 || filterDate.getHours() < 6) {
filterDate.setHours(0, 0, 0, 0); // Set to midnight
}
}
// console.log(`filterDate: ${filterDate}`);
// console.log(`filterDateEnd: ${filterDateEnd}`);
if (filterDate && useDateFilter) {
// Info, description and ToDo:
// We should distinguish between availabilities with dayOfMonth and without
// If dayOfMonth is null, we should match by day of week using the enum
// If dayOfMonth is not null, we should match by date.
// if date is 00:00:00, we should match by date only (without time)
// if date is not 00:00:00, it should be in the range of start and end times
// we should also include availabilities from previous assignments but not with preference - dayOfMonth is null. we shuold include them only if they match the day of week
// and distinguish between weekly availabiillities (entered without dayOfMonth) and old availabilities from previous months (entered with dayOfMonth, but we set it to null),
// which we count as weekly availabilities. We can use the type field for that
//console.log(`filterDate: ${filterDate}. date: ${filterDate.getDate()}. dayOfWeekEnum: ${dayOfWeekEnum}. useDateFilter: ${useDateFilter}`);
// we will have 3 cases: up-to date availabilities, old availabilities from previous months and availabilities from previous assignments but not with preference
// we will use the type field to distinguish between them
// up-to date availabilities will have type = 1
// old availabilities from previous months will have type = 2 - we want to drop that function to simplify the code and avoid confusion
// availabilities from previous assignments but not with preference will have type = 3
// also, permanent weekly availabilities will have dayOfMonth = null and type = 0
// for 0 we will match by dayOfWeekEnum and times
// for 1 we will match by exact date and times
// for 2 we will match by dayofweek, weekOfMonth and times
// for 3 we will match by dayofweek, weekOfMonth and times - this is the same as 2, but we will not count them as availabilities for the current month
// generaion of schedule:
/*
option 1: fill from blank - first two places per shift, then more if possible
option 2: fill from previous schedule , remove all assignments where new availabilities are not available
and permanent availabilities to make room for changes (we want to shuffle if possible??? do we?)
continue with option 1 from there
which one depends on if we prioritize empty shifts or making sure everyone has up to date availabilities
*/
//substract the time difference between from ISO string and local time
const offset = filterDate.getTimezoneOffset() * 60000; // offset in milliseconds
var dateAsISO = new Date(filterDate.getTime() + offset);
//if full day, match by date only
if (filterDate.getHours() == 0 || dateAsISO.getHours() == 0) {
whereClause["availabilities"] = {
some: {
OR: [
// Check only by date without considering time ( Assignments on specific days without time)
{
startTime: { gte: filterDate },
endTime: { lte: filterDateEnd },
}
,
// Check if dayOfMonth is null and match by day of week using the enum (Assigments every week)
// This includes availabilities from previous assignments but not with preference
{
dayOfMonth: null, // includes monthly and weekly repeats
dayofweek: dayOfWeekEnum,
// ToDo: and weekOfMonth
startTime: { lte: filterDate },
AND: [
{
OR: [ // OR condition for repeatUntil to handle events that either end after filterDate or repeat forever
{ endDate: { gte: filterDate } },
{ endDate: null }
]
}
]
}
]
}
};
}
//if not full day, match by date and time
else {
//match exact time (should be same as data.findPublisherAvailability())
whereClause["availabilities"] = {
some: {
OR: [
// Check if dayOfMonth is set and filterDate is between start and end dates (Assignments on specific days AND time)
{
dayOfMonth: filterDate.getDate(),
startTime: { lte: filterDate },
endTime: { gte: filterDate }
},
// Check if dayOfMonth is null and match by day of week using the enum (Assigments every week)
{
dayOfMonth: null,
dayofweek: dayOfWeekEnum,
startTime: { gte: filterDate },
}
]
}
};
}
} else {
// we use month filter if date is passed and useDateFilter is false to get all publishers with availabilities for the current month
if (fetchAvailabilities) {
// If no filter date, return all publishers's availabilities for currentMonthStart
whereClause["availabilities"] = {
some: {
OR: [
// Check if dayOfMonth is not null and startTime is after currentMonthStart (Assignments on specific days AND time)
{
dayOfMonth: { not: null },
startTime: { gte: currentMonthStart },
endTime: { lte: currentMonthEnd }
},
// Check if dayOfMonth is null and match by day of week using the enum (Assigments every week)
{
dayOfMonth: null,
}
]
}
};
//try here
// selectBase.аvailabilities = {
// select: {
// dayofweek: true,
// dayOfMonth: true,
// startTime: true,
// endTime: true,
// weekOfMonth: true,
// type: true
// },
// where: {
// OR: [
// {
// startTime: { gte: currentMonthStart },
// endTime: { lte: currentMonthEnd }
// }
// ]
// }
// }
}
}
//include availabilities if flag is true
const prisma = common.getPrismaClient(); //why we need to get it again?
publishers = await prisma.publisher.findMany({
where: whereClause,
select: {
...selectBase,
...(fetchAvailabilities && { availabilities: true }),
// ...(fetchAssignments && {
// assignments: {
// include: {
// shift: true,
// }
// }
// }
// )
}
});
console.log(`publishers: ${publishers.length}, WhereClause: ${JSON.stringify(whereClause)}`);
if (filterDate) {
if (fetchAssignments) {
//get if publisher has assignments for current weekday, week, current month, previous month
publishers.forEach(pub => {
// Filter assignments for current day
pub.currentDayAssignments = pub.assignments?.filter(assignment => {
return assignment.shift.startTime >= filterDate && assignment.shift.startTime <= filterDateEnd;
}).length;
// Filter assignments for current week
pub.currentWeekAssignments = pub.assignments?.filter(assignment => {
return assignment.shift.startTime >= currentWeekStart && assignment.shift.startTime <= currentWeekEnd;
}).length;
// Filter assignments for current month
pub.currentMonthAssignments = pub.assignments?.filter(assignment => {
return assignment.shift.startTime >= currentMonthStart && assignment.shift.startTime <= currentMonthEnd;
}).length;
// Filter assignments for previous month
pub.previousMonthAssignments = pub.assignments?.filter(assignment => {
return assignment.shift.startTime >= previousMonthStart && assignment.shift.startTime <= previousMonthEnd;
}).length;
});
}
}
if (fetchAvailabilities) {
//get the availabilities for the day. Calcullate:
//1. how many days the publisher is available for the current month - only with dayOfMonth
//2. how many days the publisher is available without dayOfMonth (previous months count)
//3. how many hours in total the publisher is available for the current month
publishers.forEach(pub => {
pub.currentMonthAvailability = pub.availabilities?.filter(avail => {
// return avail.dayOfMonth != null && avail.startTime >= currentMonthStart && avail.startTime <= currentMonthEnd;
return avail.startTime >= currentMonthStart && avail.startTime <= currentMonthEnd;
})
pub.currentMonthAvailabilityDaysCount = pub.currentMonthAvailability.length || 0;
// pub.currentMonthAvailabilityDaysCount += pub.availabilities.filter(avail => {
// return avail.dayOfMonth == null;
// }).length;
pub.currentMonthAvailabilityHoursCount = pub.currentMonthAvailability.reduce((acc, curr) => {
return acc + (curr.endTime.getTime() - curr.startTime.getTime()) / (1000 * 60 * 60);
}, 0);
//if pub has ever filled the form - if has availabilities which are not from previous assignments
pub.hasEverFilledForm = pub.availabilities?.some(avail => {
return avail.isFromPreviousAssignments == false;
});
//if pub has up-to-date availabilities (with dayOfMonth) for the current month
pub.hasUpToDateAvailabilities = pub.availabilities?.some(avail => {
return avail.dayOfMonth != null && avail.startTime >= currentMonthStart; // && avail.startTime <= currentMonthEnd;
});
//if pub has availabilities for the current day
pub.hasAvailabilityForCurrentDay = pub.availabilities?.some(avail => {
return avail.startTime >= filterDate && avail.startTime <= filterDateEnd;
});
});
if (filterDate && useDateFilter) {
// Post filter for time if dayOfMonth is null
// Modify the availabilities array of the filtered publishers
publishers.forEach(pub => {
pub.availabilities = pub.availabilities?.filter(avail => matchesAvailability(avail, filterDate));
});
}
}
return publishers;
}
function matchesAvailability(avail, filterDate) {
// Setting the start and end time of the filterDate
filterDate.setHours(0, 0, 0, 0);
const filterDateEnd = new Date(filterDate);
filterDateEnd.setHours(23, 59, 59, 999);
// Return true if avail.startTime is between filterDate and filterDateEnd
return avail.startTime >= filterDate && avail.startTime <= filterDateEnd;
}
async function getCalendarEvents(publisherId, date, availabilities = true, assignments = true) {
const result = [];
let pubs = await filterPublishers("id,firstName,lastName,email".split(","), "", date, assignments, availabilities, date ? true : false, publisherId);
let publisher = pubs[0];
if (publisher) {
if (availabilities) {
publisher.availabilities?.forEach(item => {
result.push({
...item,
title: common.getTimeFomatted(new Date(item.startTime)) + "-" + common.getTimeFomatted(new Date(item.endTime)), //item.name,
date: new Date(item.startTime),
startTime: new Date(item.startTime),
endTime: new Date(item.endTime),
publisherId: publisher.id,
type: "availability",
isFromPreviousAssignment: item.isFromPreviousAssignment,
});
});
}
if (assignments) {
publisher.assignments?.forEach(item => {
result.push({
...item,
title: common.getTimeFomatted(new Date(item.shift.startTime)) + "-" + common.getTimeFomatted(new Date(item.shift.endTime)),
date: new Date(item.shift.startTime),
startTime: new Date(item.shift.startTime),
endTime: new Date(item.shift.endTime),
publisherId: item.publisherid,
type: "assignment",
});
});
}
}
return result;
}
async function replaceInAssignment(oldPublisherId, newPublisherId, shiftId) {
const prisma = common.getPrismaClient();
const result = await prisma.assignment.updateMany({
where: {
publisherId: oldPublisherId,
shiftId: shiftId
},
data: {
publisherId: newPublisherId,
isConfirmed: false,
isBySystem: true,
isMailSent: false
}
});
return result;
}