added surveys

This commit is contained in:
Dobromir Popov
2024-06-17 15:18:28 +03:00
parent 4da00d4ec3
commit 94597e2440
6 changed files with 453 additions and 310 deletions

View File

@ -1,169 +0,0 @@
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';
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?
}
*/
export default function SurveyForm({ existingItem }) {
const router = useRouter();
const [editMode, setEditMode] = useState(existingItem ? true : false);
const [item, setItem] = useState(existingItem || {
content: "Нова анкета",
answers: [],
publicFrom: new Date().toISOString(),
publicUntil: new Date().toISOString(),
});
useState(() => setEditMode(existingItem ? true : false), [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();
try {
//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",
});
} catch (error) {
//alert("Нещо се обърка при изтриването. Моля, опитайте отново или се свържете с нас");
console.log(JSON.stringify(error));
toast.error(error.response?.data?.message || "Нещо се обърка при изтриването. Моля, опитай отново и се свържете с нас ако проблема продължи.");
}
};
return (
<div className="w-full max-w-md mx-auto" >
< form className="bg-white dark:bg-gray-800 shadow-md rounded px-8 pt-6 pb-8 mb-4" onSubmit={handleSubmit} >
<h1 className="text-2xl font-bold mb-8">Анкета {existingItem?.id}</h1>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="date">
Видима от
</label>
<DatePicker className="textbox form-input px-4 py-2 rounded" id="date" name="date" type="date" onChange={(newDate) => handleDateChange('publicFrom', newDate)} value={dayjs(item.publicFrom)} />
</div>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="date">
Видима до
</label>
<DatePicker className="textbox form-input px-4 py-2 rounded" id="date" name="date" type="date" onChange={(newDate) => handleDateChange('publicUntil', newDate)} value={dayjs(item.publicUntil)} />
</div>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="content">
Съдържание
</label>
<textarea className="textbox form-input px-4 py-2 rounded" id="content" name="content" onChange={handleChange} value={item.content} autoComplete="off" />
</div>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="answers">
Отговори
</label>
<input className="textbox form-input px-4 py-2 rounded" id="answers" name="answers" type="text" onChange={handleChange} value={item.answers} autoComplete="off" />
</div>
{/* show count of each answer and the total answered/unanswered messages */}
{/* {item.answers.map((answer) => (
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="answers">
{answer}
</label>
{item.messages.filter((message) => message.answer === answer).length}
</div>
))} */}
<div className="flex items-center justify-between">
{editMode && (
<><button className="button btn-outline bg-red-500 hover:bg-red-700 focus:outline-none focus:shadow-outline" type="button" onClick={handleDelete}>
Изтрий
</button></>
)}
<button className="btn bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded transition duration-300" type="submit">
Запази
</button>
</div>
</form >
</div >
);
}

View File

@ -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<SurveyFormProps> = ({ 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<HTMLButtonElement, 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 (
<div className="w-full max-w-md mx-auto" >
< form className="bg-white dark:bg-gray-800 shadow-md rounded px-8 pt-6 pb-8 mb-4" onSubmit={handleSubmit} >
<h1 className="text-2xl font-bold mb-8">Анкета {existingItem?.id}</h1>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="date">
Видима от
</label>
<DatePicker className="textbox form-input px-4 py-2 rounded" name="publicFrom" onChange={(newDate) => handleDateChange('publicFrom', newDate)} value={dayjs(item?.publicFrom)} />
</div>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="date">
Видима до
</label>
<DatePicker className="textbox form-input px-4 py-2 rounded" name="publicUntil" onChange={(newDate) => handleDateChange('publicUntil', newDate)} value={dayjs(item?.publicUntil)} />
</div>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="content">
Съдържание
</label>
<textarea className={`textbox form-input px-4 py-2 rounded ${editMode ? 'opacity-50 cursor-not-allowed' : ''}`} id="content" name="content" onChange={handleChange} value={item?.content} autoComplete="off" disabled={editMode} />
</div>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="answers">
Отговори
</label>
<input className={`textbox form-input px-4 py-2 rounded ${editMode ? 'opacity-50 cursor-not-allowed' : ''}`} id="answers" name="answers" type="text" onChange={handleChange} value={item?.answers} autoComplete="off" disabled={editMode}
/>
</div>
{/* show count of each answer and the total answered/unanswered messages */}
{item?.answersCount?.length > 0 && (
<div className="mb-4">
<h3 className="text-lg font-semibold mb-2">Отговори:</h3>
{item.answersCount.map((answer, index) => (
<div key={index} className="mb-2">
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor={`answer-${index}`}>
{answer}
</label>
<p className="text-gray-700">
{item.messages ? item.messages.filter((message) => message.answer === answer).length : 0}
</p>
</div>
))}
<div className="mb-2">
<label className="block text-gray-700 text-sm font-bold mb-2">Общо отговорили</label>
<p className="text-gray-700">{item.messages ? item.messages.filter((message) => message.answer).length : 0}</p>
</div>
<div className="mb-2">
<label className="block text-gray-700 text-sm font-bold mb-2">Общо неотговорили</label>
<p className="text-gray-700">{item.messages ? item.messages.filter((message) => !message.answer).length : 0}</p>
</div>
</div>
)}
<div className="flex items-center justify-between">
{editMode && (<>
<button className="button btn-outline bg-red-500 hover:bg-red-700 focus:outline-none focus:shadow-outline" type="button" onClick={handleDelete}>
Изтрий
</button>
<button className="button btn-outline bg-red-500 hover:bg-red-700 focus:outline-none focus:shadow-outline" type="button" onClick={handleDeleteAnswers}>
Изтрий отговорите
</button>
</>)}
<button className="btn bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded transition duration-300" type="submit">
Запази
</button>
</div>
</form >
</div >
);
}
export default SurveyForm;