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

survey 타입을 CreateSurveyType으로 변경하고 컨텍스트 로직으로 변경

parent 77262376
......@@ -2,10 +2,11 @@ import React from "react";
import { NavLink, useOutletContext } from "react-router-dom";
import { Outlet, useNavigate, useParams } from "react-router-dom";
import { useSurveys } from "./SurveysLayout";
import type { ISurvey } from "../types";
import type { ICreateSurvey, ISurvey } from "../types";
import { SpinnerIcon } from "../icons";
type SurveyContextType = {
survey: ISurvey;
survey: ICreateSurvey;
update: (survey: ISurvey) => Promise<any>;
};
......@@ -19,6 +20,16 @@ export const SurveyLayout = () => {
let { surveyId } = useParams<{ surveyId: string }>();
const survey = surveys.find((survey) => survey._id === surveyId);
console.log("surveys in survey layout", surveys);
if (!survey) {
return (
<div className="flex justify-center mt-5">
<SpinnerIcon className="animate-spin h-10 w-10 mr-1 bg-white text-slate-500" />
</div>
);
}
return (
<div>
<div className="flex justify-center items-center mt-6">
......
......@@ -2,25 +2,25 @@ import React, { useEffect, useState } from "react";
import { Outlet, useOutletContext } from "react-router-dom";
import { surveyApi } from "../apis";
import { catchErrors } from "../helpers";
import type { ISurvey } from "../types";
import type { ICreateSurvey, ISurvey } from "../types";
type SurveysContextType = {
error: string;
loading: boolean;
surveys: ISurvey[];
surveys: ICreateSurvey[];
create: () => Promise<any>;
remove: (id: string) => Promise<any>;
update: (survey: ISurvey) => Promise<any>;
update: (survey: ICreateSurvey) => Promise<any>;
};
export const SurveysLayout = () => {
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const [surveys, setSurveys] = useState<ISurvey[]>([]);
const [surveys, setSurveys] = useState<ICreateSurvey[]>([]);
useEffect(() => {
const getSurveys = async () => {
const surveys: ISurvey[] = await surveyApi.getSurveys();
const surveys: ICreateSurvey[] = await surveyApi.getSurveys();
// console.log(surveys);
setSurveys(surveys);
};
......@@ -28,18 +28,24 @@ export const SurveysLayout = () => {
}, []);
const create = async (surveyData: ISurvey) => {
const result: ISurvey = await surveyApi.createSurvey(surveyData);
const result: ICreateSurvey = await surveyApi.createSurvey(surveyData);
setSurveys([result, ...surveys]);
return result;
};
const update = async (surveyData: ISurvey) => {
const result = await surveyApi.updateSurvey(surveyData);
const index = surveys.findIndex((survey) => survey._id === result._id);
surveys[index] = result;
console.log("result in modify layout:", result);
/**
* 수정된 설문 객체를 적용한 새로운 설문 배열 생성하여 리랜더링
* @param surveyData 바꾸려는 설문 객체
*/
const update = async (surveyData: ICreateSurvey) => {
// const result = await surveyApi.updateSurvey(surveyData);
// const index = surveys.findIndex((survey) => survey._id === result._id);
// surveys[index] = result;
const index = surveys.findIndex((survey) => survey._id === surveyData._id);
surveys[index] = surveyData;
console.log("update in surveys layout layout:", surveyData);
setSurveys([...surveys]);
return result;
// return result;
};
/**
......
import React, { useState } from "react";
import React, { ChangeEvent, useState } from "react";
import { Navigate, useLocation, useParams } from "react-router-dom";
import { surveyApi } from "../apis";
import { ISurvey } from "../types";
import type { CreateQuestionData, IQuestionData, ISurvey } from "../types";
import { ModifySurvey } from "./ModifySurvey";
import { useSurvey } from "../layouts/SurveyLayout";
import { SpinnerIcon } from "../icons";
import { ModifySurveyView } from "./ModifySurveyView";
export const EditSurvey = () => {
const { survey, update } = useSurvey();
// const [survey, setSurvey] = useState(surveyData);
// const [survey, setSurvey] = useState<ISurvey>(surveyData);
// const [questions, setQuestions] = useState<CreateQuestionData[]>(() => {
// const questions = survey.questions;
// return questions.map((question) => ({ ...question, isEditing: false }));
// });
const questions = survey.questions;
console.log("survey", survey);
// const location = useLocation();
// const surveyState = location.state as ISurvey;
// console.log("edit survey:", surveyState);
console.log("questions", questions);
// const update = async (surveyData: ISurvey) => {
// const result = await surveyApi.updateSurvey(surveyData);
// return result;
// };
const handleTitle = (title: string) => {
console.log("title in handle title:", title);
// survey.title = title
update({ ...survey, title: title });
};
/**
* 수정된 질문을 입력받아 기존 질문을 대체합니다.
* @param question 수정할 질문
* @returns 없음
*/
const updateQuestion = (question: CreateQuestionData) => {
const index = questions.findIndex((q) => q._id === question._id);
if (index < 0) {
return;
}
questions[index] = question;
console.log("questions in update question:", questions);
// setQuestions([...questions]);
survey.questions = questions;
update(survey);
};
const addQuestion = () => {
const question: CreateQuestionData = {
_id: Math.random().toString(),
order: questions.length,
type: "singletext",
title: "",
comment: "",
isRequired: false,
content: { choices: [] },
isEditing: true,
};
// setQuestions([...questions, question]);
};
async function deleteQuestion(id: string) {
const delQuestions = questions.filter((question) => question._id !== id);
// setQuestions(delQuestions);
}
if (!survey) {
return <Navigate to={"/surveys"} />;
return (
<div className="flex justify-center mt-5">
<SpinnerIcon className="animate-spin h-10 w-10 mr-1 bg-white text-slate-500" />
</div>
);
}
return <ModifySurvey surveyData={survey} callApi={update} />;
return (
<ModifySurveyView
questions={questions}
survey={survey}
addQuestion={addQuestion}
deleteQuestion={deleteQuestion}
handleQuestion={updateQuestion}
handleTitle={handleTitle}
callApi={update}
/>
);
};
......@@ -33,6 +33,11 @@ export const ModifySurvey = ({ surveyData, callApi }: Props) => {
return incompleted;
};
/**
* 수정된 질문을 입력받아 기존 질문을 대체합니다.
* @param question 수정할 질문
* @returns 없음
*/
const handleQuestion = (question: CreateQuestionData) => {
const index = questions.findIndex((q) => q._id === question._id);
if (index < 0) {
......@@ -43,21 +48,6 @@ export const ModifySurvey = ({ surveyData, callApi }: Props) => {
setQuestions([...questions]);
};
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
survey.questions = questions;
try {
setLoading(true);
const result = await callApi(survey);
console.log("result:", result);
// navigate("/surveys/profile", { replace: true });
navigate(-1);
} catch (error) {
setLoading(false);
catchErrors(error, setError);
}
};
const addQuestion = () => {
const question: CreateQuestionData = {
_id: Math.random().toString(),
......@@ -77,6 +67,20 @@ export const ModifySurvey = ({ surveyData, callApi }: Props) => {
setQuestions(delQuestions);
}
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
survey.questions = questions;
try {
setLoading(true);
const result = await callApi(survey);
console.log("result:", result);
navigate(-1);
} catch (error) {
setLoading(false);
catchErrors(error, setError);
}
};
const disabled = hasIncompleteEditing();
return (
......
import React, { ChangeEvent, FormEvent, useState } from "react";
import { useNavigate } from "react-router-dom";
import { catchErrors } from "../helpers";
import { SpinnerIcon } from "../icons";
import { CreateQuestionData, ISurvey } from "../types";
import { QuestionsList } from "./QuestionsList";
import { SurveyTitle } from "./SurveyTitle";
type Props = {
questions: CreateQuestionData[];
survey: ISurvey;
addQuestion: () => void;
deleteQuestion: (id: string) => void;
handleQuestion: (question: CreateQuestionData) => void;
handleTitle: Function;
callApi: (surveyData: ISurvey) => Promise<any>;
};
export const ModifySurveyView = ({
questions,
survey,
addQuestion,
deleteQuestion,
handleQuestion,
handleTitle,
callApi,
}: Props) => {
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
// const [survey, setSurvey] = useState<ISurvey>(surveyData);
// const [questions, setQuestions] = useState<CreateQuestionData[]>(() => {
// const questions = survey.questions;
// return questions.map((question) => ({ ...question, isEditing: false }));
// });
// const navigate = useNavigate();
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
// setSurvey({ ...survey, [name]: value });
};
// const hasIncompleteEditing = () => {
// if (questions.length <= 0) {
// return true;
// }
// const incompleted = questions.some((question) => question.isEditing);
// return incompleted;
// };
// /**
// * 수정된 질문을 입력받아 기존 질문을 대체합니다.
// * @param question 수정할 질문
// * @returns 없음
// */
// const handleQuestion = (question: CreateQuestionData) => {
// const index = questions.findIndex((q) => q._id === question._id);
// if (index < 0) {
// return;
// }
// questions[index] = question;
// console.log("handle question questions:", questions);
// setQuestions([...questions]);
// };
// const addQuestion = () => {
// const question: CreateQuestionData = {
// _id: Math.random().toString(),
// order: questions.length,
// type: "singletext",
// title: "",
// comment: "",
// isRequired: false,
// content: { choices: [] },
// isEditing: true,
// };
// setQuestions([...questions, question]);
// };
// async function deleteQuestion(id: string) {
// const delQuestions = questions.filter((question) => question._id !== id);
// setQuestions(delQuestions);
// }
// const handleSubmit = async (e: FormEvent) => {
// e.preventDefault();
// // survey.questions = questions;
// try {
// setLoading(true);
// const result = await callApi(survey);
// console.log("result:", result);
// navigate(-1);
// } catch (error) {
// setLoading(false);
// catchErrors(error, setError);
// }
// };
// const disabled = hasIncompleteEditing();
return (
<>
{loading && (
<SpinnerIcon className="animate-spin h-5 w-5 mr-1 text-slate" />
)}
<form>
<div className="flex flex-col place-items-center">
<SurveyTitle text={survey.title} handleTitle={handleTitle} />
<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="설문지 제목"
autoComplete="on"
value={survey.title}
onChange={handleChange}
></input>
<input
type="text"
name="comment"
className="font-bold text-1xl text-center m-2 border-b-2 resize-none"
placeholder="설문조사에 대한 설명을 입력해주세요"
autoComplete="on"
size={50}
value={survey.comment}
onChange={handleChange}
></input>
</div>
<QuestionsList
questions={questions}
handleQuestion={handleQuestion}
deleteQuestion={deleteQuestion}
/>
<button
type="button"
onClick={addQuestion}
className="flex w-4/5 content-center justify-center border-2 border-black h-8 mt-3"
>
질문 추가
</button>
{error && (
<div className="text-red-500 text-sm mt-3">
<p>{error}</p>
</div>
)}
{/* <button
type="submit"
disabled={disabled}
title={`${disabled ? "완성되지 않은 부분이 존재합니다" : ""}`}
className="border bg-themeColor my-5 py-2 px-3 disabled:opacity-60 font-bold text-white"
>
저장
</button> */}
</div>
</form>
</>
);
};
import React, { useState } from "react";
export const SurveyComment = () => {
const [comment, setComment] = useState("");
const handleChange = () => {};
return (
<div>
<input
type="text"
name="comment"
className="font-bold text-1xl text-center m-2 border-b-2 resize-none"
placeholder="설문조사에 대한 설명을 입력해주세요"
autoComplete="on"
size={50}
value={comment}
onChange={handleChange}
/>
</div>
);
};
import React, {
ChangeEvent,
ChangeEventHandler,
MouseEventHandler,
useState,
} from "react";
type Props = {
// isEditing: boolean;
text: string;
handleTitle: Function;
};
export const SurveyTitle = ({ text, handleTitle }: Props) => {
const [title, setTitle] = useState(text);
const [disabled, setDisabled] = useState(true);
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setTitle(value);
};
const onEdit = () => {
setDisabled(false);
};
const onCancel = () => {
setDisabled(true);
setTitle(text);
};
const handleClick = () => {
console.log("title", title);
setDisabled(true);
handleTitle(title);
};
return (
<div
className={`flex flex-col container w-4/5 h-auto border-2 items-center m-3 py-2 rounded-lg ${
disabled ? "border-themeColor" : "border-red-500"
}`}
>
<input
type="text"
name="title"
className="font-bold text-4xl text-center m-2 border-b-2"
placeholder="설문지 제목"
autoComplete="on"
value={title}
disabled={disabled}
onChange={handleChange}
/>
<div className="flex w-11/12 justify-end">
{disabled ? (
<>
<button type="button" className="px-1" onClick={onEdit}>
수정
</button>
</>
) : (
<>
<button type="button" className="px-1" onClick={onCancel}>
취소
</button>
<button type="button" className="px-1" onClick={handleClick}>
확인
</button>
</>
)}
</div>
</div>
);
};
......@@ -23,6 +23,10 @@ export interface ISurvey {
updatedAt?: string;
}
export interface ICreateSurvey extends ISurvey {
questions: CreateQuestionData[];
}
interface IChoice {
value: number;
text: string;
......
......@@ -4,9 +4,9 @@ export { asyncWrap } from "./asyncWrap";
export const isEmpty = (obj: any) => {
return (
obj && // 👈 null and undefined check
Object.keys(obj).length === 0 &&
Object.getPrototypeOf(obj) === Object.prototype
!obj || // 👈 null and undefined check
(Object.keys(obj).length === 0 &&
Object.getPrototypeOf(obj) === Object.prototype)
);
};
......
......@@ -3,6 +3,7 @@ import { model, ObjectId, Schema, Types } from "mongoose";
export interface IQuestion {
_id?: Types.ObjectId;
user?: Types.ObjectId;
order: number;
type: string;
title?: string;
isRequired: boolean;
......@@ -13,7 +14,8 @@ export interface IQuestion {
const schema = new Schema<IQuestion>(
{
user: { type: Schema.Types.ObjectId, ref: "User" },
type: { type: String },
order: { type: Number },
type: { type: String, required: true },
title: { type: String },
isRequired: { type: Boolean },
comment: { type: String },
......
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