Commit 0f920a13 authored by Jiwon Yoon's avatar Jiwon Yoon
Browse files

isRequired check

parent 6fb8d9e5
......@@ -3,23 +3,35 @@ import { CheckboxType, AnswersType } from "../types";
type Props = {
element: CheckboxType;
answers: AnswersType | undefined;
handleAnswer: () => void;
answerQuestion: any | undefined;
};
export const ACheckboxForm = ({ element, answers, handleAnswer }: Props) => {
export const ACheckboxForm = ({ element, answerQuestion }: Props) => {
const [answer, setAnswer] = useState("");
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { value } = event.currentTarget;
// response.answers.map((a) => {
// if (a.questionId === element._id) {
// a.answer = value;
// }
// });
answers && (answers.answer = value);
if (answerQuestion.answer) {
if (answerQuestion.answer.find((a: any) => a === value)) {
const newList = answerQuestion.answer.filter((a: any) => a !== value);
answerQuestion.answer = newList;
if (answerQuestion.answer.length) {
answerQuestion.requiredCheck = true;
} else {
answerQuestion.requiredCheck = false;
}
} else {
answerQuestion.answer.push(value);
answerQuestion.requiredCheck = true;
}
} else {
answerQuestion.answer = [];
answerQuestion.answer.push(value);
answerQuestion.requiredCheck = true;
}
setAnswer(value);
handleAnswer();
console.log(answerQuestion);
};
return (
<div className="flex w-full gap-2 justify-around my-3">
......@@ -30,7 +42,6 @@ export const ACheckboxForm = ({ element, answers, handleAnswer }: Props) => {
type="checkbox"
value={choice.text}
onChange={handleChange}
required={element.isRequired}
/>
<label className="text-lg">{choice.text}</label>
</div>
......
......@@ -2,29 +2,24 @@ import React, { useState } from "react";
import { DateType, AnswersType } from "../types";
type Props = {
element: DateType;
answers: AnswersType | undefined;
handleAnswer: () => void;
answerQuestion: any | undefined;
};
export const ADateForm = ({ element, answers, handleAnswer }: Props) => {
export const ADateForm = ({ element, answerQuestion }: Props) => {
const [answer, setAnswer] = useState("");
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { value } = event.currentTarget;
// response.answers.map((a) => {
// if (a.questionId === element._id) {
// a.answer = value;
// }
// });
answers && (answers.answer = value);
answerQuestion.answer = value;
setAnswer(value);
handleAnswer();
if (answerQuestion.answer) {
answerQuestion.requiredCheck = true;
} else {
answerQuestion.requiredCheck = false;
}
console.log(answerQuestion);
};
return (
<div className="justify-start w-11/12 m-3 py-4">
<input
type="date"
onChange={handleChange}
required={element.isRequired}
></input>
<input type="date" onChange={handleChange}></input>
</div>
);
};
......@@ -3,30 +3,28 @@ import { DropdownType, AnswersType } from "../types";
type Props = {
element: DropdownType;
answers: AnswersType | undefined;
handleAnswer: () => void;
answerQuestion: any | undefined;
};
export const ADropdownForm = ({ element, handleAnswer, answers }: Props) => {
export const ADropdownForm = ({ element, answerQuestion }: Props) => {
const [answer, setAnswer] = useState("");
const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
const { value } = event.currentTarget;
// response.answers.map((a) => {
// if (a.questionId === element._id) {
// a.answer = value;
// }
// });
answers && (answers.answer = value);
answerQuestion.answer = value;
setAnswer(value);
handleAnswer();
if (answerQuestion.answer) {
answerQuestion.requiredCheck = true;
} else {
answerQuestion.requiredCheck = false;
}
console.log(answerQuestion);
};
return (
<div className="flex flex-col container w-4/5 h-auto items-center m-3 py-3">
<select
className="py-2 hover:bg-themeColor bg-gray-200 rounded"
onChange={handleChange}
required={element.isRequired}
>
{element.content.choices.map((choice) => (
<option value={choice.text}>{choice.text}</option>
......
......@@ -3,23 +3,22 @@ import { EssayType, AnswersType } from "../types";
type Props = {
element: EssayType;
answers: AnswersType | undefined;
handleAnswer: () => void;
answerQuestion: any | undefined;
};
export const AEssayForm = ({ element, handleAnswer, answers }: Props) => {
export const AEssayForm = ({ element, answerQuestion }: Props) => {
const [answer, setAnswer] = useState("");
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { value } = event.currentTarget;
// response.answers.map((a) => {
// if (a.questionId === element._id) {
// a.answer = value;
// }
// });
answers && (answers.answer = value);
answerQuestion.answer = value;
setAnswer(value);
handleAnswer();
if (answerQuestion.answer) {
answerQuestion.requiredCheck = true;
} else {
answerQuestion.requiredCheck = false;
}
console.log(answerQuestion);
};
return (
<div className="flex mt-3 w-full justify-center">
......@@ -29,7 +28,6 @@ export const AEssayForm = ({ element, handleAnswer, answers }: Props) => {
id={element._id}
onChange={handleChange}
value={answer}
required={element.isRequired}
></input>
</div>
);
......
......@@ -3,28 +3,24 @@ import { FileType, AnswersType } from "../types";
type Props = {
element: FileType;
answers: AnswersType | undefined;
handleAnswer: () => void;
answerQuestion: any | undefined;
addFiles: (oneFile: { questionId: string; file: File }) => void;
};
export const AFileForm = ({
element,
answers,
handleAnswer,
addFiles,
}: Props) => {
export const AFileForm = ({ element, answerQuestion, addFiles }: Props) => {
const [answer, setAnswer] = useState("");
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.currentTarget.files) {
const uploadFile = event.currentTarget.files[0];
addFiles({ questionId: element._id, file: uploadFile });
// response.answers.map((a) => {
// if (a.questionId === element._id) {
// a.answer = uploadFile.name;
// }
// });
answers && (answers.answer = uploadFile.name);
handleAnswer();
answerQuestion.answer = uploadFile.name;
if (answerQuestion.answer) {
answerQuestion.requiredCheck = true;
} else {
answerQuestion.requiredCheck = false;
}
setAnswer(uploadFile.name);
console.log(answerQuestion);
}
};
return (
......@@ -34,7 +30,6 @@ export const AFileForm = ({
name="file"
className=" w-11/12 h-16"
onChange={handleChange}
required={element.isRequired}
></input>
</div>
);
......
import React from "react";
import { BasicQuestionType, AnswersType } from "../types";
import { BasicQuestionType, AnswersType, SurveyType } from "../types";
import { ACheckboxForm } from "./ACheckboxForm";
import { ADateForm } from "./ADateForm";
import { ADropdownForm } from "./ADropdownForm";
......@@ -10,75 +10,42 @@ import { ARatingForm } from "./ARatingForm";
type Props = {
question: BasicQuestionType;
answer: AnswersType | undefined;
handleAnswer: () => void;
answerQuestion: any | undefined;
addFiles: (oneFile: { questionId: string; file: File }) => void;
};
export const AQuestion = ({
question,
handleAnswer,
answer,
addFiles,
}: Props) => {
export const AQuestion = ({ question, answerQuestion, addFiles }: Props) => {
function getContent(question: BasicQuestionType) {
switch (question.type) {
case "essay":
return (
<AEssayForm
element={question}
answers={answer}
handleAnswer={handleAnswer}
/>
<AEssayForm element={question} answerQuestion={answerQuestion} />
);
case "radio":
return (
<ARadioForm
element={question}
answers={answer}
handleAnswer={handleAnswer}
/>
<ARadioForm element={question} answerQuestion={answerQuestion} />
);
case "checkbox":
return (
<ACheckboxForm
element={question}
answers={answer}
handleAnswer={handleAnswer}
/>
<ACheckboxForm element={question} answerQuestion={answerQuestion} />
);
case "dropdown":
return (
<ADropdownForm
element={question}
answers={answer}
handleAnswer={handleAnswer}
/>
<ADropdownForm element={question} answerQuestion={answerQuestion} />
);
case "file":
return (
<AFileForm
element={question}
answers={answer}
handleAnswer={handleAnswer}
answerQuestion={answerQuestion}
addFiles={addFiles}
/>
);
case "rating":
return (
<ARatingForm
element={question}
answers={answer}
handleAnswer={handleAnswer}
/>
<ARatingForm element={question} answerQuestion={answerQuestion} />
);
case "date":
return (
<ADateForm
element={question}
answers={answer}
handleAnswer={handleAnswer}
/>
);
return <ADateForm element={question} answerQuestion={answerQuestion} />;
default:
return <></>;
}
......@@ -88,6 +55,11 @@ export const AQuestion = ({
<div className="flex flex-col container w-4/5 h-auto border-2 border-themeColor items-center m-3 py-4">
<div className="flex flexgi-row 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>
{getContent(question)}
......
......@@ -3,23 +3,22 @@ import { RadioType, AnswersType } from "../types";
type Props = {
element: RadioType;
answers: AnswersType | undefined;
handleAnswer: () => void;
answerQuestion: any | undefined;
};
export const ARadioForm = ({ element, answers, handleAnswer }: Props) => {
export const ARadioForm = ({ element, answerQuestion }: Props) => {
const [answer, setAnswer] = useState("");
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { value } = event.currentTarget;
// response.answers.map((a) => {
// if (a.questionId === element._id) {
// a.answer = value;
// }
// });
answers && (answers.answer = value);
answerQuestion.answer = value;
setAnswer(value);
handleAnswer();
if (answerQuestion.answer) {
answerQuestion.requiredCheck = true;
} else {
answerQuestion.requiredCheck = false;
}
console.log(answerQuestion);
};
return (
<div className="flex w-full gap-2 justify-around my-3">
......@@ -32,7 +31,6 @@ export const ARadioForm = ({ element, answers, handleAnswer }: Props) => {
name={element._id}
onChange={handleChange}
value={choice.text}
required={element.isRequired}
></input>
<label className="text-lg" id={choice.text}>
{choice.text}
......
......@@ -3,32 +3,31 @@ import { RatingType, AnswersType } from "../types";
type Props = {
element: RatingType;
answers: AnswersType | undefined;
handleAnswer: () => void;
answerQuestion: any | undefined;
};
export const ARatingForm = ({ element, answers, handleAnswer }: Props) => {
export const ARatingForm = ({ element, answerQuestion }: Props) => {
const [selectedchoice, setSelectedchoice] = useState("");
const [answer, setAnswer] = useState("");
function buttonClick(event: React.MouseEvent<HTMLButtonElement>) {
event.preventDefault();
const { name } = event.currentTarget;
// response.answers.map((a) => {
// if (a.questionId === element._id) {
// a.answer = name;
// }
// });
answers && (answers.answer = name);
answerQuestion.answer = name;
setAnswer(name);
setSelectedchoice(event.currentTarget.name);
handleAnswer();
if (answerQuestion.answer) {
answerQuestion.requiredCheck = true;
} else {
answerQuestion.requiredCheck = false;
}
console.log(answerQuestion);
}
return (
<div className="flex w-full justify-center space-x-12 my-3">
<div className="flex w-full justify-center my-3">
<label className="mt-3">{element.content.minRateDescription}</label>
{element.content.choices.map((choice) => (
<div className="flex gap-4">
<div className="flex gap-4 mx-1">
<button
type="button"
className="border border-themeColor rounded-full w-12 h-12 text-center hover:bg-slate-300"
......
......@@ -2,12 +2,14 @@ import React, { FormEvent, useEffect, useRef, useState } from "react";
import { useParams } from "react-router-dom";
import { surveyApi, answerApi } from "../apis";
import { catchErrors } from "../helpers";
import { Question } from "../questions";
import { AnswerType, SurveyType } from "../types";
import { AQuestion } from "./AQuestion";
export const SurveyForm = () => {
let { surveyId } = useParams<{ surveyId: string }>();
const [files, setFiles] = useState<{ questionId: string; file: File }[]>([]);
const [requiredErrorMessage, setRequiredErrorMessage] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
......@@ -19,12 +21,18 @@ export const SurveyForm = () => {
questions: [],
});
const answer = useRef<AnswerType>({
surveyId: "surveyId",
guestId: "",
answers: [],
const answerSurvey = useRef<any>({
_id: "surveyId",
user: {},
title: "",
comment: "",
questions: [],
});
useEffect(() => {
ansSurvey();
}, [surveyId]);
const addFiles = (oneFile: { questionId: string; file: File }) => {
if (!files.find((a) => a.questionId === oneFile.questionId)) {
setFiles([...files, oneFile]);
......@@ -34,23 +42,12 @@ export const SurveyForm = () => {
async function ansSurvey() {
try {
if (surveyId) {
const answersurvey: any = await surveyApi.ansSurvey(surveyId);
console.log(answersurvey);
const questionIds = answersurvey.questions.map((el: any) => {
return { questionId: el._id, type: el.type, answer: "" };
});
console.log(questionIds);
if (answersurvey) {
// setResponse({
// ...answer,
// surveyId: answersurvey._id,
// answers: questionIds,
// });
answer.current.surveyId = answersurvey._id;
answer.current.guestId = answersurvey.guestId;
answer.current.answers = questionIds;
setSurvey(answersurvey);
const getSurvey: any = await surveyApi.ansSurvey(surveyId);
console.log("survey가져옴ㅎㅎ", getSurvey);
if (getSurvey) {
answerSurvey.current._id = getSurvey._id;
answerSurvey.current.questions = getSurvey.questions;
setSurvey(getSurvey);
setSuccess(true);
setError("");
}
......@@ -64,17 +61,22 @@ export const SurveyForm = () => {
}
}
useEffect(() => {
ansSurvey();
}, [surveyId]);
async function handleSubmit(event: FormEvent) {
event.preventDefault();
const answers = answerSurvey.current.questions.map((q: any) => {
return { questionId: q.questionId, answer: q.answer, type: q.type };
});
const requiredErrorQ = answerSurvey.current.questions.find(
(q: any) => q.isRequired && q.isRequired !== q.requiredCheck
);
if (requiredErrorQ) {
alert("필수질문에 응답하지 않으셨습니다.");
} else {
try {
const formData = new FormData();
formData.append("surveyId", answer.current.surveyId);
formData.append("surveyId", answerSurvey.current._id);
formData.append("guestId", "");
formData.append("answers", JSON.stringify(answer.current.answers));
formData.append("answers", JSON.stringify(answers));
files.map((f) => {
formData.append("uploadFiles", f.file);
});
......@@ -88,16 +90,11 @@ export const SurveyForm = () => {
setLoading(false);
}
}
const handleAnswer = () => {
console.log("handle answer:", answer.current);
// const newList = [...answer.answers];
// setResponse({ ...answer, answers: newList });
};
}
return (
<>
{console.log("rendering survey form", answer.current)}
{console.log("rendering survey form", answerSurvey.current)}
<form onSubmit={handleSubmit}>
<div className="flex flex-col place-items-center">
<div className="flex flex-col container place-items-center mt-4">
......@@ -105,15 +102,12 @@ export const SurveyForm = () => {
<p className="font-bold text-1xl text-center m-2">
{survey.comment}
</p>
{survey.questions.map((question) => {
{survey.questions.map((question, index) => {
return (
<AQuestion
question={question}
answer={answer.current.answers.find(
(ans) => ans.questionId === question._id
)}
answerQuestion={answerSurvey.current.questions[index]}
addFiles={addFiles}
handleAnswer={handleAnswer}
></AQuestion>
);
})}
......
......@@ -2,7 +2,7 @@ import { asyncWrap } from "../helpers";
import { TypedRequest } from "../types";
import formidable from "formidable";
import { FileInfo } from "../models";
import { fileDb, userDb } from "../db";
import { fileDb, userDb, answerDb } from "../db";
import fs from "fs/promises";
export const createAnswers = asyncWrap(async (reqExp, res) => {
......@@ -11,29 +11,39 @@ export const createAnswers = asyncWrap(async (reqExp, res) => {
const answers = JSON.parse(answer.answers);
answer.answers = answers;
const files = req.files.uploadFiles as formidable.File[];
console.log("controller의 files", files);
// console.log("controller의 files", files);
let uploadFile;
try {
if (files) {
// 1) 파일을 DB에 저장 후 다시 retFile가져와서
// *근데 파일이 여러 개일 수 있기 때문에 순회해야 됨
files.map(async (file) => {
// *근데 파일이 여러 개일 수 있기 때문에 순회해야 됨-map()을 쓰면 async function이 되어버려서 for문 이용함
for (let index = 0; index < files.length; index++) {
const file = files[index];
uploadFile = new FileInfo({
name: file.originalFilename,
url: file.newFilename,
isNew: true,
});
const retFile = await fileDb.createFile(file);
console.log(retFile);
// 2) answers의 type이 file인 친구들 찾아서 그 친구의 answer와 filename을 비교 후 같으면
const targetObj = answer.find((ans: any) => ans.type === "file");
const targetObj = answer.answers.find(
(ans: any) => ans.answer === file.originalFilename
);
// 3) answer에다가 retFile의 _id 넣어주기
targetObj.answer = retFile._id;
});
}
}
// 3) Answer DB 만들기(map을 돌려서 하나씩 추가시켜야 함)
// console.log(answer);
// const newAnswer = await answerDb.createAnswer(answer);
for (let index = 0; index < answer.answers.length; index++) {
const element = answer.answers[index];
const newAnswer = await answerDb.createAnswer({
surveyId: answer.surveyId,
guestId: answer.guestId,
questionId: element.questionId,
answer: element.answer,
});
console.log("DB에 넣은 answer", newAnswer);
}
// 주의: ref는 반드시 save를 해야 디비에 생성이 됩니다.
return res.json();
} catch (error: any) {
......
import { Answer, IAnswer } from "../models";
export const createAnswer = async (answer: IAnswer) => {
const newQuestion = await Answer.create(answer);
return newQuestion;
};
......@@ -3,3 +3,4 @@ export * as questionDb from "./question.db";
export * as roleDb from "./role.db";
export * as surveyDb from "./survey.db";
export * as userDb from "./user.db";
export * as answerDb from "./answer.db";
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