Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
students
survey
Commits
f3fc15f0
Commit
f3fc15f0
authored
Aug 22, 2022
by
Yoon, Daeki
😅
Browse files
survey 타입을 CreateSurveyType으로 변경하고 컨텍스트 로직으로 변경
parent
77262376
Changes
10
Show whitespace changes
Inline
Side-by-side
frontend/src/layouts/SurveyLayout.tsx
View file @
f3fc15f0
...
...
@@ -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
:
I
Create
Survey
;
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"
>
...
...
frontend/src/layouts/SurveysLayout.tsx
View file @
f3fc15f0
...
...
@@ -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
:
I
Create
Survey
[];
create
:
()
=>
Promise
<
any
>
;
remove
:
(
id
:
string
)
=>
Promise
<
any
>
;
update
:
(
survey
:
ISurvey
)
=>
Promise
<
any
>
;
update
:
(
survey
:
I
Create
Survey
)
=>
Promise
<
any
>
;
};
export
const
SurveysLayout
=
()
=>
{
const
[
error
,
setError
]
=
useState
(
""
);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
surveys
,
setSurveys
]
=
useState
<
ISurvey
[]
>
([]);
const
[
surveys
,
setSurveys
]
=
useState
<
I
Create
Survey
[]
>
([]);
useEffect
(()
=>
{
const
getSurveys
=
async
()
=>
{
const
surveys
:
ISurvey
[]
=
await
surveyApi
.
getSurveys
();
const
surveys
:
I
Create
Survey
[]
=
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
:
I
Create
Survey
=
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;
};
/**
...
...
frontend/src/surveys/EditSurvey.tsx
View file @
f3fc15f0
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
}
/>
);
};
frontend/src/surveys/ModifySurvey.tsx
View file @
f3fc15f0
...
...
@@ -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
(
...
...
frontend/src/surveys/ModifySurveyView.tsx
0 → 100644
View file @
f3fc15f0
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
>
</>
);
};
frontend/src/surveys/SurveyComment.tsx
0 → 100644
View file @
f3fc15f0
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
>
);
};
frontend/src/surveys/SurveyTitle.tsx
0 → 100644
View file @
f3fc15f0
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
>
);
};
frontend/src/types/index.ts
View file @
f3fc15f0
...
...
@@ -23,6 +23,10 @@ export interface ISurvey {
updatedAt
?:
string
;
}
export
interface
ICreateSurvey
extends
ISurvey
{
questions
:
CreateQuestionData
[];
}
interface
IChoice
{
value
:
number
;
text
:
string
;
...
...
src/helpers/index.ts
View file @
f3fc15f0
...
...
@@ -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
)
);
};
...
...
src/models/question.model.ts
View file @
f3fc15f0
...
...
@@ -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
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment