diff --git a/_doc/ToDo.md b/_doc/ToDo.md index fa13d7e..1bc87ef 100644 --- a/_doc/ToDo.md +++ b/_doc/ToDo.md @@ -259,7 +259,7 @@ in schedule admin - if a publisher is always pair & family is not in the shift - [] fix transport UI [] revise import/export to word [] allow keyman/scheduler role -[] allow blocking of inputs (different from publishing) +[] allow blocking of inputs (different from publishing) TODO: fix to keep previous occurances when repeating evert week [] user - add createdAt field [] FIX insecure logins \ No newline at end of file diff --git a/components/availability/AvailabilityList.js b/components/availability/AvailabilityList.js index 6447c00..0add9e9 100644 --- a/components/availability/AvailabilityList.js +++ b/components/availability/AvailabilityList.js @@ -17,11 +17,22 @@ export default function AvailabilityList({ publisher, showNew }) { const [showAv, setShowAv] = useState(showNew || false); const [selectedItem, setSelectedItem] = useState(null); const [items, setItems] = useState(publisher.availabilities); // Convert items prop to state + const [blockedAvailabilityDate, setBlockedAvailabilityDate] = useState(null); useEffect(() => { console.log('items set to:', items?.map(item => item.id)); }, [items]) + useEffect(() => { + axiosInstance.get(`/api/?action=settings&key=AvailabilityBlockDate`) + .then(({ data }) => { + setBlockedAvailabilityDate(new Date(data.value)); + }) + .catch(error => { + console.error("Error getting blocked date:", error); + }); + }, []); + const toggleAv = () => setShowAv(!showAv); const editAvailability = (item) => { setSelectedItem(item); @@ -72,9 +83,16 @@ export default function AvailabilityList({ publisher, showNew }) { {/* */} - + {(blockedAvailabilityDate && new Date(item.startTime) < blockedAvailabilityDate) ? ( + + ) : ( + + )} + ))} diff --git a/components/calendar/avcalendar.tsx b/components/calendar/avcalendar.tsx index 27b66d9..a829268 100644 --- a/components/calendar/avcalendar.tsx +++ b/components/calendar/avcalendar.tsx @@ -511,7 +511,8 @@ const AvCalendar = ({ publisherId, events, selectedDate, cartEvents, lastPublish <>
{/* достъпности на {publisherId} */} - + {/* having multiple ToastContainers causes double rendering of toasts and all kind of problems */} + {/* */}
{ setItem({ ...item, [target.name]: target.value }); }; diff --git a/components/sidemenuData.js b/components/sidemenuData.js index e884535..fb62d4b 100644 --- a/components/sidemenuData.js +++ b/components/sidemenuData.js @@ -1,5 +1,9 @@ import { UserRole } from "@prisma/client"; +// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +// import { faStar } from '@fortawesome/free-solid-svg-icons'; // Star icon +// import { faClipboardList } from '@fortawesome/free-solid-svg-icons'; // Clipboard icon +import { FaStar } from 'react-icons/fa'; // Import FontAwesome icons const sidemenu = [ @@ -103,6 +107,19 @@ const sidemenu = [ text: "Календар", url: "/cart/calendar", roles: [UserRole.ADMIN, UserRole.POWERUSER], + }, + { + id: "surveys", + // text: "Анкети", + // add new icon before text + // text: "Анкети", + text: ( + + + Анкети + + ), + url: "/cart/surveys", }, { id: "cart-reports", text: "Отчети", diff --git a/components/survey/SurveyForm.tsx b/components/survey/SurveyForm.tsx new file mode 100644 index 0000000..4b6f37d --- /dev/null +++ b/components/survey/SurveyForm.tsx @@ -0,0 +1,233 @@ +import axiosInstance from '../../src/axiosSecure'; +import { useEffect, useState } from "react"; +import { toast } from "react-hot-toast"; +import { useRouter } from "next/router"; +import Link from "next/link"; +import { useSession } from "next-auth/react" +import { MessageType, Message, Survey } from "@prisma/client"; +// import { content } from 'googleapis/build/src/apis/content'; +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; +// import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'; +// import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs' +import dayjs from 'dayjs'; +import { set } from 'lodash'; + +const common = require('src/helpers/common'); + + +// ------------------ ------------------ +// This component is used to create and edit +/* location model: + +model Survey { + id Int @id @default(autoincrement()) + content String + answers Json? + messages Message[] + publicFrom DateTime? + publicUntil DateTime? +} + +model Message { + id Int @id @default(autoincrement()) + publisher Publisher @relation(fields: [publisherId], references: [id]) + publisherId String + date DateTime + content String + isRead Boolean @default(false) + isPublic Boolean @default(false) + type MessageType @default(Email) + publicUntil DateTime? + shownDate DateTime? + answer String? + answerDate DateTime? + + Survey Survey? @relation(fields: [surveyId], references: [id]) + surveyId Int? +} +*/ + +interface SurveyFormProps { + existingItem: Survey | null; +} + +const SurveyForm: React.FC = ({ existingItem }) => { + + const router = useRouter(); + const [editMode, setEditMode] = useState(existingItem ? true : false); + + const [item, setItem] = useState(existingItem || { + ...existingItem, + content: existingItem?.content || "Нова анкета", + answers: existingItem?.answers.split(",") || [], + publicFrom: existingItem?.publicFrom ? dayjs(existingItem.publicFrom).toISOString() : new Date().toISOString(), + publicUntil: existingItem?.publicUntil ? dayjs(existingItem.publicUntil).toISOString() : new Date().toISOString(), + }); + + + useEffect(() => { + let transformedItem = { ...existingItem }; + transformedItem.answersCount = existingItem?.answers.split(",") || []; + setEditMode(existingItem ? true : false); + setItem(transformedItem); + }, [existingItem]); + + + const handleChange = ({ target }) => { + setItem({ ...item, [target.name]: target.value }); + }; + + const handleDateChange = (fieldName, newDate) => { + setItem((prevItem) => ({ + ...prevItem, + [fieldName]: newDate + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + delete item.answersCount; + try { + + if (editMode) { + delete item.messages; + const { data } = await axiosInstance.put(`/api/data/surveys/${existingItem.id}`, item); + toast.success("Анкетата е обновена успешно"); + } + else { + //get all publisherIds and create a message for each + const pubs = await axiosInstance.get("/api/data/publishers"); + const messages = pubs.data.map(pub => { + return { + publisherId: pub.id, + content: JSON.stringify({ message: item.content, options: item.answers }), + date: new Date(), + isPublic: false, + type: MessageType.InApp, + publicUntil: item.publicUntil, + } + }); + item.messages = { create: messages }; + const { data } = await axiosInstance.post("/api/data/surveys", item); + toast.success("Анкетата е създадена успешно"); + } + router.push("/cart/surveys"); + } catch (error) { + toast.error("Възникна грешка при създаването на анкетата"); + console.error("Error creating survey:", error); + } + } + + const handleDelete = async (e) => { + e.preventDefault(); + if (!editMode) return; + try { + await axiosInstance.delete(`/api/data/surveys/${existingItem.id}`); + + toast.success("Записът изтрит", { + position: "bottom-center", + }); + router.push("/cart/surveys"); + + } catch (error) { + //alert("Нещо се обърка при изтриването. Моля, опитайте отново или се свържете с нас"); + console.log(JSON.stringify(error)); + toast.error(error.response?.data?.message || "Нещо се обърка при изтриването. Моля, опитай отново и се свържете с нас ако проблема продължи."); + } + }; + + function handleDeleteAnswers(e: MouseEvent): void { + e.preventDefault(); + if (!editMode) return; + + Promise.all(existingItem.messages.map(message => + axiosInstance.put(`/api/data/messages/${message.id}`, { answer: null }) + )) + .then(() => { + toast.success("Отговорите изтрити", { + position: "bottom-center", + }); + }) + .catch((error) => { + console.log(JSON.stringify(error)); + toast.error(error.response?.data?.message || "Нещо се обърка при изтриването. Моля, опитай отново и се свържете с нас ако проблема продължи."); + }); + } + + return ( +
+ < form className="bg-white dark:bg-gray-800 shadow-md rounded px-8 pt-6 pb-8 mb-4" onSubmit={handleSubmit} > + +

Анкета {existingItem?.id}

+
+ + handleDateChange('publicFrom', newDate)} value={dayjs(item?.publicFrom)} /> +
+
+ + handleDateChange('publicUntil', newDate)} value={dayjs(item?.publicUntil)} /> +
+
+ +