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 questionApi from "./question.api";
export * as surveyApi from "./survey.api";
export * as answerApi from "./answer.api";
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";
import { ADropdownForm } from "./ADropdown";
import { AEssayForm } from "./AEssayForm";
import { ARadioForm } from "./ARadioForm";
import { AFileForm } from "./AFileForm";
type Props = {
question: BasicQuestionType;
response: AnswerType;
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) {
switch (question.type) {
case "essay":
......@@ -46,8 +53,15 @@ export const AQuestion = ({ question, handleAnswer, response }: Props) => {
handleAnswer={handleAnswer}
/>
);
// case "file":
// return <AFileForm element={element} currentId={currentId} />;
case "file":
return (
<AFileForm
element={question}
response={response}
handleAnswer={handleAnswer}
addFiles={addFiles}
/>
);
// case "rating":
// return (
// <ARatingForm
......
import React, { FormEvent, useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { surveyApi } from "../apis";
import { surveyApi, answerApi } from "../apis";
import { catchErrors } from "../helpers";
import { AnswerType, SurveyType } from "../types";
import { AQuestion } from "./AQuestion";
import { ARadioForm } from "./ARadioForm";
export const SurveyForm = () => {
let { surveyId } = useParams<{ surveyId: string }>();
const [files, setFiles] = useState<{ questionId: string; file: File }[]>([]);
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
......@@ -18,8 +18,8 @@ export const SurveyForm = () => {
comment: "",
questions: [],
});
const [response, setResponse] = useState<AnswerType>({
surveyId: surveyId,
const [answer, setResponse] = useState<AnswerType>({
surveyId: "surveyId",
guestId: "",
answers: [{ questionId: "", answer: "" }],
});
......@@ -28,23 +28,30 @@ export const SurveyForm = () => {
ansSurvey();
}, [surveyId]);
const addFiles = (oneFile: { questionId: string; file: File }) => {
if (!files.find((a) => a.questionId === oneFile.questionId)) {
setFiles([...files, oneFile]);
}
};
async function ansSurvey() {
try {
if (surveyId) {
const answersurvey: SurveyType = await surveyApi.ansSurvey(surveyId);
const answersurvey: any = await surveyApi.ansSurvey(surveyId);
console.log(answersurvey);
const questionIds = answersurvey.questions.map((el) => {
const questionIds = answersurvey.questions.map((el: any) => {
return { questionId: el._id, answer: "" };
});
console.log(questionIds);
setResponse({
...response,
surveyId: answersurvey._id,
answers: questionIds,
});
setSurvey(answersurvey);
setSuccess(true);
setError("");
if (answersurvey) {
setResponse({
...answer,
surveyId: answersurvey._id,
answers: questionIds,
});
setSurvey(answersurvey);
setSuccess(true);
setError("");
}
} else {
setLoading(true);
}
......@@ -55,18 +62,35 @@ export const SurveyForm = () => {
}
}
function handleSubmit(event: FormEvent) {
async function handleSubmit(event: FormEvent) {
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 newList = [...response.answers];
setResponse({ ...response, answers: newList });
const newList = [...answer.answers];
setResponse({ ...answer, answers: newList });
};
return (
<>
{console.log(response)}
{console.log(answer)}
<form onSubmit={handleSubmit}>
<div className="flex flex-col place-items-center">
<div className="flex flex-col container place-items-center mt-4">
......@@ -78,7 +102,8 @@ export const SurveyForm = () => {
return (
<AQuestion
question={question}
response={response}
response={answer}
addFiles={addFiles}
handleAnswer={handleAnswer}
></AQuestion>
);
......
......@@ -82,7 +82,7 @@ export interface RatingType extends BasicQuestionType {
}
export interface AnswerType {
surveyId?: string;
surveyId: string;
guestId: string;
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";
import { asyncWrap } from "../helpers/asyncWrap";
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 form = formidable({ multiples: false, uploadDir: "uploads" });
......@@ -12,12 +12,10 @@ export const uploadAvatar = asyncWrap(async (reqExp, res, next) => {
reject(err);
return;
}
// console.log("fields", fields);
// console.log("files", files);
console.log("fields", fields);
console.log("files", files);
req.body = fields;
req.files = files;
resolve(files);
});
});
......
......@@ -4,3 +4,4 @@ export * as questionCtrl from "./question.controller";
export * as surveyCtrl from "./survey.controller";
export * as roleCtrl from "./role.controller";
export * as userCtrl from "./user.controller";
export * as answerCtrl from "./answer.controller";
import { model, Schema, Types } from "mongoose";
export interface IResponse {
export interface IAnswer {
_id?: Types.ObjectId;
surveyId?: Types.ObjectId;
questionId?: Types.ObjectId;
respondent?: string;
guestId?: string;
answer?: any;
}
const schema = new Schema<IResponse>(
const schema = new Schema<IAnswer>(
{
surveyId: { type: Schema.Types.ObjectId, ref: "Survey" },
questionId: { type: Schema.Types.ObjectId, ref: "Question" },
respondent: { type: String },
guestId: { type: String },
answer: { type: Object },
},
{ 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";
export { default as Role } from "./role.model";
export { default as Survey, ISurvey } from "./survey.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";
import surveyRouter from "./survey.route";
import roleRouter from "./role.route";
import userRouter from "./user.route";
import answerRouter from "./answer.route";
const router = express.Router();
......@@ -12,5 +13,6 @@ router.use("/questions", questionRouter);
router.use("/surveys", surveyRouter);
router.use("/roles", roleRouter);
router.use("/users", userRouter);
router.use("/answers", answerRouter);
export default router;
......@@ -9,7 +9,7 @@ router
.post(
authCtrl.requireLogin,
authCtrl.hasRole("admin"),
fileCtrl.uploadAvatar,
fileCtrl.uploadFile,
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