added surveys
This commit is contained in:
@ -13,39 +13,60 @@ const SurveyPage = ({ serverSurveys }) => {
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="view-location-page max-w-4xl mx-auto my-8">
|
||||
<h1>Survey Page</h1>
|
||||
</div>
|
||||
<div className="max-w-4xl mx-auto my-8 p-4 bg-white shadow-md rounded">
|
||||
<h1 className="text-2xl font-bold mb-4">Анкети</h1>
|
||||
|
||||
<div className="flex flex-row justify-between">
|
||||
<div className="w-1/2">
|
||||
<h2>Surveys</h2>
|
||||
<ul>
|
||||
{serverSurveys.map((survey) => (
|
||||
<li key={survey.id}>
|
||||
{survey.id}: {survey.context}: <br />
|
||||
{Object.entries(_.groupBy(survey.messages, 'answer')).map(([key, items]) => (
|
||||
<div key={key}>
|
||||
{key}: {items.length}
|
||||
<div className="flex flex-row justify-between">
|
||||
<div className="w-1/2 pr-4">
|
||||
<h2 className="text-xl font-semibold mb-4">Списък</h2>
|
||||
<ul className="space-y-4">
|
||||
{serverSurveys.map((survey) => (
|
||||
<li key={survey.id} className="p-4 border rounded bg-gray-50 shadow-sm">
|
||||
<p className="font-medium">{survey.id}: {survey.content}</p>
|
||||
{/* <p className="text-gray-700">{survey.publicFrom} - {survey.publicUntil}</p> */}
|
||||
<p className="mt-2"> [{survey.answers}] </p>
|
||||
<div className="mt-2">
|
||||
{Object.entries(_.groupBy(survey.messages, message => message.answer || "Без отговор")).map(([key, items]) => (
|
||||
<div key={key} className="text-sm text-gray-700">
|
||||
{key}: {items.length}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
<button className='btn' onClick={() => setSelectedSurvey(survey)}>Edit</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<button className='btn' onClick={() => setSelectedSurvey(null)}>New Survey</button>
|
||||
<button
|
||||
className="btn mt-2 bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded"
|
||||
onClick={() => setSelectedSurvey(survey)}
|
||||
>
|
||||
Зареди детайли
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<button
|
||||
className="btn mt-4 bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
|
||||
onClick={() => setSelectedSurvey(null)}
|
||||
>
|
||||
Нова анкета
|
||||
</button>
|
||||
</div>
|
||||
<div className="w-1/2 pl-4">
|
||||
<h2 className="text-xl font-semibold mb-4">Детайли</h2>
|
||||
<SurveyForm existingItem={selectedSurvey} />
|
||||
</div>
|
||||
{/* <div className="w-1/2 pl-4">
|
||||
<h2 className="text-xl font-semibold mb-4">Selected Survey</h2>
|
||||
{selectedSurvey ? (
|
||||
<div className="p-4 border rounded bg-gray-50 shadow-sm">
|
||||
<h3 className="text-lg font-bold">{selectedSurvey.title}</h3>
|
||||
<p className="text-gray-700 mt-2">{selectedSurvey.description}</p>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-gray-700">No survey selected.</p>
|
||||
)}
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="w-1/2">
|
||||
<h2>Selected Survey</h2>
|
||||
{selectedSurvey && (
|
||||
<div>
|
||||
<h3>{selectedSurvey.title}</h3>
|
||||
<p>{selectedSurvey.description}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-8">
|
||||
</div>
|
||||
</div>
|
||||
<SurveyForm existingItem={selectedSurvey} />
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
264
pages/dash.tsx
264
pages/dash.tsx
@ -2,6 +2,7 @@ import { useSession } from "next-auth/react"
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Layout from "../components/layout"
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import AvCalendar from '../components/calendar/avcalendar';
|
||||
import { getSession } from "next-auth/react";
|
||||
@ -25,9 +26,9 @@ interface IProps {
|
||||
initialUserId: string;
|
||||
cartEvents: any;
|
||||
lastPublishedDate: Date;
|
||||
messages: any;
|
||||
}
|
||||
export default function DashboardPage({ initialItems, initialUserId, cartEvents, lastPublishedDate }: IProps) {
|
||||
|
||||
export default function DashboardPage({ initialItems, initialUserId, cartEvents, lastPublishedDate, messages }: IProps) {
|
||||
const router = useRouter();
|
||||
const { newLogin } = router.query;
|
||||
const { data: session } = useSession();
|
||||
@ -51,17 +52,132 @@ export default function DashboardPage({ initialItems, initialUserId, cartEvents,
|
||||
}, [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
|
||||
// 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
|
||||
|
||||
useEffect(() => {
|
||||
if (messages.length > 0) {
|
||||
showMessageToasts(messages);
|
||||
}
|
||||
}, [messages]);
|
||||
|
||||
const showMessageToasts = (messages, handleMessageOptionAnswer) => {
|
||||
const handleOptionClick = async (messageId, option, toastId) => {
|
||||
try {
|
||||
await axiosInstance.put(`/api/data/messages/${messageId}`, { answer: option });
|
||||
toast.dismiss(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-${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, // Keep the toast open until manually closed
|
||||
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}
|
||||
>
|
||||
×
|
||||
</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);
|
||||
@ -107,107 +223,6 @@ export default function DashboardPage({ initialItems, initialUserId, cartEvents,
|
||||
}
|
||||
|
||||
|
||||
// async function getAvailabilities(userId) {
|
||||
// const prismaClient = common.getPrismaClient();
|
||||
// const items = await prismaClient.availability.findMany({
|
||||
// where: {
|
||||
// publisherId: userId,
|
||||
// },
|
||||
// select: {
|
||||
// id: true,
|
||||
// name: true,
|
||||
// isActive: true,
|
||||
// isFromPreviousAssignment: true,
|
||||
// isFromPreviousMonth: true,
|
||||
// dayofweek: true,
|
||||
// dayOfMonth: true,
|
||||
// startTime: true,
|
||||
// endTime: true,
|
||||
// repeatWeekly: true,
|
||||
// endDate: true,
|
||||
// publisher: {
|
||||
// select: {
|
||||
// firstName: true,
|
||||
// lastName: true,
|
||||
// id: true,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// // Convert Date objects to ISO strings
|
||||
// const serializableItems = items.map(item => ({
|
||||
// ...item,
|
||||
// startTime: item.startTime.toISOString(),
|
||||
// endTime: item.endTime.toISOString(),
|
||||
// name: common.getTimeFormatted(item.startTime) + "-" + common.getTimeFormatted(item.endTime),
|
||||
// //endDate can be null
|
||||
// endDate: item.endDate ? item.endDate.toISOString() : null,
|
||||
// type: 'availability',
|
||||
// // Convert other Date fields similarly if they exist
|
||||
// }));
|
||||
|
||||
// /*model Assignment {
|
||||
// id Int @id @default(autoincrement())
|
||||
// shift Shift @relation(fields: [shiftId], references: [id], onDelete: Cascade)
|
||||
// shiftId Int
|
||||
// publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade)
|
||||
// publisherId String
|
||||
// isActive Boolean @default(true)
|
||||
// isConfirmed Boolean @default(false)
|
||||
// isWithTransport Boolean @default(false)
|
||||
// Report Report[]
|
||||
// }*/
|
||||
// //get assignments for this user
|
||||
// const assignments = await prismaClient.assignment.findMany({
|
||||
// where: {
|
||||
// publisherId: userId,
|
||||
// },
|
||||
// select: {
|
||||
// id: true,
|
||||
// isBySystem: true,
|
||||
// isConfirmed: true,
|
||||
// isWithTransport: true,
|
||||
// shift: {
|
||||
// select: {
|
||||
// id: true,
|
||||
// name: true,
|
||||
// startTime: true,
|
||||
// endTime: true,
|
||||
// //select all assigned publishers names as name - comma separated
|
||||
// assignments: {
|
||||
// select: {
|
||||
// publisher: {
|
||||
// select: {
|
||||
// firstName: true,
|
||||
// lastName: true,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// const serializableAssignments = assignments.map(item => ({
|
||||
// ...item,
|
||||
// startTime: item.shift.startTime.toISOString(),
|
||||
// endTime: item.shift.endTime.toISOString(),
|
||||
// // name: item.shift.publishers.map(p => p.firstName + " " + p.lastName).join(", "),
|
||||
// //name: item.shift.assignments.map(a => a.publisher.firstName[0] + " " + a.publisher.lastName).join(", "),
|
||||
// name: common.getTimeFormatted(new Date(item.shift.startTime)) + "-" + common.getTimeFormatted(new Date(item.shift.endTime)),
|
||||
// type: 'assignment',
|
||||
// //delete shift object
|
||||
// shift: null,
|
||||
// publisher: { id: userId }
|
||||
// }));
|
||||
|
||||
// serializableItems.push(...serializableAssignments);
|
||||
|
||||
// return serializableItems;
|
||||
|
||||
// }
|
||||
|
||||
export const getServerSideProps = async (context) => {
|
||||
const auth = await serverSideAuth({
|
||||
req: context.req,
|
||||
@ -293,13 +308,38 @@ export const getServerSideProps = async (context) => {
|
||||
lastPublishedDate = lastPublishedDate > 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) => {
|
||||
return (!message.Survey.publicFrom || message.Survey.publicFrom >= common.getStartOfDay(new Date()))
|
||||
&& (!message.Survey.publicUntil || message.Survey.publicUntil <= common.getEndOfDay(new Date()))
|
||||
});
|
||||
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: (await import(`../content/i18n/${context.locale}.json`)).default
|
||||
messages: messages
|
||||
},
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user