From af87b7d51b491f2ed75da26604b0bd753f516140 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Sat, 13 Apr 2024 18:27:19 +0300 Subject: [PATCH] new coverMe routine; refactoring --- components/publisher/SearchReplacement.js | 147 +++++++++++ next.config.js | 2 +- pages/api/email.ts | 58 +++-- pages/api/index.ts | 286 +++------------------- pages/cart/publishers/myschedule.tsx | 24 +- src/helpers/data.js | 265 +++++++++++++++++++- src/helpers/email.js | 21 +- 7 files changed, 503 insertions(+), 300 deletions(-) create mode 100644 components/publisher/SearchReplacement.js diff --git a/components/publisher/SearchReplacement.js b/components/publisher/SearchReplacement.js new file mode 100644 index 0000000..527cbc0 --- /dev/null +++ b/components/publisher/SearchReplacement.js @@ -0,0 +1,147 @@ +import React, { useState, useEffect } from 'react'; +import axiosInstance from '../../src/axiosSecure'; +import { toast } from 'react-toastify'; +import { set } from 'date-fns'; + +function SearchReplacement({ shiftId, assignmentId }) { + const [users, setUsers] = useState([]); + const [showModal, setShowModal] = useState(false); + + const fetchUsers = async () => { + // Dummy endpoint and shiftId, replace with actual + const response = await axiosInstance.get('/api/?action=getPossibleShiftPublisherEmails&shiftId=' + shiftId); + setUsers(response.data); + setShowModal(true); + }; + + const sendCoverMeRequestByEmail = (selectedGroups) => { + // You can map 'selectedGroups' to determine which API calls to make + console.log("Selected Groups:", selectedGroups); + axiosInstance.post('/api/email?action=sendCoverMeRequestByEmail', { + assignmentId: assignmentId, + toSubscribed: selectedGroups.includes('subscribedPublishers'), + toAvailable: selectedGroups.includes('availablePublishers'), + }).then(response => { + console.log("response", response); + setShowModal(false); + //toast success and confirm the change + toast.success("Заявката за заместник е изпратена!", { + onClose: () => { + window.location.reload(); + } + }); + }).catch(error => { + console.log("error", error); + }); + } + + return ( +
+ + { + showModal && ( + setShowModal(false)} + onConfirm={sendCoverMeRequestByEmail} + subscribedPublishers={users.subscribedPublishers} + availablePublishers={users.availablePublishers} + /> + // setShowModal(false)} + // onConfirm={(selectedUsers) => { + // console.log(selectedUsers); // Here you would call the email API + // setShowModal(false); + // }} + // /> + ) + } +
+ ); +} + +function ConfirmationModal({ isOpen, onClose, onConfirm, subscribedPublishers, availablePublishers }) { + const [selectedGroups, setSelectedGroups] = useState([]); + + const handleToggleGroup = (groupName) => { + setSelectedGroups(prev => { + if (prev.includes(groupName)) { + return prev.filter(name => name !== groupName); + } else { + return [...prev, groupName]; + } + }); + }; + + if (!isOpen) return null; + + return ( +
+
+
+

Можете да изпратите заявка за заместник до следните групи:

+
+ +
+
+ +
+
+ + +
+
+
+ ); + +} + + +export default SearchReplacement; diff --git a/next.config.js b/next.config.js index 87288ce..2406980 100644 --- a/next.config.js +++ b/next.config.js @@ -5,7 +5,7 @@ const withPWA = require('next-pwa')({ register: true, // ? publicExcludes: ["!_error*.js"], //? - disable: process.env.NODE_ENV === 'development', + //disable: process.env.NODE_ENV === 'development', }) module.exports = withPWA({ diff --git a/pages/api/email.ts b/pages/api/email.ts index 9b1b533..9a10ef8 100644 --- a/pages/api/email.ts +++ b/pages/api/email.ts @@ -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" }); diff --git a/pages/api/index.ts b/pages/api/index.ts index 6ce6997..538891d 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -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: diff --git a/pages/cart/publishers/myschedule.tsx b/pages/cart/publishers/myschedule.tsx index bf8a2d5..017b21c 100644 --- a/pages/cart/publishers/myschedule.tsx +++ b/pages/cart/publishers/myschedule.tsx @@ -7,6 +7,7 @@ import common from '../../../src/helpers/common'; import Modal from 'components/Modal'; import ConfirmationModal from 'components/ConfirmationModal'; import PublisherSearchBox from '../../../components/publisher/PublisherSearchBox'; // Update the path +import SearchReplacement from '../../../components/publisher/SearchReplacement'; // Update the path import { monthNamesBG, GetTimeFormat, GetDateFormat } from "../../../src/helpers/const" import { useSession, getSession } from 'next-auth/react'; @@ -52,21 +53,6 @@ export default function MySchedulePage({ assignments }) { }); }; - const searchReplacement = (assignmentId) => { - axiosInstance.post('/api/email?action=sendCoverMeRequestByEmail', { - assignmentId: assignmentId, - }).then(response => { - console.log("response", response); - //toast success and confirm the change - toast.success("Заявката за заместник е изпратена!", { - onClose: () => { - window.location.reload(); - } - }); - }).catch(error => { - console.log("error", error); - }); - } return ( @@ -121,12 +107,8 @@ export default function MySchedulePage({ assignments }) { > Избери Заместник - + + diff --git a/src/helpers/data.js b/src/helpers/data.js index dc39ff2..1cc459b 100644 --- a/src/helpers/data.js +++ b/src/helpers/data.js @@ -226,6 +226,268 @@ async function getAvailabilities(userId) { return serializableItems; } + +async function filterPublishersNew(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, currentWeekEnd, + currentMonthStart, currentMonthEnd, + previousMonthStart, previousMonthEnd; + + 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; + +} + +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; +} + const fs = require('fs'); const path = require('path'); @@ -255,5 +517,6 @@ module.exports = { findPublisher, findPublisherAvailability, runSqlFile, - getAvailabilities + getAvailabilities, + filterPublishersNew }; \ No newline at end of file diff --git a/src/helpers/email.js b/src/helpers/email.js index 1e0f2a1..2e8c9de 100644 --- a/src/helpers/email.js +++ b/src/helpers/email.js @@ -25,22 +25,23 @@ let mailtrapTestClient = null; // password: 'c7bc05f171c96c' // }); -//test +//PROD MAILTRAP var transporter = nodemailer.createTransport({ - host: process.env.MAILERSEND_SERVER, - port: process.env.MAILERSEND_PORT, + host: process.env.MAILTRAP_HOST || "sandbox.smtp.mailtrap.io", + port: 2525, auth: { - user: process.env.MAILERSEND_USER, - pass: process.env.MAILERSEND_PASS + user: process.env.MAILTRAP_USER, + pass: process.env.MAILTRAP_PASS } }); -// production + +//PROD MAILERSEND // var transporter = nodemailer.createTransport({ -// host: "live.smtp.mailtrap.io", -// port: 587, +// host: process.env.MAILERSEND_SERVER, +// port: process.env.MAILERSEND_PORT, // auth: { -// user: "api", -// pass: "1cfe82e747b8dc3390ed08bb16e0f48d" +// user: process.env.MAILERSEND_USER, +// pass: process.env.MAILERSEND_PASS // } // });