Commit be1ba639 authored by Yoon, Daeki's avatar Yoon, Daeki 😅
Browse files

result, answer 로직 및 불필요한 폴더 파일 삭제

parent e7ae6d3f
export { Accordion } from "./Accordion";
import React from "react";
import { useNavigate } from "react-router-dom";
export const CompleteSurvey = () => {
const navigate = useNavigate();
return (
<div className="flex flex-col place-items-center mt-24">
<div className="flex flex-col container place-items-center place-content-center space-y-5 space-x-2 w-full h-56">
<p className="text-3xl font-bold">설문조사가 제출되었습니다</p>
<p>응답이 완료되었습니다</p>
<button
className="flex place-content-start rounded-lg bg-themeColor w-20 h-10 text-center py-2 px-4 text-white"
type="button"
onClick={() => navigate("/")}
>
홈으로
</button>
</div>
</div>
);
};
import React, { FormEvent, useEffect, useState } from "react";
import { useParams, useLocation, useNavigate } from "react-router-dom";
import { questionApi, surveyApi } from "../apis";
import { SpinnerIcon } from "../icons";
import { Question } from "../questions";
import { IQuestionData, ISurvey } from "../types";
import { catchErrors } from "../helpers";
export const CreateSurvey = () => {
let { surveyId } = useParams<{ surveyId: string }>();
const [isEditing, setIsEditing] =
useState<{ qid: string; isEditing: boolean }[]>();
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const navigate = useNavigate();
const [survey, setSurvey] = useState<ISurvey>({
_id: surveyId || "",
user: {},
title: "",
comment: "",
questions: [],
});
useEffect(() => {
getSurvey();
}, [surveyId]);
async function getSurvey() {
try {
if (surveyId) {
const thisSurvey: ISurvey = await surveyApi.getSurvey(surveyId);
const initEditing = thisSurvey.questions.map((question) => {
return { qid: question._id, isEditing: false };
});
// console.log("init editing", initEditing);
setIsEditing(initEditing);
setSurvey(thisSurvey);
setSuccess(true);
setError("");
} else {
setLoading(true);
}
} catch (error) {
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
const handleEditing = (qid: string, edited: boolean) => {
console.log("handle editing:", qid, edited);
if (isEditing) {
const index = isEditing.findIndex((q) => q.qid === qid);
isEditing[index].isEditing = edited;
setIsEditing([...isEditing]);
}
};
const handleQuestion = (element: IQuestionData) => {
const index = survey.questions.findIndex(
(question) => question._id === element._id
);
survey.questions[index] = element;
const newList = [...survey.questions];
console.log("new list in handle question", newList);
setSurvey({ ...survey, questions: newList });
};
const handleSurvey = (event: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.currentTarget;
setSurvey({ ...survey, [name]: value });
};
async function handleSubmit(event: FormEvent) {
event.preventDefault();
const notEditComplete = isEditing?.find((el) => el.isEditing);
if (notEditComplete) {
alert("아직 수정이 완료되지 않은 질문이 존재합니다.");
} else {
try {
const newSurvey: ISurvey = await surveyApi.editSurvey(survey);
console.log(newSurvey);
setSuccess(true);
alert("저장되었습니다");
navigate("/profile");
setError("");
} catch (error) {
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
}
async function addQuestion() {
try {
if (surveyId) {
// const questions: BasicQuestionType[] = await questionApi.createQuestion(
// surveyId
// );
// console.log(questions);
const question: IQuestionData = await questionApi.createQuestion(
surveyId
);
console.log(question);
isEditing &&
setIsEditing([...isEditing, { qid: question._id, isEditing: true }]);
// setSurvey({ ...survey, questions: questions });
setSurvey({ ...survey, questions: [...questions, question] });
setSuccess(true);
setError("");
} else {
setLoading(true);
}
} catch (error) {
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
async function deleteQuestion(id: string) {
const newList: IQuestionData[] = [...survey.questions];
try {
const newQuestion: IQuestionData = await questionApi.deleteQuestion(id);
setSurvey({ ...survey, questions: newList.filter((a) => a._id !== id) });
setSuccess(true);
setError("");
} catch (error) {
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
const questions = survey.questions;
// console.log(questions);
return (
<>
{error ? alert(error) : <></>}
{loading && (
<SpinnerIcon className="animate-spin h-5 w-5 mr-1 text-slate" />
)}
<form onSubmit={handleSubmit}>
<div className="flex flex-col place-items-center">
<div className="flex flex-col container place-items-center mt-4">
<input
type="text"
name="title"
className="font-bold text-4xl text-center m-2 border-b-2"
placeholder="설문지 제목"
value={survey.title}
onChange={handleSurvey}
></input>
<input
type="text"
name="comment"
className="font-bold text-1xl text-center m-2 border-b-2 resize-none"
placeholder="설문조사에 대한 설명을 입력해주세요"
size={50}
value={survey.comment}
onChange={handleSurvey}
></input>
</div>
{questions.map((question) => (
<Question
key={question._id}
element={question}
isEditing={
isEditing?.filter((q) => q.qid === question._id)[0]
?.isEditing ?? true
}
handleEditing={handleEditing}
handleQuestion={handleQuestion}
deleteQuestion={deleteQuestion}
/>
))}
<div className="flex w-4/5 content-center justify-center border-2 border-black h-8 mt-3">
<button type="button" onClick={addQuestion}>
질문 추가
</button>
</div>
<div>
<button
type="submit"
className="border bg-themeColor my-5 py-2 px-3 font-bold text-white"
>
저장하기
</button>
</div>
</div>
</form>
</>
);
};
import React from "react";
import { NavLink } from "react-router-dom";
import { Outlet, useNavigate, useParams } from "react-router-dom";
export const EditResultButton = () => {
let { surveyId } = useParams<{ surveyId: string }>();
const navigate = useNavigate();
return (
<div>
<div className="flex place-content-center mt-6">
<NavLink
to={`/surveys/${surveyId}/edit`}
style={({ isActive }) =>
isActive
? {
width: "140px",
color: "white",
backgroundColor: "#008080",
borderTopLeftRadius: "25px",
borderBottomLeftRadius: "25px",
textAlign: "center",
fontWeight: "bold",
fontSize: "20px",
}
: {
width: "140px",
borderWidth: "1px",
borderColor: "#008080",
borderTopLeftRadius: "25px",
borderBottomLeftRadius: "25px",
textAlign: "center",
fontSize: "18px",
}
}
>
<div className="m-3 ">설문지 수정</div>
</NavLink>
<NavLink
to={`/surveys/${surveyId}/result`}
style={({ isActive }) =>
isActive
? {
width: "140px",
color: "white",
backgroundColor: "#008080",
borderTopRightRadius: "25px",
borderBottomRightRadius: "25px",
textAlign: "center",
fontWeight: "bold",
fontSize: "20px",
}
: {
width: "140px",
borderWidth: "1px",
borderColor: "#008080",
borderTopRightRadius: "25px",
borderBottomRightRadius: "25px",
textAlign: "center",
fontSize: "18px",
}
}
>
<div className="m-3">응답결과</div>
</NavLink>
</div>
<Outlet />
</div>
);
};
import React, { FormEvent, useEffect, useState } from "react";
import { useParams, useLocation, useNavigate } from "react-router-dom";
import { questionApi, surveyApi } from "../apis";
import { SpinnerIcon } from "../icons";
import { Question } from "../questions";
import { IQuestionData, ISurvey } from "../types";
import { catchErrors } from "../helpers";
export const EditSurvey = () => {
let { surveyId } = useParams<{ surveyId: string }>();
interface CustomizedState {
save: boolean;
}
const [isEditing, setIsEditing] =
useState<{ qid: string; isEditing: boolean }[]>();
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const navigate = useNavigate();
const [survey, setSurvey] = useState<ISurvey>({
_id: surveyId || "",
user: {},
title: "",
comment: "",
questions: [],
});
useEffect(() => {
getSurvey();
}, [surveyId]);
async function getSurvey() {
try {
if (surveyId) {
const thisSurvey: ISurvey = await surveyApi.getSurvey(surveyId);
const initEditing = thisSurvey.questions.map((question) => {
return { qid: question._id, isEditing: false };
});
// console.log("init editing", initEditing);
setIsEditing(initEditing);
setSurvey(thisSurvey);
setSuccess(true);
setError("");
} else {
setLoading(true);
}
} catch (error) {
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
const handleEditing = (qid: string, edited: boolean) => {
console.log("handle editing:", qid, edited);
if (isEditing) {
const index = isEditing.findIndex((q) => q.qid === qid);
isEditing[index].isEditing = edited;
setIsEditing([...isEditing]);
}
};
const handleQuestion = (element: IQuestionData) => {
const index = survey.questions.findIndex(
(question) => question._id === element._id
);
survey.questions[index] = element;
const newList = [...survey.questions];
console.log("new list in handle question", newList);
setSurvey({ ...survey, questions: newList });
};
const handleSurvey = (event: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.currentTarget;
setSurvey({ ...survey, [name]: value });
};
async function handleSubmit(event: FormEvent) {
event.preventDefault();
const notEditComplete = isEditing?.find((el) => el.isEditing);
if (notEditComplete) {
alert("아직 수정이 완료되지 않은 질문이 존재합니다.");
} else {
try {
const newSurvey: ISurvey = await surveyApi.editSurvey(survey);
console.log(newSurvey);
setSuccess(true);
alert("저장되었습니다");
navigate("/profile");
setError("");
} catch (error) {
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
}
async function addQuestion() {
try {
if (surveyId) {
// const questions: BasicQuestionType[] = await questionApi.createQuestion(
// surveyId
// );
// console.log(questions);
const question: IQuestionData = await questionApi.createQuestion(
surveyId
);
console.log(question);
// const addedEditing = questions.map((question) => {
// return { qid: question._id, isEditing: false };
// });
// console.log("added editing", addedEditing);
isEditing &&
setIsEditing([...isEditing, { qid: question._id, isEditing: true }]);
// setSurvey({ ...survey, questions: questions });
setSurvey({ ...survey, questions: [...questions, question] });
setSuccess(true);
setError("");
} else {
setLoading(true);
}
} catch (error) {
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
async function deleteQuestion(id: string) {
const newList: IQuestionData[] = [...survey.questions];
try {
const newQuestion: IQuestionData = await questionApi.deleteQuestion(id);
setSurvey({ ...survey, questions: newList.filter((a) => a._id !== id) });
setSuccess(true);
setError("");
} catch (error) {
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
const questions = survey.questions;
// console.log(questions);
// console.log("isediting", isEditing);
return (
<>
{error ? alert(error) : <></>}
{loading && (
<SpinnerIcon className="animate-spin h-5 w-5 mr-1 text-slate" />
)}
<form onSubmit={handleSubmit}>
<div className="flex flex-col place-items-center">
<div className="flex flex-col container place-items-center mt-4">
<input
type="text"
name="title"
className="font-bold text-4xl text-center m-2 border-b-2"
placeholder="설문지 제목"
value={survey.title}
onChange={handleSurvey}
></input>
<input
type="text"
name="comment"
className="font-bold text-1xl text-center m-2 border-b-2 resize-none"
placeholder="설문조사에 대한 설명을 입력해주세요"
size={50}
value={survey.comment}
onChange={handleSurvey}
></input>
</div>
{questions.map((question) => (
<Question
key={question._id}
element={question}
isEditing={
isEditing?.filter((q) => q.qid === question._id)[0]
?.isEditing ?? false
}
handleEditing={handleEditing}
handleQuestion={handleQuestion}
deleteQuestion={deleteQuestion}
/>
))}
<div className="flex w-4/5 content-center justify-center border-2 border-themeColor2 border-addQuestionColor h-8 mt-3 rounded-lg ">
<button type="button" onClick={addQuestion}>
질문 추가
</button>
</div>
<div>
<button
type="submit"
className="border bg-themeColor my-5 py-2 px-3 font-bold text-white"
>
저장하기
</button>
</div>
</div>
</form>
</>
);
};
import React from "react";
import { useNavigate } from "react-router-dom";
export const SameSurvey = () => {
const navigate = useNavigate();
return (
<div className="flex flex-col place-items-center mt-24">
<div className="flex flex-col container place-items-center place-content-center space-y-5 space-x-2 w-full h-56">
<p className="text-3xl font-bold px-3">이미 제출된 설문조사입니다</p>
<button
className="flex place-content-start rounded-lg bg-themeColor w-20 h-10 text-center py-2 px-4 text-white"
type="button"
onClick={() => navigate("/")}
>
홈으로
</button>
</div>
</div>
);
};
export { EditResultButton } from "./EditResultButton";
import React from "react";
import { IQuestionData, IAnswer } from "../types";
import { getAnswerElementByType } from "../helpers";
type Props = {
question: IQuestionData;
answer: IAnswer;
};
export const AQuestion = ({ question, answer }: Props) => {
return (
<div className="flex flex-col container w-4/5 h-auto border-2 border-themeColor items-center m-3 py-4 rounded-lg">
<div className="flex my-1 w-11/12 place-content-between items-center">
<div className="text-xl font-bold">{question.title}</div>
{question.isRequired ? (
<div className="text-xs text-red-600">* 필수질문</div>
) : (
<></>
)}
</div>
<div className="w-11/12 text-slate-500">{question.comment}</div>
{getAnswerElementByType(question, answer)}
</div>
);
};
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
import { IQuestionData } from "../types"; import { IQuestionData } from "../types";
import { REssayForm } from "./REssayForm"; // import {
import { RCheckboxForm } from "./RCheckboxForm"; // REssay,
import { RRadioForm } from "./RRadioForm"; // RCheckbox,
import { RDropdownForm } from "./RDropdownForm"; // RRadio,
import { RFileForm } from "./RFileForm"; // RDropdown,
import { RRatingForm } from "./RRatingForm"; // RFile,
import { RDateForm } from "./RDateForm"; // RRating,
// RDate,
// } from "../forms";
import { getResultElementByType } from "../helpers/question.helper";
type AccordionProps = { type AccordionProps = {
question: IQuestionData; question: IQuestionData;
...@@ -21,26 +24,26 @@ export const Accordion = ({ question }: AccordionProps) => { ...@@ -21,26 +24,26 @@ export const Accordion = ({ question }: AccordionProps) => {
setOpened(!isOpened); setOpened(!isOpened);
setHeight(!isOpened ? `${contentElement.current?.scrollHeight}px` : "0px"); setHeight(!isOpened ? `${contentElement.current?.scrollHeight}px` : "0px");
}; };
function getContent(question: IQuestionData) { // function getContent(question: IQuestionData) {
switch (question.type) { // switch (question.type) {
case "essay": // case "singletext":
return <REssayForm question={question} />; // return <REssay question={question} />;
case "radio": // case "radio":
return <RRadioForm question={question} />; // return <RRadio question={question} />;
case "checkbox": // case "checkbox":
return <RCheckboxForm question={question} />; // return <RCheckbox question={question} />;
case "dropdown": // case "dropdown":
return <RDropdownForm question={question} />; // return <RDropdown question={question} />;
case "file": // case "file":
return <RFileForm question={question} />; // return <RFile question={question} />;
case "rating": // case "rating":
return <RRatingForm question={question} />; // return <RRating question={question} />;
case "date": // case "date":
return <RDateForm question={question} />; // return <RDate question={question} />;
default: // default:
return <></>; // return <></>;
} // }
} // }
// console.log(question); // console.log(question);
...@@ -60,7 +63,7 @@ export const Accordion = ({ question }: AccordionProps) => { ...@@ -60,7 +63,7 @@ export const Accordion = ({ question }: AccordionProps) => {
style={{ height: height }} style={{ height: height }}
className="bg-gray-100 overflow-hidden transition-all duration-300" className="bg-gray-100 overflow-hidden transition-all duration-300"
> >
{question.answers && getContent(question)} {question.answers && getResultElementByType(question)}
</div> </div>
</div> </div>
</div> </div>
......
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { answerApi, surveyApi } from "../apis"; import { answerApi, surveyApi } from "../apis";
import { catchErrors } from "../helpers"; import { catchErrors } from "../helpers";
import { Accordion } from "../results"; import { Accordion } from "./Accordion";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { ISurvey } from "../types"; import { ISurvey } from "../types";
......
...@@ -3,3 +3,4 @@ export { CreateSurvey } from "./CreateSurvey"; ...@@ -3,3 +3,4 @@ export { CreateSurvey } from "./CreateSurvey";
export { EditSurvey } from "./EditSurvey"; export { EditSurvey } from "./EditSurvey";
export { Preview } from "./Preview"; export { Preview } from "./Preview";
export { Profile } from "./Profile"; export { Profile } from "./Profile";
export { ResultSurvey } from "./ResultSurvey";
import { QUESTION_TYPES } from "../commons";
// 타입 지정
export interface IUser { export interface IUser {
email?: string; email?: string;
isLoggedIn: boolean; isLoggedIn: boolean;
...@@ -11,7 +14,7 @@ export interface SignupUser { ...@@ -11,7 +14,7 @@ export interface SignupUser {
} }
export interface ISurvey { export interface ISurvey {
_id: string; _id?: string;
user: any; user: any;
title: string; title: string;
comment: string; comment: string;
...@@ -33,7 +36,7 @@ interface IBasicContent { ...@@ -33,7 +36,7 @@ interface IBasicContent {
export interface IQuestionData { export interface IQuestionData {
_id?: string; _id?: string;
order: number; order: number;
type: string; type: IQuestionType;
title: string; title: string;
isRequired: boolean; isRequired: boolean;
comment: string; comment: string;
...@@ -42,13 +45,8 @@ export interface IQuestionData { ...@@ -42,13 +45,8 @@ export interface IQuestionData {
[key: string]: string | number | boolean | any; [key: string]: string | number | boolean | any;
} }
export interface AnswerQuestionType extends IQuestionData { export interface CreateQuestionData extends IQuestionData {
requiredCheck: boolean; isEditing: boolean;
answer: any;
}
export interface AnswerSurveyType extends ISurvey {
questions: AnswerQuestionType[];
} }
export interface IEssay extends IQuestionData {} export interface IEssay extends IQuestionData {}
...@@ -60,11 +58,6 @@ export interface IRadio extends IQuestionData { ...@@ -60,11 +58,6 @@ export interface IRadio extends IQuestionData {
}; };
} }
interface IChoices {
value: number;
text: string;
}
export interface ICheckbox extends IQuestionData { export interface ICheckbox extends IQuestionData {
content: IBasicContent & { maxCount: number }; content: IBasicContent & { maxCount: number };
} }
...@@ -87,21 +80,55 @@ export interface IRating extends IQuestionData { ...@@ -87,21 +80,55 @@ export interface IRating extends IQuestionData {
}; };
} }
export interface AnswersType { export interface IAnswer {
questionId: string; question: IQuestionData;
type: string; surveyId: string;
answer: any; guestId?: string;
requiredCheck: boolean;
content: any;
} }
export interface AnswerType { export interface IAnswerRequestData {
questionId: string;
surveyId: string; surveyId: string;
guestId: string; guestId?: string;
answers: AnswersType[]; content: any;
} }
export interface AnswerProps { // export interface IAnswerSurvey extends ISurvey {
// questions: IAnswerQuestion[];
// }
// export interface IAnswers {
// questionId: string;
// type: string;
// content: any;
// }
// export interface IAnswer {
// surveyId: string;
// guestId: string;
// answers: IAnswers[];
// }
export interface IAnswerProps {
element: IQuestionData; element: IQuestionData;
answerQuestion: AnswerQuestionType; answer: IAnswer;
// answers: AnswersType | undefined; // answers: AnswersType | undefined;
// handleAnswer: () => void; // handleAnswer: () => void;
} }
export interface IQuestionProps {
element: CreateQuestionData;
// isEditing: boolean;
// handleEditing: Function;
handleQuestion: Function;
deleteQuestion: Function;
}
export type IQuestionFormProps = Pick<
IQuestionProps,
"element" | "handleQuestion"
> & { isEditing: boolean };
export type IQuestionType = keyof typeof QUESTION_TYPES;
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */ /* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"jsx": "react", /* Specify what JSX code is generated. */ "jsx": "react", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
......
import { NextFunction, Request, Response } from "express"; import { NextFunction, Request, Response } from "express";
import { asyncWrap, isEmpty } from "../helpers"; import { asyncWrap, formidableFilesToArray, isEmpty } from "../helpers";
import { TypedRequest } from "../types"; import type { TypedRequest } from "../types";
import formidable from "formidable"; import formidable from "formidable";
import { FileInfo } from "../models"; import { FileInfo, IAnswer } from "../models";
import { fileDb, userDb, answerDb, surveyDb } from "../db"; import { fileDb, userDb, answerDb, surveyDb } from "../db";
import fs from "fs/promises"; import fs from "fs/promises";
export const createAnswers = asyncWrap(async (reqExp, res) => { export const createAnswers = asyncWrap(async (reqExp, res) => {
const req = reqExp as TypedRequest; const req = reqExp as TypedRequest;
const answer = req.body; const answer = req.body;
console.log("answer in create answers:", answer);
const answers = JSON.parse(answer.answers); const answers = JSON.parse(answer.answers);
answer.answers = answers; answer.answers = answers;
let files: any[] = []; let files: any[] = [];
...@@ -47,7 +48,7 @@ export const createAnswers = asyncWrap(async (reqExp, res) => { ...@@ -47,7 +48,7 @@ export const createAnswers = asyncWrap(async (reqExp, res) => {
surveyId: answer.surveyId, surveyId: answer.surveyId,
guestId: answer.guestId, guestId: answer.guestId,
questionId: element.questionId, questionId: element.questionId,
answer: element.answer, content: element.answer,
}); });
}); });
await Promise.all(c); await Promise.all(c);
...@@ -63,6 +64,45 @@ export const createAnswers = asyncWrap(async (reqExp, res) => { ...@@ -63,6 +64,45 @@ export const createAnswers = asyncWrap(async (reqExp, res) => {
} }
}); });
export const createAnswersWithoutFile = asyncWrap(async (req, res) => {
const answers = req.body as IAnswer[];
const newAnswers = await Promise.all(
answers.map(
async (answer) =>
await answerDb.createAnswer({
surveyId: answer.surveyId,
guestId: answer.guestId,
questionId: answer.questionId,
content: answer.content,
})
)
);
console.log("new answers:", newAnswers);
res.json(newAnswers);
});
export const createAnswerWithFile = asyncWrap(async (reqExp, res) => {
const req = reqExp as TypedRequest;
console.log("body:", req.body, "files:", req.files);
const answer = req.body;
let fileInfos;
const files = formidableFilesToArray(req.files.uploadFiles);
if (files) {
fileInfos = await Promise.all(
files.map(async (file) => await fileDb.createFile(file))
);
}
answer.content = fileInfos;
const newAnswer = await answerDb.createAnswer(answer);
console.log("new answer:", newAnswer);
res.json(newAnswer);
});
export const getAnswers = asyncWrap(async (reqExp, res) => { export const getAnswers = asyncWrap(async (reqExp, res) => {
const req = reqExp as TypedRequest; const req = reqExp as TypedRequest;
const { surveyId } = req.params; const { surveyId } = req.params;
......
...@@ -12,7 +12,7 @@ export const getAnswers = async (surveyId: string) => { ...@@ -12,7 +12,7 @@ export const getAnswers = async (surveyId: string) => {
{ {
$group: { $group: {
_id: "$questionId", _id: "$questionId",
answers: { $push: "$answer" }, answers: { $push: "$content" },
}, },
}, },
{ {
......
import type { File } from "formidable";
export { asyncWrap } from "./asyncWrap"; export { asyncWrap } from "./asyncWrap";
export const isEmpty = (obj: any) => { export const isEmpty = (obj: any) => {
...@@ -7,3 +9,13 @@ export const isEmpty = (obj: any) => { ...@@ -7,3 +9,13 @@ export const isEmpty = (obj: any) => {
Object.getPrototypeOf(obj) === Object.prototype Object.getPrototypeOf(obj) === Object.prototype
); );
}; };
export const formidableFilesToArray = (files: File | File[]): File[] | null => {
if (Array.isArray(files)) {
return files;
}
if (isEmpty(files)) {
return null;
}
return [files];
};
...@@ -5,7 +5,7 @@ export interface IAnswer { ...@@ -5,7 +5,7 @@ export interface IAnswer {
surveyId?: Types.ObjectId; surveyId?: Types.ObjectId;
questionId?: Types.ObjectId; questionId?: Types.ObjectId;
guestId?: string; guestId?: string;
answer?: any; content?: any;
} }
const schema = new Schema<IAnswer>( const schema = new Schema<IAnswer>(
...@@ -13,7 +13,7 @@ const schema = new Schema<IAnswer>( ...@@ -13,7 +13,7 @@ const schema = new Schema<IAnswer>(
surveyId: { type: Schema.Types.ObjectId, ref: "Survey" }, surveyId: { type: Schema.Types.ObjectId, ref: "Survey" },
questionId: { type: Schema.Types.ObjectId, ref: "Question" }, questionId: { type: Schema.Types.ObjectId, ref: "Question" },
guestId: { type: String }, guestId: { type: String },
answer: { type: Object }, content: { type: Object },
}, },
{ timestamps: true } { timestamps: true }
); );
......
...@@ -3,7 +3,12 @@ import { answerCtrl, authCtrl, fileCtrl, surveyCtrl } from "../controllers"; ...@@ -3,7 +3,12 @@ import { answerCtrl, authCtrl, fileCtrl, surveyCtrl } from "../controllers";
const router = express.Router(); const router = express.Router();
router.route("/").post(fileCtrl.uploadFile, answerCtrl.createAnswers); router.route("/").post(answerCtrl.createAnswersWithoutFile);
router
.route("/upload")
.post(fileCtrl.uploadFile, answerCtrl.createAnswerWithFile);
router router
.route("/:surveyId") .route("/:surveyId")
.get(authCtrl.requireLogin, authCtrl.authenticate, answerCtrl.getAnswers); .get(authCtrl.requireLogin, authCtrl.authenticate, answerCtrl.getAnswers);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment