Commit 374b9208 authored by Jiwon Yoon's avatar Jiwon Yoon
Browse files

file을 포함한 설문조사 답변 서버로 보내기

parent 667e4ac8
import axios from "axios";
import { AnswerType } from "../types";
import baseUrl from "./baseUrl";
export const saveAnswers = async (answer: FormData) => {
const { data } = await axios.post(`${baseUrl}/answers`, answer);
return data;
};
export * as authApi from "./auth.api"; export * as authApi from "./auth.api";
export * as questionApi from "./question.api"; export * as questionApi from "./question.api";
export * as surveyApi from "./survey.api"; export * as surveyApi from "./survey.api";
export * as answerApi from "./answer.api";
export { baseImageUrl } from "./baseUrl"; export { baseImageUrl } from "./baseUrl";
import React, { useState } from "react";
import { FileType, AnswerType } from "../types";
type Props = {
element: FileType;
response: AnswerType;
handleAnswer: () => void;
addFiles: (oneFile: { questionId: string; file: File }) => void;
};
export const AFileForm = ({
element,
response,
handleAnswer,
addFiles,
}: Props) => {
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;
}
});
handleAnswer();
}
};
return (
<div id="content" className="flex mt-4 w-full justify-center">
<input
type="file"
name="file"
className=" w-11/12 h-16"
onChange={handleChange}
></input>
</div>
);
};
...@@ -5,13 +5,20 @@ import { ACheckboxForm } from "./ACheckbox"; ...@@ -5,13 +5,20 @@ import { ACheckboxForm } from "./ACheckbox";
import { ADropdownForm } from "./ADropdown"; import { ADropdownForm } from "./ADropdown";
import { AEssayForm } from "./AEssayForm"; import { AEssayForm } from "./AEssayForm";
import { ARadioForm } from "./ARadioForm"; import { ARadioForm } from "./ARadioForm";
import { AFileForm } from "./AFileForm";
type Props = { type Props = {
question: BasicQuestionType; question: BasicQuestionType;
response: AnswerType; response: AnswerType;
handleAnswer: () => void; handleAnswer: () => void;
addFiles: (oneFile: { questionId: string; file: File }) => void;
}; };
export const AQuestion = ({ question, handleAnswer, response }: Props) => { export const AQuestion = ({
question,
handleAnswer,
response,
addFiles,
}: Props) => {
function getContent(question: BasicQuestionType) { function getContent(question: BasicQuestionType) {
switch (question.type) { switch (question.type) {
case "essay": case "essay":
...@@ -46,8 +53,15 @@ export const AQuestion = ({ question, handleAnswer, response }: Props) => { ...@@ -46,8 +53,15 @@ export const AQuestion = ({ question, handleAnswer, response }: Props) => {
handleAnswer={handleAnswer} handleAnswer={handleAnswer}
/> />
); );
// case "file": case "file":
// return <AFileForm element={element} currentId={currentId} />; return (
<AFileForm
element={question}
response={response}
handleAnswer={handleAnswer}
addFiles={addFiles}
/>
);
// case "rating": // case "rating":
// return ( // return (
// <ARatingForm // <ARatingForm
......
import React, { FormEvent, useEffect, useState } from "react"; import React, { FormEvent, useEffect, useState } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { surveyApi } from "../apis"; import { surveyApi, answerApi } from "../apis";
import { catchErrors } from "../helpers"; import { catchErrors } from "../helpers";
import { AnswerType, SurveyType } from "../types"; import { AnswerType, SurveyType } from "../types";
import { AQuestion } from "./AQuestion"; import { AQuestion } from "./AQuestion";
import { ARadioForm } from "./ARadioForm";
export const SurveyForm = () => { export const SurveyForm = () => {
let { surveyId } = useParams<{ surveyId: string }>(); let { surveyId } = useParams<{ surveyId: string }>();
const [files, setFiles] = useState<{ questionId: string; file: File }[]>([]);
const [error, setError] = useState(""); const [error, setError] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false); const [success, setSuccess] = useState(false);
...@@ -18,8 +18,8 @@ export const SurveyForm = () => { ...@@ -18,8 +18,8 @@ export const SurveyForm = () => {
comment: "", comment: "",
questions: [], questions: [],
}); });
const [response, setResponse] = useState<AnswerType>({ const [answer, setResponse] = useState<AnswerType>({
surveyId: surveyId, surveyId: "surveyId",
guestId: "", guestId: "",
answers: [{ questionId: "", answer: "" }], answers: [{ questionId: "", answer: "" }],
}); });
...@@ -28,23 +28,30 @@ export const SurveyForm = () => { ...@@ -28,23 +28,30 @@ export const SurveyForm = () => {
ansSurvey(); ansSurvey();
}, [surveyId]); }, [surveyId]);
const addFiles = (oneFile: { questionId: string; file: File }) => {
if (!files.find((a) => a.questionId === oneFile.questionId)) {
setFiles([...files, oneFile]);
}
};
async function ansSurvey() { async function ansSurvey() {
try { try {
if (surveyId) { if (surveyId) {
const answersurvey: SurveyType = await surveyApi.ansSurvey(surveyId); const answersurvey: any = await surveyApi.ansSurvey(surveyId);
console.log(answersurvey); console.log(answersurvey);
const questionIds = answersurvey.questions.map((el) => { const questionIds = answersurvey.questions.map((el: any) => {
return { questionId: el._id, answer: "" }; return { questionId: el._id, answer: "" };
}); });
console.log(questionIds); console.log(questionIds);
if (answersurvey) {
setResponse({ setResponse({
...response, ...answer,
surveyId: answersurvey._id, surveyId: answersurvey._id,
answers: questionIds, answers: questionIds,
}); });
setSurvey(answersurvey); setSurvey(answersurvey);
setSuccess(true); setSuccess(true);
setError(""); setError("");
}
} else { } else {
setLoading(true); setLoading(true);
} }
...@@ -55,18 +62,35 @@ export const SurveyForm = () => { ...@@ -55,18 +62,35 @@ export const SurveyForm = () => {
} }
} }
function handleSubmit(event: FormEvent) { async function handleSubmit(event: FormEvent) {
event.preventDefault(); event.preventDefault();
try {
const formData = new FormData();
formData.append("surveyId", answer.surveyId);
formData.append("guestId", "");
formData.append("answers", JSON.stringify(answer.answers));
files.map((f) => {
formData.append("files", f.file);
});
const newAnswer: AnswerType = await answerApi.saveAnswers(formData);
// console.log(newAnswer);
setSuccess(true);
setError("");
} catch (error) {
catchErrors(error, setError);
} finally {
setLoading(false);
}
} }
const handleAnswer = () => { const handleAnswer = () => {
const newList = [...response.answers]; const newList = [...answer.answers];
setResponse({ ...response, answers: newList }); setResponse({ ...answer, answers: newList });
}; };
return ( return (
<> <>
{console.log(response)} {console.log(answer)}
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className="flex flex-col place-items-center"> <div className="flex flex-col place-items-center">
<div className="flex flex-col container place-items-center mt-4"> <div className="flex flex-col container place-items-center mt-4">
...@@ -78,7 +102,8 @@ export const SurveyForm = () => { ...@@ -78,7 +102,8 @@ export const SurveyForm = () => {
return ( return (
<AQuestion <AQuestion
question={question} question={question}
response={response} response={answer}
addFiles={addFiles}
handleAnswer={handleAnswer} handleAnswer={handleAnswer}
></AQuestion> ></AQuestion>
); );
......
...@@ -82,7 +82,7 @@ export interface RatingType extends BasicQuestionType { ...@@ -82,7 +82,7 @@ export interface RatingType extends BasicQuestionType {
} }
export interface AnswerType { export interface AnswerType {
surveyId?: string; surveyId: string;
guestId: string; guestId: string;
answers: { questionId: string; answer: any }[]; answers: { questionId: string; answer: any }[];
} }
import { asyncWrap } from "../helpers";
import { TypedRequest } from "../types";
import formidable from "formidable";
import { FileInfo } from "../models";
import { fileDb, userDb } from "../db";
import fs from "fs/promises";
export const createAnswers = asyncWrap(async (reqExp, res) => {
const req = reqExp as TypedRequest;
const answer = req.body;
const answers = JSON.parse(answer.answers);
answer.answers = answers;
console.log(answers);
const file = req.files.img as formidable.File;
let img;
try {
// 1) 파일을 DB에 저장
if (file) {
// img = new FileInfo({
// name: file.originalFilename,
// url: file.newFilename,
// isNew: true,
// });
// await fileDb.createFile(file);
// 2) answer에 img 항목 추가
answer.img = img;
}
// 3) Answer 만들기(map을 돌려서 하나씩 추가시켜야 함)
console.log(answer);
// const newAnswer = await answerDb.createAnswer(answer);
// 주의: ref는 반드시 save를 해야 디비에 생성이 됩니다.
return res.json();
} catch (error: any) {
console.log("error in create user:", error);
// 오류 발생시 저장된 파일 제거
if (file) {
// img && (await fileDb.deleteFileById(img._id.toString()));
await fs.unlink(file.filepath);
}
res.status(422).send(error.message || "사용자 생성 오류");
}
});
...@@ -2,7 +2,7 @@ import formidable from "formidable"; ...@@ -2,7 +2,7 @@ import formidable from "formidable";
import { asyncWrap } from "../helpers/asyncWrap"; import { asyncWrap } from "../helpers/asyncWrap";
import { TypedRequest } from "../types"; import { TypedRequest } from "../types";
export const uploadAvatar = asyncWrap(async (reqExp, res, next) => { export const uploadFile = asyncWrap(async (reqExp, res, next) => {
const req = reqExp as TypedRequest; const req = reqExp as TypedRequest;
const form = formidable({ multiples: false, uploadDir: "uploads" }); const form = formidable({ multiples: false, uploadDir: "uploads" });
...@@ -12,12 +12,10 @@ export const uploadAvatar = asyncWrap(async (reqExp, res, next) => { ...@@ -12,12 +12,10 @@ export const uploadAvatar = asyncWrap(async (reqExp, res, next) => {
reject(err); reject(err);
return; return;
} }
console.log("fields", fields);
// console.log("fields", fields); console.log("files", files);
// console.log("files", files);
req.body = fields; req.body = fields;
req.files = files; req.files = files;
resolve(files); resolve(files);
}); });
}); });
......
...@@ -4,3 +4,4 @@ export * as questionCtrl from "./question.controller"; ...@@ -4,3 +4,4 @@ export * as questionCtrl from "./question.controller";
export * as surveyCtrl from "./survey.controller"; export * as surveyCtrl from "./survey.controller";
export * as roleCtrl from "./role.controller"; export * as roleCtrl from "./role.controller";
export * as userCtrl from "./user.controller"; export * as userCtrl from "./user.controller";
export * as answerCtrl from "./answer.controller";
import { model, Schema, Types } from "mongoose"; import { model, Schema, Types } from "mongoose";
export interface IResponse { export interface IAnswer {
_id?: Types.ObjectId; _id?: Types.ObjectId;
surveyId?: Types.ObjectId; surveyId?: Types.ObjectId;
questionId?: Types.ObjectId; questionId?: Types.ObjectId;
respondent?: string; guestId?: string;
answer?: any; answer?: any;
} }
const schema = new Schema<IResponse>( 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" },
respondent: { type: String }, guestId: { type: String },
answer: { type: Object }, answer: { type: Object },
}, },
{ timestamps: true } { timestamps: true }
); );
export default model<IResponse>("Response", schema); export default model<IAnswer>("Answer", schema);
...@@ -3,3 +3,4 @@ export { default as Question, IQuestion } from "./question.model"; ...@@ -3,3 +3,4 @@ export { default as Question, IQuestion } from "./question.model";
export { default as Role } from "./role.model"; export { default as Role } from "./role.model";
export { default as Survey, ISurvey } from "./survey.model"; export { default as Survey, ISurvey } from "./survey.model";
export { default as User, IUser } from "./user.model"; export { default as User, IUser } from "./user.model";
export { default as Answer, IAnswer } from "./answer.model";
import express from "express";
import { answerCtrl, fileCtrl } from "../controllers";
const router = express.Router();
router.route("/").post(fileCtrl.uploadFile, answerCtrl.createAnswers);
export default router;
...@@ -4,6 +4,7 @@ import questionRouter from "./question.route"; ...@@ -4,6 +4,7 @@ import questionRouter from "./question.route";
import surveyRouter from "./survey.route"; import surveyRouter from "./survey.route";
import roleRouter from "./role.route"; import roleRouter from "./role.route";
import userRouter from "./user.route"; import userRouter from "./user.route";
import answerRouter from "./answer.route";
const router = express.Router(); const router = express.Router();
...@@ -12,5 +13,6 @@ router.use("/questions", questionRouter); ...@@ -12,5 +13,6 @@ router.use("/questions", questionRouter);
router.use("/surveys", surveyRouter); router.use("/surveys", surveyRouter);
router.use("/roles", roleRouter); router.use("/roles", roleRouter);
router.use("/users", userRouter); router.use("/users", userRouter);
router.use("/answers", answerRouter);
export default router; export default router;
...@@ -9,7 +9,7 @@ router ...@@ -9,7 +9,7 @@ router
.post( .post(
authCtrl.requireLogin, authCtrl.requireLogin,
authCtrl.hasRole("admin"), authCtrl.hasRole("admin"),
fileCtrl.uploadAvatar, fileCtrl.uploadFile,
userCtrl.createUser userCtrl.createUser
); );
......
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