new coverMe routine; refactoring
This commit is contained in:
@ -4,6 +4,7 @@ import { getToken } from "next-auth/jwt";
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { createRouter, expressWrapper } from "next-connect";
|
||||
const common = require('../../src/helpers/common');
|
||||
const data = require('../../src/helpers/data');
|
||||
const emailHelper = require('../../src/helpers/email');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const CON = require("../../src/helpers/const");
|
||||
@ -213,9 +214,10 @@ export default async function handler(req, res) {
|
||||
//get from POST data: shiftId, assignmentId, date
|
||||
//let shiftId = req.body.shiftId;
|
||||
let assignmentId = req.body.assignmentId;
|
||||
let date = req.body.date;
|
||||
|
||||
console.log("User: " + user.email + " sent a 'CoverMe' request for his assignment " + assignmentId + " " + date);
|
||||
let toSubscribed = req.body.toSubscribed;
|
||||
let toAvailable = req.body.toAvailable;
|
||||
|
||||
|
||||
let assignment = await prisma.assignment.findUnique({
|
||||
where: {
|
||||
@ -233,6 +235,8 @@ export default async function handler(req, res) {
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log("User: " + user.email + " sent a 'CoverMe' request for his assignment " + assignmentId + " - " + assignment.shift.cartEvent.location.name + " " + assignment.shift.startTime.toISOString());
|
||||
|
||||
|
||||
// update the assignment. generate new publicGuid, isConfirmed to false
|
||||
let newPublicGuid = uuidv4();
|
||||
@ -246,29 +250,43 @@ export default async function handler(req, res) {
|
||||
}
|
||||
});
|
||||
|
||||
//get all subscribed publisers
|
||||
const subscribedPublishers = await prisma.publisher.findMany({
|
||||
where: {
|
||||
isSubscribedToCoverMe: true
|
||||
}
|
||||
});
|
||||
let subscribedPublishers = [], availablePublishers = [];
|
||||
if (toSubscribed) {
|
||||
//get all subscribed publisers
|
||||
subscribedPublishers = await prisma.publisher.findMany({
|
||||
where: {
|
||||
isSubscribedToCoverMe: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (toAvailable) {
|
||||
availablePublishers = await data.filterPublishersNew("id,firstName,lastName,email", new Date(assignment.shift.startTime), true, false);
|
||||
|
||||
}
|
||||
//concat and remove duplicate emails
|
||||
let pubsToSend = subscribedPublishers.concat(availablePublishers).
|
||||
filter((item, index, self) =>
|
||||
index === self.findIndex((t) => (
|
||||
t.email === item.email
|
||||
))
|
||||
);
|
||||
|
||||
//send email to all subscribed publishers
|
||||
for (let i = 0; i < subscribedPublishers.length; i++) {
|
||||
if (subscribedPublishers[i].id == user.id) {
|
||||
continue;
|
||||
}
|
||||
for (let i = 0; i < pubsToSend.length; i++) {
|
||||
|
||||
//send email to subscribed publisher
|
||||
let acceptUrl = process.env.NEXTAUTH_URL + "/api/email?action=email_response&emailaction=coverMeAccept&userId=" + subscribedPublishers[i].id + "&shiftId=" + assignment.shiftId + "&assignmentPID=" + newPublicGuid;
|
||||
let acceptUrl = process.env.NEXTAUTH_URL + "/api/email?action=email_response&emailaction=coverMeAccept&userId=" + pubsToSend[i].id + "&shiftId=" + assignment.shiftId + "&assignmentPID=" + newPublicGuid;
|
||||
|
||||
let model = {
|
||||
user: user,
|
||||
shiftId: assignment.shiftId,
|
||||
acceptUrl: acceptUrl,
|
||||
prefix: user.isMale ? "Брат" : "Сестра",
|
||||
firstName: subscribedPublishers[i].firstName,
|
||||
lastName: subscribedPublishers[i].lastName,
|
||||
email: subscribedPublishers[i].email,
|
||||
firstName: pubsToSend[i].firstName,
|
||||
lastName: pubsToSend[i].lastName,
|
||||
email: pubsToSend[i].email,
|
||||
placeName: assignment.shift.cartEvent.location.name,
|
||||
dateStr: common.getDateFormated(assignment.shift.startTime),
|
||||
time: common.formatTimeHHmm(assignment.shift.startTime),
|
||||
@ -276,8 +294,8 @@ export default async function handler(req, res) {
|
||||
};
|
||||
let results = emailHelper.SendEmailHandlebars(
|
||||
{
|
||||
name: subscribedPublishers[i].firstName + " " + subscribedPublishers[i].lastName,
|
||||
email: subscribedPublishers[i].email
|
||||
name: pubsToSend[i].firstName + " " + pubsToSend[i].lastName,
|
||||
email: pubsToSend[i].email
|
||||
}, "coverMe", model);
|
||||
// if (results) {
|
||||
// console.log("Error sending email: " + error);
|
||||
@ -285,10 +303,12 @@ export default async function handler(req, res) {
|
||||
//}
|
||||
|
||||
if (results) {
|
||||
console.log("Email sent to: " + subscribedPublishers[i].email);
|
||||
console.log("Email sent to: " + pubsToSend[i].email);
|
||||
}
|
||||
|
||||
}
|
||||
res.status(200).json({ message: "CoverMe request sent" });
|
||||
|
||||
break;
|
||||
default:
|
||||
return res.status(400).json({ message: "Invalid action" });
|
||||
|
@ -347,6 +347,43 @@ export default async function handler(req, res) {
|
||||
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({
|
||||
@ -425,254 +462,7 @@ export async function getMonthlyStatistics(selectFields, filterDate) {
|
||||
|
||||
|
||||
export async function filterPublishersNew_Available(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isWithStats = true) {
|
||||
|
||||
// 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;
|
||||
}, {});
|
||||
|
||||
selectBase.assignments = {
|
||||
select: {
|
||||
id: true,
|
||||
shift: {
|
||||
select: {
|
||||
id: true,
|
||||
startTime: true,
|
||||
endTime: true
|
||||
}
|
||||
}
|
||||
},
|
||||
where: {
|
||||
shift: {
|
||||
startTime: {
|
||||
gte: filterDate,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var monthInfo = common.getMonthDatesInfo(filterDate);
|
||||
var weekNr = common.getWeekOfMonth(filterDate); //getWeekNumber
|
||||
let dayOfWeekEnum = common.getDayOfWeekNameEnEnumForDate(filterDate);
|
||||
if (!isExactTime) {
|
||||
filterDate.setHours(0, 0, 0, 0); // Set to midnight
|
||||
}
|
||||
const filterDateEnd = new Date(filterDate);
|
||||
filterDateEnd.setHours(23, 59, 59, 999);
|
||||
|
||||
|
||||
let whereClause = {};
|
||||
//if full day, match by date only
|
||||
if (!isExactTime) { // Check only by date without considering time ( Assignments on specific days without time)
|
||||
whereClause["availabilities"] = {
|
||||
some: {
|
||||
OR: [
|
||||
{
|
||||
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 },
|
||||
AND: [
|
||||
{
|
||||
OR: [ // OR condition for repeatUntil to handle events that either end after filterDate or repeat forever
|
||||
{ endDate: { gte: filterDate } },
|
||||
{ endDate: null }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
if (isForTheMonth) {
|
||||
// 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,
|
||||
AND: [
|
||||
{
|
||||
OR: [ // OR condition for repeatUntil to handle events that either end after filterDate or repeat forever
|
||||
{ endDate: { gte: filterDate } },
|
||||
{ endDate: null }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
console.log(`getting publishers for date: ${filterDate}, isExactTime: ${isExactTime}, isForTheMonth: ${isForTheMonth}`);
|
||||
//include availabilities if flag is true
|
||||
const prisma = common.getPrismaClient(); //why we need to get it again?
|
||||
let publishers = await prisma.publisher.findMany({
|
||||
where: whereClause,
|
||||
select: {
|
||||
...selectBase,
|
||||
availabilities: true
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`publishers: ${publishers.length}, WhereClause: ${JSON.stringify(whereClause)}`);
|
||||
|
||||
// convert matching weekly availabilities to availabilities for the day to make furter processing easier on the client.
|
||||
// we trust that the filtering was OK, so we use the dateFilter as date.
|
||||
publishers.forEach(pub => {
|
||||
pub.availabilities = pub.availabilities.map(avail => {
|
||||
if (avail.dayOfMonth == null) {
|
||||
let newStart = new Date(filterDate);
|
||||
newStart.setHours(avail.startTime.getHours(), avail.startTime.getMinutes(), 0, 0);
|
||||
let newEnd = new Date(filterDate);
|
||||
newEnd.setHours(avail.endTime.getHours(), avail.endTime.getMinutes(), 0, 0);
|
||||
return {
|
||||
...avail,
|
||||
startTime: newStart,
|
||||
endTime: newEnd
|
||||
}
|
||||
}
|
||||
return avail;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
let currentWeekStart: Date, currentWeekEnd: Date,
|
||||
currentMonthStart: Date, currentMonthEnd: Date,
|
||||
previousMonthStart: Date, previousMonthEnd: Date;
|
||||
|
||||
if (isWithStats) {
|
||||
currentWeekStart = common.getStartOfWeek(filterDate);
|
||||
currentWeekEnd = common.getEndOfWeek(filterDate);
|
||||
currentMonthStart = monthInfo.firstMonday;
|
||||
currentMonthEnd = monthInfo.lastSunday;
|
||||
let prevMnt = new Date(filterDate)
|
||||
prevMnt.setMonth(prevMnt.getMonth() - 1);
|
||||
monthInfo = common.getMonthDatesInfo(prevMnt);
|
||||
previousMonthStart = monthInfo.firstMonday;
|
||||
previousMonthEnd = monthInfo.lastSunday;
|
||||
|
||||
//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;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//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 => {
|
||||
if (isWithStats) {
|
||||
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 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 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 availabilities for the current day
|
||||
pub.hasAvailabilityForCurrentDay = pub.availabilities?.some(avail => {
|
||||
return avail.startTime >= filterDate && avail.startTime <= filterDateEnd;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (isExactTime) {
|
||||
// Post filter for time if dayOfMonth is null as we can't only by time for multiple dates in SQL
|
||||
// Modify the availabilities array of the filtered publishers
|
||||
publishers.forEach(pub => {
|
||||
pub.availabilities = pub.availabilities?.filter(avail => matchesAvailability(avail, filterDate));
|
||||
});
|
||||
}
|
||||
|
||||
return publishers;
|
||||
return data.filterPublishersNew(selectFields, filterDate, isExactTime, isForTheMonth, isWithStats);
|
||||
}
|
||||
|
||||
// availabilites filter:
|
||||
|
Reference in New Issue
Block a user