new survey page
This commit is contained in:
@ -81,6 +81,7 @@ export default function ReportForm({ shiftId, existingItem, onDone }) {
|
|||||||
};
|
};
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [item.date, existingItem]);
|
}, [item.date, existingItem]);
|
||||||
|
|
||||||
const handleChange = ({ target }) => {
|
const handleChange = ({ target }) => {
|
||||||
setItem({ ...item, [target.name]: target.value });
|
setItem({ ...item, [target.name]: target.value });
|
||||||
};
|
};
|
||||||
|
169
components/survey/SurveyForm.js
Normal file
169
components/survey/SurveyForm.js
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
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 >
|
||||||
|
);
|
||||||
|
}
|
1
package-lock.json
generated
1
package-lock.json
generated
@ -49,6 +49,7 @@
|
|||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"levenshtein-edit-distance": "^3.0.1",
|
"levenshtein-edit-distance": "^3.0.1",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
"mailtrap": "^3.3.0",
|
"mailtrap": "^3.3.0",
|
||||||
"module-alias": "^2.2.3",
|
"module-alias": "^2.2.3",
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"levenshtein-edit-distance": "^3.0.1",
|
"levenshtein-edit-distance": "^3.0.1",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
"mailtrap": "^3.3.0",
|
"mailtrap": "^3.3.0",
|
||||||
"module-alias": "^2.2.3",
|
"module-alias": "^2.2.3",
|
||||||
|
73
pages/cart/surveys/index.tsx
Normal file
73
pages/cart/surveys/index.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import Layout from "../../../components/layout";
|
||||||
|
import { GetServerSideProps } from 'next';
|
||||||
|
import { Location, UserRole } from "@prisma/client";
|
||||||
|
import axiosServer from '../../../src/axiosServer';
|
||||||
|
const common = require('../../../src/helpers/common');
|
||||||
|
// import * as common from '../../../src/helpers/common';
|
||||||
|
import SurveyForm from '../../../components/survey/SurveyForm';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
const SurveyPage = ({ serverSurveys }) => {
|
||||||
|
const [selectedSurvey, setSelectedSurvey] = useState(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<div className="view-location-page max-w-4xl mx-auto my-8">
|
||||||
|
<h1>Survey Page</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
))}
|
||||||
|
<button className='btn' onClick={() => setSelectedSurvey(survey)}>Edit</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<button className='btn' onClick={() => setSelectedSurvey(null)}>New Survey</button>
|
||||||
|
</div>
|
||||||
|
<div className="w-1/2">
|
||||||
|
<h2>Selected Survey</h2>
|
||||||
|
{selectedSurvey && (
|
||||||
|
<div>
|
||||||
|
<h3>{selectedSurvey.title}</h3>
|
||||||
|
<p>{selectedSurvey.description}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<SurveyForm existingItem={selectedSurvey} />
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SurveyPage;
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||||
|
const prisma = common.getPrismaClient();
|
||||||
|
let serverSurveys = await prisma.survey.findMany({
|
||||||
|
where: {
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
messages: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
serverSurveys = common.convertDatesToISOStrings(serverSurveys);
|
||||||
|
|
||||||
|
context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate");
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
serverSurveys: serverSurveys
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -287,10 +287,11 @@ export const getServerSideProps = async (context) => {
|
|||||||
key: "AvailabilityBlockDate"
|
key: "AvailabilityBlockDate"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (blockedDate)
|
|
||||||
blockedDate.value = new Date(blockedDate.value);
|
|
||||||
|
|
||||||
lastPublishedDate = lastPublishedDate > blockedDate.value ? lastPublishedDate : blockedDate.value;
|
if (blockedDate) {
|
||||||
|
blockedDate.value = new Date(blockedDate.value);
|
||||||
|
lastPublishedDate = lastPublishedDate > blockedDate.value ? lastPublishedDate : blockedDate.value;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE `message` DROP FOREIGN KEY `Message_surveyId_fkey`;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE `Message` ADD CONSTRAINT `Message_surveyId_fkey` FOREIGN KEY (`surveyId`) REFERENCES `Survey`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -287,7 +287,7 @@ model Message {
|
|||||||
answer String?
|
answer String?
|
||||||
answerDate DateTime?
|
answerDate DateTime?
|
||||||
|
|
||||||
Survey Survey? @relation(fields: [surveyId], references: [id])
|
Survey Survey? @relation(fields: [surveyId], references: [id], onDelete: Cascade)
|
||||||
surveyId Int?
|
surveyId Int?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user