diff --git a/.env.test b/.env.test
index 94abc74..38c9d2f 100644
--- a/.env.test
+++ b/.env.test
@@ -17,8 +17,8 @@ AUTH0_ISSUER=https://dev-wkzi658ckibr1amv.us.auth0.com
# GOOGLE_ID=926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com
# GOOGLE_SECRET=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
-EMAIL_SERVICE=mailtrap
-MAILTRAP_HOST_BULK=bulk.smtp.mailtrap.io
-MAILTRAP_HOST=live.smtp.mailtrap.io
-MAILTRAP_USER=api
-MAILTRAP_PASS=1cfe82e747b8dc3390ed08bb16e0f48d
\ No newline at end of file
+# EMAIL_SERVICE=mailtrap
+# MAILTRAP_HOST_BULK=bulk.smtp.mailtrap.io
+# MAILTRAP_HOST=live.smtp.mailtrap.io
+# MAILTRAP_USER=api
+# MAILTRAP_PASS=1cfe82e747b8dc3390ed08bb16e0f48d
\ No newline at end of file
diff --git a/_doc/ToDo.md b/_doc/ToDo.md
index 123edcb..b5f5b1f 100644
--- a/_doc/ToDo.md
+++ b/_doc/ToDo.md
@@ -224,12 +224,12 @@ in schedule admin - if a publisher is always pair & family is not in the shift -
лог ако е изрит потребител.
-last login. pubs.
-otchet - za denq
-делете цонфирм
-статистика - фкс (янка) + posledno vlizane
+[x] OK last login. pubs.
+[x] OK otchet - za denq
+[x] OK - делете цонфирм
+[x] статистика - фкс (янка) + posledno vlizane
-заместник, предпочитание в миналото - да не може.
-Да иска потвърждение преди да заместиш някой
-да не се виждат непубликуваните смени в Моите смени
-да не се виждат старите предпочитания ако не си админ в публишерс
\ No newline at end of file
+[x] OK заместник, предпочитание в миналото - да не може.
+[] Да иска потвърждение преди да заместиш някой
+[] да не се виждат непубликуваните смени в Моите смени
+[] да не се виждат старите предпочитания ако не си админ в публишерс
\ No newline at end of file
diff --git a/components/calendar/avcalendar.tsx b/components/calendar/avcalendar.tsx
index 258463c..13acedd 100644
--- a/components/calendar/avcalendar.tsx
+++ b/components/calendar/avcalendar.tsx
@@ -2,6 +2,8 @@ import React, { useState, useEffect } from 'react';
import { Calendar, momentLocalizer, dateFnsLocalizer } from 'react-big-calendar';
import 'react-big-calendar/lib/css/react-big-calendar.css';
import AvailabilityForm from '../availability/AvailabilityForm';
+import ProtectedRoute from '../protectedRoute';
+import { UserRole } from "@prisma/client";
import common from '../../src/helpers/common';
import { toast } from 'react-toastify';
@@ -16,6 +18,7 @@ import { MdToday } from 'react-icons/md';
import { useSwipeable } from 'react-swipeable';
import axiosInstance from '../../src/axiosSecure';
+
// import { set, format, addDays } from 'date-fns';
// import { isEqual, isSameDay, getHours, getMinutes } from 'date-fns';
import { filter } from 'jszip';
@@ -45,6 +48,8 @@ const messages = {
const AvCalendar = ({ publisherId, events, selectedDate }) => {
+ const isAdmin = ProtectedRoute.IsInRole(UserRole.ADMIN);
+
const [date, setDate] = useState(new Date());
//ToDo: see if we can optimize this
const [evts, setEvents] = useState(events); // Existing events
@@ -211,8 +216,9 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => {
if (!start || !end) return;
//readonly for past dates (ToDo: if not admin)
- if (startdate < new Date() || end < new Date() || startdate > end) return;
-
+ if (!isAdmin) {
+ if (startdate < new Date() || end < new Date() || startdate > end) return;
+ }
// Check if start and end are on the same day
if (startdate.toDateString() !== enddate.toDateString()) {
end = common.setTimeHHmm(startdate, "23:59");
@@ -299,22 +305,22 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => {
}
- if (event.isActive) {
- switch (event.type) {
- case 'assignment':
- // backgroundColor = '#48bb78' // always green-500 as we don't pass isConfirmed correctly
- //backgroundColor = event.isConfirmed ? '#48bb78' : '#f6e05e'; // green-500 and yellow-300 from Tailwind CSS
- break;
- case 'recurring':
- backgroundColor = '#63b3ed'; // blue-300 from Tailwind CSS
- break;
- default: // availability
- //backgroundColor = '#a0aec0'; // gray-400 from Tailwind CSS
- break;
- }
- } else {
- backgroundColor = '#a0aec0'; // Default color for inactive events
+ // if (event.isActive) {
+ switch (event.type) {
+ case 'assignment':
+ backgroundColor = '#48bb78' // always green-500 as we don't pass isConfirmed correctly
+ //backgroundColor = event.isConfirmed ? '#48bb78' : '#f6e05e'; // green-500 and yellow-300 from Tailwind CSS
+ break;
+ case 'recurring':
+ backgroundColor = '#63b3ed'; // blue-300 from Tailwind CSS
+ break;
+ default: // availability
+ //backgroundColor = '#a0aec0'; // gray-400 from Tailwind CSS
+ break;
}
+ // } else {
+ // backgroundColor = '#a0aec0'; // Default color for inactive events
+ // }
return {
style: {
@@ -337,9 +343,7 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => {
const handleMouseLeave = () => setIsHovered(false);
if (currentView !== 'agenda') {
//if event.type is availability show in blue. if it is schedule - green if confirmed, yellow if not confirmed
- //if event is not active - show in gray
- let bgColorClass = 'bg-gray-500'; // Default color for inactive events
- var bgColor = event.isActive ? "" : "bg-gray-500";
+ var bgColor = "";
//ToDo: fix this. maybe we're missing some properties
// if (event.isFromPreviousMonth) {
// // set opacity to 0.5
@@ -354,7 +358,6 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => {
if (event.start !== undefined && event.end !== undefined && event.startTime !== null && event.endTime !== null) {
try {
if (event.type === "recurring") {
- //bgColor = "bg-blue-300";
event.title = common.getTimeFomatted(event.startTime) + " - " + common.getTimeFomatted(event.endTime);
}
else {
diff --git a/components/protectedRoute.tsx b/components/protectedRoute.tsx
index 9a9b88a..4c2adc9 100644
--- a/components/protectedRoute.tsx
+++ b/components/protectedRoute.tsx
@@ -68,3 +68,8 @@ export async function serverSideAuth({ req, allowedRoles }) {
// Return the session if the user is authenticated and has the required role
return { session };
}
+// Static method to check if the user has a specific role
+ProtectedRoute.IsInRole = async (roleName) => {
+ const session = await getSession();
+ return session && session.user && session.user.role === roleName;
+};
\ No newline at end of file
diff --git a/components/publisher/SearchReplacement.js b/components/publisher/SearchReplacement.js
index 527cbc0..5d69bf1 100644
--- a/components/publisher/SearchReplacement.js
+++ b/components/publisher/SearchReplacement.js
@@ -114,7 +114,7 @@ function ConfirmationModal({ isOpen, onClose, onConfirm, subscribedPublishers, a
checked={selectedGroups.includes('availablePublishers')}
onChange={() => handleToggleGroup('availablePublishers')}
/>
- На разположение:
+ На разположение :
{availablePublishers.map(pub => (
diff --git a/pages/api/email.ts b/pages/api/email.ts
index facba07..08f6547 100644
--- a/pages/api/email.ts
+++ b/pages/api/email.ts
@@ -9,6 +9,7 @@ const emailHelper = require('../../src/helpers/email');
const { v4: uuidv4 } = require('uuid');
const CON = require("../../src/helpers/const");
import { EventLogType } from "@prisma/client";
+const logger = require('../../src/logger');
import fs from 'fs';
import path from 'path';
@@ -46,6 +47,7 @@ export default async function handler(req, res) {
});
// Update the user status to accepted
console.log("User: " + publisher.firstName + " " + publisher.lastName + " accepted the CoverMe request");
+ logger.info("" + publisher.firstName + " " + publisher.lastName + " accepted the CoverMe request for shift " + shiftId + " PID: " + req.query.assignmentPID + "");
let assignmentPID = req.query.assignmentPID;
if (!shiftId) {
@@ -245,7 +247,6 @@ export default async function handler(req, res) {
}
}
});
- console.log("User: " + publisher.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
@@ -260,23 +261,35 @@ export default async function handler(req, res) {
}
});
- let subscribedPublishers = [], availablePublishers = [];
- if (toSubscribed) {
- //get all subscribed publisers
- subscribedPublishers = await prisma.publisher.findMany({
- where: {
- isSubscribedToCoverMe: true
- }
- });
+ let targetEmails = await data.getCoverMePublisherEmails(assignment.shift.id);
+ if (!toSubscribed) {
+ targetEmails.subscribedPublishers = [];
+ }
+ if (!toAvailable) {
+ targetEmails.availablePublishers = [];
}
+ // let subscribedPublishers = targetEmails.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);
+
+ // }
+ // use
- 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).
+ let pubsToSend = targetEmails.subscribedPublishers.concat(targetEmails.availablePublishers).
filter((item, index, self) =>
index === self.findIndex((t) => (
t.email === item.email && item.email !== publisher.email//and exclude the user himself
@@ -284,7 +297,7 @@ export default async function handler(req, res) {
);
console.log("Sending CoverMe request to " + pubsToSend.length + " publishers");
- await prisma.eventLog.create({
+ let eventLog = await prisma.eventLog.create({
data: {
date: new Date(),
publisher: { connect: { id: publisher.id } },
@@ -294,6 +307,7 @@ export default async function handler(req, res) {
+ "до: " + pubsToSend.map(p => p.firstName + " " + p.lastName + "<" + p.email + ">").join(", "),
}
});
+ logger.info("User: " + publisher.email + " sent a 'CoverMe' request for his assignment " + assignmentId + " - " + assignment.shift.cartEvent.location.name + " " + assignment.shift.startTime.toISOString() + " to " + pubsToSend.map(p => p.firstName + " " + p.lastName + "<" + p.email + ">").join(", ") + ". EventLogId: " + eventLog.id + "");
//send email to all subscribed publishers
for (let i = 0; i < pubsToSend.length; i++) {
diff --git a/pages/api/index.ts b/pages/api/index.ts
index bcd17ac..adc1129 100644
--- a/pages/api/index.ts
+++ b/pages/api/index.ts
@@ -2,8 +2,9 @@ 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 dataHelper = require('../../src/helpers/data');
const subq = require('../../prisma/bl/subqueries');
+import { addMinutes } from 'date-fns';
import fs from 'fs';
import path from 'path';
@@ -171,7 +172,7 @@ export default async function handler(req, res) {
// 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);
+ let publisher = await dataHelper.findPublisher(filter, req.query.email, req.query.select, getAll);
res.status(200).json(publisher);
break;
@@ -350,41 +351,8 @@ export default async function handler(req, res) {
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 });
+ let data = await dataHelper.getCoverMePublisherEmails(parseInt(req.query.shiftId));
+ res.status(200).json(data);
break;
default:
@@ -464,7 +432,7 @@ export async function getMonthlyStatistics(selectFields, filterDate) {
export async function filterPublishersNew_Available(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isWithStats = true, includeOldAvailabilities = false) {
- return data.filterPublishersNew(selectFields, filterDate, isExactTime, isForTheMonth, isWithStats, includeOldAvailabilities);
+ return dataHelper.filterPublishersNew(selectFields, filterDate, isExactTime, isForTheMonth, false, isWithStats, includeOldAvailabilities);
}
// availabilites filter:
@@ -837,8 +805,48 @@ function matchesAvailability(avail, filterDate) {
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];
+ // let pubs = await filterPublishers("id,firstName,lastName,email".split(","), "", date, assignments, availabilities, date ? true : false, publisherId);
+
+ const prisma = common.getPrismaClient();
+ let publisher = await prisma.publisher.findUnique({
+ where: {
+ id: publisherId
+ },
+ select: {
+ id: true,
+ firstName: true,
+ lastName: true,
+ email: true,
+ availabilities: {
+ select: {
+ id: true,
+ dayOfMonth: true,
+ dayofweek: true,
+ weekOfMonth: true,
+ startTime: true,
+ endTime: true,
+ name: true,
+ isFromPreviousAssignment: true,
+ isFromPreviousMonth: true,
+ repeatWeekly: true,
+ }
+ },
+ assignments: {
+ select: {
+ id: true,
+ shift: {
+ select: {
+ id: true,
+ startTime: true,
+ endTime: true,
+ isPublished: true
+ }
+ }
+ }
+ }
+ }
+ });
+
if (publisher) {
if (availabilities) {
publisher.availabilities?.forEach(item => {
diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx
index 5bbb9ae..0ab474b 100644
--- a/pages/cart/calendar/index.tsx
+++ b/pages/cart/calendar/index.tsx
@@ -603,7 +603,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
message="Това ще изпрати имейли до всички участници за смените им през избрания месец. Сигурни ли сте?"
/>