+
{question}
diff --git a/src/features/surveys/managers/createSurveyManager.ts b/src/features/surveys/managers/createSurveyManager.ts
index 97fd4684..4784f0a1 100644
--- a/src/features/surveys/managers/createSurveyManager.ts
+++ b/src/features/surveys/managers/createSurveyManager.ts
@@ -4,9 +4,11 @@ import toast from 'react-hot-toast';
import useCopyToClipboard from 'shared/hooks/useCopyToClipboard';
import useTranslation from 'next-translate/useTranslation';
import { QuestionType } from '@prisma/client';
-import { postFetch } from '../../../../lib/axiosConfig';
+import { postFetch, putFetch } from '../../../../lib/axiosConfig';
import { defaultQuestions } from 'shared/constants/surveysConfig';
import { DRAFT_SURVEY_SESSION_STORAGE } from 'shared/constants/app';
+import { SurveyWithQuestions } from 'types/SurveyWithQuestions';
+import { Question as QuestionDto } from '@prisma/client';
export interface Question {
id: string;
@@ -22,19 +24,32 @@ export interface SurveyOptions {
displayTitle: boolean;
}
-export const useCreateSurveyManager = () => {
- const [title, setTitle] = useState('');
- const [questions, setQuestions] = useState(defaultQuestions);
+export const useCreateSurveyManager = (initialData?: SurveyWithQuestions) => {
+ const [isEditMode] = useState(!!initialData);
+
+ const [title, setTitle] = useState(initialData?.title ?? '');
+
+ const mapQuestionsWithExpanded = (questions?: QuestionDto[]) => {
+ return questions?.map((question) => ({
+ ...question,
+ expanded: false,
+ }));
+ };
+
+ const [questions, setQuestions] = useState(
+ mapQuestionsWithExpanded(initialData?.questions) ?? defaultQuestions
+ );
+ const [surveyOptions, setSurveyOptions] = useState({
+ oneQuestionPerStep: initialData?.oneQuestionPerStep ?? true,
+ displayTitle: initialData?.displayTitle ?? true,
+ });
+
const [error, setError] = useState('');
const [isCreating, setIsCreating] = useState(false);
const [isSubmitted, setIsSubmitted] = useState(false);
const router = useRouter();
const { copy } = useCopyToClipboard();
const { t } = useTranslation('surveyCreate');
- const [surveyOptions, setSurveyOptions] = useState({
- oneQuestionPerStep: true,
- displayTitle: true,
- });
const signInToCreateSurvey = () => {
router.push('/login');
@@ -249,6 +264,40 @@ export const useCreateSurveyManager = () => {
setIsCreating(false);
};
+ const confirmEditSurvey = async () => {
+ if (!isSurveyValid() || !initialData) return;
+
+ setIsCreating(true);
+
+ try {
+ const newSurvey = await putFetch(`/api/survey/${initialData.id}`, {
+ title,
+ oneQuestionPerStep: surveyOptions.oneQuestionPerStep,
+ displayTitle: surveyOptions.displayTitle,
+ questions: questions.map((question) => ({
+ id: question.id,
+ title: question.title,
+ options: question.options,
+ type: question.type,
+ isRequired: question.isRequired,
+ })),
+ });
+
+ await router.push(`/survey/answer/${newSurvey.id}`, undefined, {
+ scroll: false,
+ });
+ } catch (error) {
+ toast.error(t('surveyCreationFailed'));
+ }
+ setIsCreating(false);
+ };
+
+ const discardChanges = () => {
+ router.push(`/survey/answer/${initialData?.id}`, undefined, {
+ scroll: false,
+ });
+ };
+
const reorderQuestion = (startIndex: number, endIndex: number) => {
const newOrderedQuestions = Array.from(questions);
@@ -288,5 +337,8 @@ export const useCreateSurveyManager = () => {
surveyOptions,
updateSurveyOptions,
signInToCreateSurvey,
+ isEditMode,
+ confirmEditSurvey,
+ discardChanges,
};
};
diff --git a/src/layout/Footer/Footer.tsx b/src/layout/Footer/Footer.tsx
index 15b83fa9..ad9f4e07 100644
--- a/src/layout/Footer/Footer.tsx
+++ b/src/layout/Footer/Footer.tsx
@@ -3,7 +3,7 @@ import React from 'react';
export default function Footer() {
return (
);
}
diff --git a/src/pages/api/answer/[id].ts b/src/pages/api/answer/[id].ts
index 1f1b63bf..b8f2c941 100644
--- a/src/pages/api/answer/[id].ts
+++ b/src/pages/api/answer/[id].ts
@@ -7,18 +7,27 @@ interface AnswerData {
answersData: { questionId: string; answer?: string }[];
}
-export async function getSurveyData(surveyId: string) {
- const survey = await prismadb.survey.findUnique({
- where: {
- id: surveyId,
- },
- include: {
- questions: true,
- answers: false,
- },
- });
+export async function getSurveyData(surveyId: string, userId?: string) {
+ try {
+ const survey = await prismadb.survey.findFirst({
+ where: {
+ id: surveyId,
+ userId,
+ },
+ include: {
+ questions: {
+ orderBy: {
+ order: 'asc',
+ },
+ },
+ answers: false,
+ },
+ });
- return survey;
+ return survey;
+ } catch (error) {
+ return null;
+ }
}
const isAnswerDataValid = (answerData: AnswerData) => {
diff --git a/src/pages/api/auth/[...nextauth].ts b/src/pages/api/auth/[...nextauth].ts
index c691c369..b63ab164 100644
--- a/src/pages/api/auth/[...nextauth].ts
+++ b/src/pages/api/auth/[...nextauth].ts
@@ -60,9 +60,20 @@ export const authOptions: NextAuthOptions = {
},
callbacks: {
session: async ({ session, token }) => {
- if (session?.user) {
+ if (session?.user && token.uid) {
+ const isSessionValid = await prismadb.user.findUnique({
+ where: {
+ id: token.uid as string,
+ },
+ });
+
+ if (!isSessionValid) {
+ return Promise.reject(new Error('Session not valid'));
+ }
+
session.user.id = token.uid;
}
+
return session;
},
jwt: async ({ user, token }) => {
diff --git a/src/pages/api/survey/[id].ts b/src/pages/api/survey/[id].ts
index ad0f2f5c..36384ca6 100644
--- a/src/pages/api/survey/[id].ts
+++ b/src/pages/api/survey/[id].ts
@@ -2,6 +2,7 @@ import { NextApiRequest, NextApiResponse } from 'next';
import prismadb from '../../../../lib/prismadb';
import serverAuth from '../../../../lib/serverAuth';
+import { SurveyData, isSurveyValid } from '.';
export enum SurveyActionTypes {
UPDATE_ACTIVE = 'UPDATE_ACTIVE',
@@ -11,26 +12,35 @@ interface SurveyPatchPayloadI {
}
export async function getSurveyWithAnswers(surveyId: string, userId: string) {
- const survey = await prismadb.survey.findFirst({
- where: {
- id: surveyId,
- userId: userId,
- },
- include: {
- questions: true,
- answers: {
- include: {
- answerData: true,
+ try {
+ const survey = await prismadb.survey.findFirst({
+ where: {
+ id: surveyId,
+ userId: userId,
+ },
+ include: {
+ questions: {
+ orderBy: {
+ order: 'asc',
+ },
},
- orderBy: {
- createdAt: 'desc',
+ answers: {
+ include: {
+ answerData: true,
+ },
+ orderBy: {
+ createdAt: 'desc',
+ },
},
},
- },
- });
+ });
- return survey;
+ return survey;
+ } catch (error) {
+ return null;
+ }
}
+
export async function updateSurveyActiveStatus({
surveyId,
isActive,
@@ -46,6 +56,7 @@ export async function updateSurveyActiveStatus({
});
return survey;
}
+
export async function handlePatch(req: NextApiRequest, res: NextApiResponse) {
const surveyId = String(req.query.id);
const { actionType } = req.body as SurveyPatchPayloadI;
@@ -74,6 +85,7 @@ export async function handlePatch(req: NextApiRequest, res: NextApiResponse) {
}
}
}
+
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
@@ -81,6 +93,7 @@ export default async function handler(
try {
const requestMethod = req.method;
const session = await serverAuth(req, res);
+ const userId = session.currentUser.id;
const { id } = req.query;
switch (requestMethod) {
@@ -92,7 +105,6 @@ export default async function handler(
return res.status(200).json(survey);
}
-
case 'DELETE': {
const survey = await prismadb.survey.findFirst({
where: {
@@ -116,6 +128,72 @@ export default async function handler(
case 'PATCH': {
return handlePatch(req, res);
}
+ case 'PUT': {
+ const {
+ title,
+ description,
+ questions,
+ oneQuestionPerStep,
+ displayTitle,
+ } = req.body as SurveyData;
+ if (!isSurveyValid(req.body)) {
+ return res.status(400).end();
+ }
+
+ const surveyFound = await prismadb.survey.findFirst({
+ where: { id: id as string, userId },
+ });
+
+ if (!surveyFound?.id) {
+ return res.status(404).end();
+ }
+
+ const surveyQuestions = await prismadb.question.findMany({
+ where: {
+ surveyId: id as string,
+ },
+ });
+
+ const newQuestions = [];
+
+ surveyQuestions.forEach(async (question) => {
+ const foundQuestionIndex = questions.findIndex(
+ (q) => q.id === question.id
+ );
+
+ if (foundQuestionIndex === -1) return;
+
+ const questionFound = questions[foundQuestionIndex];
+
+ const newQuestion = await prismadb.question.update({
+ where: {
+ id: question.id,
+ },
+ data: {
+ title: questionFound.title,
+ description: questionFound.description,
+ isRequired: questionFound.isRequired,
+ order: foundQuestionIndex,
+ },
+ });
+
+ newQuestions.push(newQuestion);
+ });
+
+ const survey = await prismadb.survey.update({
+ where: {
+ id: id as string,
+ },
+ data: {
+ title,
+ description,
+ oneQuestionPerStep,
+ displayTitle,
+ },
+ });
+
+ return res.status(200).json({ id: survey.id });
+ }
default:
return res.status(405).end();
}
diff --git a/src/pages/api/survey/index.ts b/src/pages/api/survey/index.ts
index b745c206..6dd765df 100644
--- a/src/pages/api/survey/index.ts
+++ b/src/pages/api/survey/index.ts
@@ -11,7 +11,7 @@ import {
MIN_QUESTIONS,
} from 'shared/constants/surveysConfig';
-interface SurveyData {
+export interface SurveyData {
title: string;
description: string;
questions: Question[];
@@ -38,7 +38,7 @@ export async function getAllUserSurveys(userId: string) {
return surveys;
}
-const isSurveyValid = (survey: SurveyData) => {
+export const isSurveyValid = (survey: SurveyData) => {
if (
survey.title.trim() === '' ||
survey.title.length > MAX_TITLE_LENGTH ||
@@ -70,8 +70,13 @@ export default async function handler(
return res.status(200).json({ surveys });
}
case 'POST': {
- const { title, description, questions, oneQuestionPerStep, displayTitle } =
- req.body as SurveyData;
+ const {
+ title,
+ description,
+ questions,
+ oneQuestionPerStep,
+ displayTitle,
+ } = req.body as SurveyData;
if (!isSurveyValid(req.body)) {
return res.status(400).end();
@@ -86,12 +91,13 @@ export default async function handler(
oneQuestionPerStep,
displayTitle,
questions: {
- create: questions.map((question) => ({
+ create: questions.map((question, index) => ({
type: question.type,
title: question.title,
description: question.description,
options: question.options,
isRequired: question.isRequired,
+ order: index,
})),
},
},
diff --git a/src/pages/survey/answer/[surveyId]/index.tsx b/src/pages/survey/answer/[surveyId]/index.tsx
index 6bc476b6..fd935f7d 100644
--- a/src/pages/survey/answer/[surveyId]/index.tsx
+++ b/src/pages/survey/answer/[surveyId]/index.tsx
@@ -1,5 +1,11 @@
-import { RefreshIcon, ShareIcon, TrashIcon } from '@heroicons/react/outline';
import Toggle from 'shared/components/Toggle/Toggle';
+import {
+ PencilIcon,
+ RefreshIcon,
+ ShareIcon,
+ TrashIcon,
+} from '@heroicons/react/outline';
+
import Head from 'next/head';
import withAnimation from 'shared/HOC/withAnimation';
import withProtectedRoute from 'shared/HOC/withProtectedRoute';
@@ -16,6 +22,7 @@ import ResultComponent from 'features/surveys/components/ResultsComponents/Resul
import useModal from 'features/surveys/hooks/useModal';
import DeleteSurveyModal from 'features/surveys/components/DeleteSurveyModal/DeleteSurveyModal';
import ShareSurveyModal from 'features/surveys/components/ShareSurveryModal/ShareSurveyModal';
+import { useRouter } from 'next/router';
export async function getServerSideProps(context: NextPageContext) {
const session = await getSession(context);
@@ -77,6 +84,12 @@ function SurveyResultsPage({
const { t } = useTranslation('surveyAnswer');
+ const router = useRouter();
+
+ const handleEditSurvey = () => {
+ router.push(`/survey/create/${surveyId}`);
+ };
+
return (
<>
@@ -100,6 +113,13 @@ function SurveyResultsPage({
/>
+
}
+ />
)}
diff --git a/src/shared/components/StyledDialog/StyledDialog.tsx b/src/shared/components/StyledDialog/StyledDialog.tsx
index 18eda005..d55c4c1b 100644
--- a/src/shared/components/StyledDialog/StyledDialog.tsx
+++ b/src/shared/components/StyledDialog/StyledDialog.tsx
@@ -50,19 +50,22 @@ export default function StyledDialog({
contentClassName
)}
>
-