Files
mwitnessing/pages/dash.tsx
Dobromir Popov bab62816b0 only use blocked date and no published date for blocking;
allow any date to be selected as block date - not only the end of the month
2024-09-17 23:18:51 +03:00

360 lines
13 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 { useSession } from "next-auth/react"
import { useRouter } from 'next/router';
import React, { useState, useEffect, use } from 'react';
import Layout from "../components/layout"
import { toast } from 'react-toastify';
import AvCalendar from '../components/calendar/avcalendar';
import { getSession } from "next-auth/react";
import common from '../src/helpers/common';
import { Availability, UserRole } from "@prisma/client";
import ProtectedRoute, { serverSideAuth } from "../components/protectedRoute";
import axiosInstance from '../src/axiosSecure';
// const dataHelper = require('../../src/helpers/data');
import dataHelper from '../src/helpers/data';
import { authOptions } from './api/auth/[...nextauth]'
import { getServerSession } from "next-auth/next"
import PublisherSearchBox from '../components/publisher/PublisherSearchBox';
import PublisherInlineForm from '../components/publisher/PublisherInlineForm';
import CartEventForm from "components/cartevent/CartEventForm";
interface IProps {
initialItems: Availability[];
initialUserId: string;
cartEvents: any;
lastPublishedDate: Date;
messages: any;
}
export default function DashboardPage({ initialItems, initialUserId, cartEvents, lastPublishedDate, messages }: IProps) {
const router = useRouter();
const { newLogin } = router.query;
const { data: session } = useSession();
const [userName, setUserName] = useState('');
const [userId, setUserId] = useState(initialUserId);
const [events, setEvents] = useState(initialItems?.map(item => ({
...item,
title: item.name,
date: new Date(item.startTime),
startTime: new Date(item.startTime),
endTime: new Date(item.endTime),
publisherId: item.publisherId,
})));
useEffect(() => {
if (session && userName === '' && session.user.name) {
setUserName(session.user.name);
setUserId(session.user.id);
//handleUserSelection({ id: session.user.id, firstName: session.user.name, lastName: '' });
}
}, [session]);
// MESSAGES
//const [notificationsVisible, setNotificationsVisible] = useState(false);
// useEffect(() => {
// //if (newLogin === 'true')
// {
// // alert("Мили братя, искаме само да ви напомним да ни изпратите вашите предпочитания за юни до 25-то число като използвате меню 'Възможности'. Ако имате проблем, моля пишете ни на 'specialnosvidetelstvanesofia@gmail.com'");
// const currentPath = router.pathname;
// router.replace(currentPath, undefined, { shallow: true }); // Removes the query without affecting the history
// }
// }, []);// show the message every time we load the page
// const [processedMessages, setProcessedMessages] = useState(new Set());
// useEffect(() => {
// if (messages && messages.length > 0) {
// const unprocessedMessages = messages.filter(message => !processedMessages.has(message.id));
// if (unprocessedMessages.length > 0) {
// showMessageToasts(unprocessedMessages);
// setProcessedMessages(new Set([...processedMessages, ...unprocessedMessages.map(msg => msg.id)]));
// }
// }
// }, [messages, processedMessages]);
useEffect(() => {
if (messages && messages.length > 0) {
showMessageToasts(messages);
}
}, [messages]);
const showMessageToasts = (messages) => {
const handleOptionClick = async (messageId, option, toastId) => {
try {
await axiosInstance.put(`/api/data/messages/${messageId}`, { answer: option });
handleClose(toastId);
} catch (error) {
console.error("Error updating message:", error);
toast.error("Error updating message. Please try again.");
}
};
const handleClose = (toastId) => {
toast.dismiss(toastId);
};
messages.forEach((message, messageIndex) => {
const toastId = `message-${message.id}-${messageIndex}`;
const content = (
<div>
<div>{message.content.message}</div>
<div>
{message.content.options?.map((option, index) => (
<button
key={index}
onClick={() => handleOptionClick(message.id, option, toastId)}
className="btn bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded m-1"
>
{option}
</button>
))}
</div>
</div>
);
toast(content, {
toastId,
autoClose: false,
closeButton: true,
onClose: () => handleClose(toastId),
});
});
};
// const showMessageToastNewModal = (messages, handleMessageOptionAnswer) => {
// let currentMessageIndex = 0;
// const showModal = () => {
// if (currentMessageIndex >= messages.length) {
// return; // All messages have been shown
// }
// const message = messages[currentMessageIndex];
// const content = (
// <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
// <div className="bg-white rounded shadow-lg p-4 max-w-lg w-full">
// <div className="text-right">
// <button
// className="text-gray-500 hover:text-gray-700"
// onClick={handleClose}
// >
// &times;
// </button>
// </div>
// <div className="mb-4">{message.content.message}</div>
// <div>
// {message.content.options?.map((option, index) => (
// <button
// key={index}
// onClick={() => handleOptionClick(message.id, option)}
// className="btn bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded m-1"
// >
// {option}
// </button>
// ))}
// </div>
// </div>
// </div>
// );
// toast(content, {
// autoClose: false, // Keep the toast open until manually closed
// closeButton: false,
// onClose: handleClose,
// //className: 'custom-toast', // Optional custom class for additional styling
// });
// };
// const handleOptionClick = async (messageId, option) => {
// try {
// await axiosInstance.put(`/api/data/messages/${messageId}`, { answer: option });
// toast.dismiss();
// currentMessageIndex++;
// showModal();
// } catch (error) {
// console.error("Error updating message:", error);
// toast.error("Error updating message. Please try again.");
// }
// };
// const handleClose = () => {
// toast.dismiss();
// };
// showModal();
// };
// FOR ADMINS ONLY
const handleUserSelection = async (publisher) => {
if (!publisher || publisher.id === undefined) return;
console.log("selecting publisher", publisher.id);
setUserName(publisher.firstName + " " + publisher.lastName);
setUserId(publisher.id);
try {
let events = await axiosInstance.get(`/api/?action=getCalendarEvents&publisherId=${publisher.id}`);
setEvents(events.data);
} catch (error) {
console.error("Error fetching publisher info:", error);
// Handle the error appropriately
}
};
// EXAMPLE USAGE OF ProtectedRoute
ProtectedRoute.IsInRole(UserRole.ADMIN).then(isAdmin => {
if (isAdmin) {
console.log("User is an admin.");
} else {
console.log("User is not an admin.");
}
});
return (
<Layout>
<ProtectedRoute allowedRoles={[UserRole.ADMIN, UserRole.POWERUSER, UserRole.USER, UserRole.EXTERNAL]} deniedMessage="">
<h1 className="pt-2 pb-1 text-xl font-bold text-center">Графика на {userName}</h1>
<ProtectedRoute allowedRoles={[UserRole.ADMIN, UserRole.POWERUSER]} deniedMessage="">
<PublisherSearchBox selectedId={userId} infoText="" onChange={handleUserSelection} />
</ProtectedRoute>
<div className="flex flex-row md:flex-row mt-4 xs:mt-1 space-y-4 md:space-y-0 md:space-x-4 h-[calc(100vh-10rem)]">
<div className="flex-1">
<div className="text-center font-bold pb-3 xs:pb-1">
<PublisherInlineForm publisherId={userId} />
</div>
<AvCalendar publisherId={userId} events={events} selectedDate={new Date()} cartEvents={cartEvents} lastPublishedDate={lastPublishedDate} />
</div>
</div>
</ProtectedRoute>
</Layout>
);
}
export const getServerSideProps = async (context) => {
const auth = await serverSideAuth({
req: context.req,
allowedRoles: [/* ...allowed roles... */]
});
// const session = await getSession(context);
const sessionServer = await getServerSession(context.req, context.res, authOptions)
if (!sessionServer) {
return {
redirect: {
destination: '/auth/signin',
permanent: false,
},
};
}
const role = sessionServer?.user.role;
console.log("server role: " + role);
const userId = sessionServer?.user.id;
var isAdmin = sessionServer?.user.role == UserRole.ADMIN;//role.localeCompare(UserRole.ADMIN) === 0;
var items = await dataHelper.getCalendarEvents(userId, true, true, isAdmin);
// common.convertDatesToISOStrings(items);
//serializable dates
items = items.map(item => {
const updatedItem = {
...item,
startTime: item.startTime.toISOString(),
endTime: item.endTime.toISOString(),
date: item.date.toISOString(),
name: common.getTimeFormatted(item.startTime) + "-" + common.getTimeFormatted(item.endTime)
};
if (updatedItem.shift) {
updatedItem.shift = {
...updatedItem.shift,
startTime: updatedItem.shift.startTime.toISOString(),
endTime: updatedItem.shift.endTime.toISOString()
};
updatedItem.isPublished = updatedItem.shift.isPublished;
}
return updatedItem;
});
// log first availability startTime to verify timezone and UTC conversion
const prisma = common.getPrismaClient();
let cartEvents = await prisma.cartEvent.findMany({
where: {
isActive: true,
},
select: {
id: true,
startTime: true,
endTime: true,
dayofweek: true,
shiftDuration: true,
}
});
cartEvents = common.convertDatesToISOStrings(cartEvents);
let lastPublishedDate = (await prisma.shift.findFirst({
where: {
isPublished: true,
},
select: {
endTime: true,
},
orderBy: {
endTime: 'desc'
}
}))?.endTime || new Date();
let blockedDate = await prisma.settings.findUnique({
where: {
key: "AvailabilityBlockDate"
}
});
if (blockedDate) {
blockedDate.value = new Date(blockedDate.value);
lastPublishedDate = blockedDate.value;
}
let messages = await prisma.message.findMany({
where: {
publisherId: userId,
isPublic: false,
answer: null,
},
include: {
Survey: true,
}
});
messages = messages.filter((message) => {
let now = new Date();
return (!message.Survey.publicFrom || message.Survey.publicFrom <= common.getStartOfDay(now))
&& (!message.Survey.publicUntil || message.Survey.publicUntil >= common.getEndOfDay(now))
});
messages = common.convertDatesToISOStrings(messages);
messages = messages.map(message => {
if (message.content) {
message.content = JSON.parse(message.content);
message.content.options = message.content.options?.split(",");
}
return message;
});
return {
props: {
initialItems: items,
userId: sessionServer?.user.id,
cartEvents: cartEvents,
lastPublishedDate: lastPublishedDate.toISOString(),
messages: messages
},
};
}