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
2c9d5fe2
Commit
2c9d5fe2
authored
Jul 15, 2022
by
Jiwon Yoon
Browse files
isRequired, survey-question cascade delete
parent
4f7388bd
Changes
15
Hide whitespace changes
Inline
Side-by-side
frontend/src/apis/question.api.ts
View file @
2c9d5fe2
...
...
@@ -21,7 +21,9 @@ export const updateQuestion = async (question: BasicQuestionType) => {
return
data
;
};
export
const
deleteQuestion
=
async
(
id
:
string
)
=>
{
const
{
data
}
=
await
axios
.
delete
(
`
${
baseUrl
}
/questions/delete/
${
id
}
`
);
export
const
deleteQuestion
=
async
(
questionId
:
string
)
=>
{
const
{
data
}
=
await
axios
.
delete
(
`
${
baseUrl
}
/questions/delete/
${
questionId
}
`
);
return
data
;
};
frontend/src/apis/survey.api.ts
View file @
2c9d5fe2
...
...
@@ -24,3 +24,8 @@ export const editSurvey = async (survey: SurveyType) => {
);
return
data
;
};
export
const
deleteSurvey
=
async
(
surveyId
:
string
)
=>
{
const
{
data
}
=
await
axios
.
delete
(
`
${
baseUrl
}
/surveys/delete/
${
surveyId
}
`
);
return
data
;
};
frontend/src/commons/Header.tsx
View file @
2c9d5fe2
...
...
@@ -14,37 +14,30 @@ export const Header = () => {
</
Link
>
<
div
className
=
"md:flex items-center justify-end md:flex-1 lg:w-0"
>
{
user
.
isLoggedIn
?
(
<
div
className
=
""
>
<
div
>
<
button
onClick
=
{
()
=>
logout
()
}
className
=
"
whitespace-nowrap
font-bold text-gray-600 hover:text-themeColor mx-1 py-2 px-3 rounded-md"
className
=
"font-bold text-gray-600 hover:text-themeColor mx-1 py-2 px-3 rounded-md"
>
로그아웃
</
button
>
{
location
.
pathname
===
"
/profile
"
?
(
""
)
:
(
<
Link
to
=
"/profile"
className
=
"whitespace-nowrap font-bold text-gray-600 hover:text-themeColor mx-1 py-2 px-3 rounded-md"
>
<
Link
to
=
"/profile"
>
<
button
className
=
"font-bold text-gray-600 hover:text-themeColor mx-1 py-2 px-3 rounded-md"
>
프로필
</
Link
>
)
}
</
button
>
</
Link
>
</
div
>
)
:
(
<
div
>
<
Link
to
=
"/login"
className
=
"whitespace-nowrap font-bold text-gray-600 hover:text-themeColor mx-1 py-2 px-3 rounded-md"
>
로그인
<
Link
to
=
"/login"
>
<
button
className
=
"font-bold text-gray-600 hover:text-themeColor mx-1 py-2 px-3 rounded-md"
>
로그인
</
button
>
</
Link
>
<
Link
to
=
"/signup"
className
=
"whitespace-nowrap font-bold text-white hover:bg-blue-500 mx-1 py-2 px-3 bg-themeColor rounded-md "
>
회원가입
<
Link
to
=
"/signup"
>
<
button
className
=
"font-bold text-white hover:bg-blue-500 mx-1 py-2 px-3 bg-themeColor rounded-md "
>
회원가입
</
button
>
</
Link
>
</
div
>
)
}
...
...
frontend/src/profile/MySurvey.tsx
deleted
100644 → 0
View file @
4f7388bd
import
React
from
"
react
"
;
import
{
BasicQuestionType
,
SurveyType
}
from
"
../types
"
;
type
Props
=
{
data
:
SurveyType
;
};
export
const
MySurveyCard
=
({
data
}:
Props
)
=>
{
return
(
<
div
className
=
"w-48 h-60 rounded overflow-hidden border-2"
>
<
div
className
=
"px-6 py-4"
>
<
p
className
=
"text-gray-700 text-base"
>
{
data
.
comment
}
</
p
>
</
div
>
<
div
className
=
"flex flex-col py-6"
>
<
div
className
=
"px-2 py-2"
>
<
label
>
{
data
.
title
}
</
label
>
</
div
>
<
div
className
=
"flex justify-end"
>
<
select
className
=
"py-2 w-14 bg-themeColor rounded text-white"
//value={}
//onChange={}
>
<
option
value
=
"option"
>
옵션
</
option
>
<
option
value
=
"option"
>
삭제
</
option
>
<
option
value
=
"option"
>
이름 바꾸기
</
option
>
</
select
>
</
div
>
</
div
>
</
div
>
);
};
frontend/src/profile/MySurveyCard.tsx
0 → 100644
View file @
2c9d5fe2
import
React
,
{
useState
}
from
"
react
"
;
import
{
useNavigate
}
from
"
react-router-dom
"
;
import
{
surveyApi
}
from
"
../apis
"
;
import
{
SurveyType
}
from
"
../types
"
;
type
Props
=
{
data
:
SurveyType
;
};
export
const
MySurveyCard
=
({
data
}:
Props
)
=>
{
const
navigate
=
useNavigate
();
const
[
error
,
setError
]
=
useState
(
""
);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
success
,
setSuccess
]
=
useState
(
false
);
const
editSurvey
=
()
=>
{
navigate
(
`/surveys/edit/
${
data
.
_id
}
`
,
{
replace
:
true
,
});
};
async
function
deleteSurvey
()
{
try
{
if
(
data
.
_id
)
{
const
survey
=
await
surveyApi
.
deleteSurvey
(
data
.
_id
);
setSuccess
(
true
);
setError
(
""
);
location
.
reload
();
}
else
{
setLoading
(
true
);
}
}
catch
(
error
)
{
console
.
log
(
"
에러발생
"
);
// catchErrors(error, setError)
}
finally
{
setLoading
(
false
);
}
}
return
(
<
div
className
=
"w-52 h-60 rounded border-2"
>
<
div
className
=
"h-32 p-5"
>
<
p
className
=
"text-gray-700"
>
{
data
.
comment
?
data
.
comment
:
"
설명없는 설문조사
"
}
</
p
>
</
div
>
<
div
className
=
"flex flex-col px-5 py-3"
>
<
div
className
=
"h-12"
>
<
p
className
=
"font-bold"
>
{
data
.
title
?
data
.
title
:
"
제목없는 설문조사
"
}
</
p
>
<
p
className
=
"text-gray-500 text-sm"
>
{
data
.
updatedAt
?.
substring
(
0
,
10
)
}
</
p
>
</
div
>
<
div
className
=
"flex justify-end pt-1"
>
<
button
type
=
"button"
className
=
"bg-themeColor rounded text-white py-1 px-1.5 mr-1"
onClick
=
{
editSurvey
}
>
수정
</
button
>
<
button
type
=
"button"
className
=
"bg-themeColor rounded text-white py-1 px-1.5 ml-1"
onClick
=
{
deleteSurvey
}
>
삭제
</
button
>
</
div
>
</
div
>
</
div
>
);
};
frontend/src/profile/Profile.tsx
View file @
2c9d5fe2
...
...
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
import
{
useNavigate
}
from
"
react-router-dom
"
;
import
{
surveyApi
}
from
"
../apis
"
;
import
{
SurveyType
}
from
"
../types
"
;
import
{
MySurveyCard
}
from
"
./MySurvey
"
;
import
{
MySurveyCard
}
from
"
./MySurvey
Card
"
;
const
testData
=
[
{
id
:
0
,
name
:
"
이름1
"
,
description
:
"
설명1
"
},
...
...
@@ -21,7 +21,8 @@ export const Profile = () => {
useEffect
(()
=>
{
getSurveys
();
},
[
cardDatas
]);
},
[]);
async
function
createSurvey
()
{
const
newSurvey
:
SurveyType
=
await
surveyApi
.
createSurvey
(
survey
);
navigate
(
`/surveys/edit/
${
newSurvey
.
_id
}
`
,
{
...
...
@@ -31,24 +32,25 @@ export const Profile = () => {
async
function
getSurveys
()
{
const
surveys
:
SurveyType
[]
=
await
surveyApi
.
getSurveys
();
console
.
log
(
surveys
);
setCardDatas
(
surveys
);
}
// let surveys = getSurvey(_id);
return
(
<
div
className
=
"flex flex-col items-center"
>
<
div
className
=
"m-5"
>
나의 설문조사
</
div
>
<
div
className
=
"m-5
text-bold
"
>
나의 설문조사
</
div
>
<
div
className
=
"flex space-x-4 mt-5"
>
<
button
onClick
=
{
createSurvey
}
className
=
"flex h-60 w-
48
items-center border-2 border-themeColor font-bold bg-gray-200 hover:bg-themeColor rounded-lg "
className
=
"flex h-60 w-
52
items-center border-2 border-themeColor font-bold bg-gray-200 hover:bg-themeColor rounded-lg "
>
<
div
className
=
"text-center px-6 py-6 font-bold text-gray-500 place-items-center hover:text-white"
>
CREATE NEW SURVEY!
</
div
>
</
button
>
{
cardDatas
.
map
((
data
,
i
)
=>
{
return
<
MySurveyCard
data
=
{
data
}
key
=
{
i
}
/>;
{
cardDatas
.
map
((
data
,
i
ndex
)
=>
{
return
<
MySurveyCard
data
=
{
data
}
key
=
{
i
ndex
}
/>;
})
}
</
div
>
</
div
>
...
...
frontend/src/questions/Question.tsx
View file @
2c9d5fe2
...
...
@@ -34,9 +34,6 @@ export const Question = ({
changeCurrentId
,
currentId
,
}:
Props
)
=>
{
const
handleEditClick
=
()
=>
{
changeCurrentId
(
element
.
_id
);
};
async
function
handleEditComplete
()
{
try
{
const
newQuestion
:
BasicQuestionType
=
await
questionApi
.
updateQuestion
(
...
...
@@ -92,10 +89,6 @@ export const Question = ({
handleQuestion
(
element
.
_id
);
}
function
handleDelete
()
{
deleteQuestion
(
element
.
_id
);
}
function
getContent
(
element
:
BasicQuestionType
)
{
switch
(
element
.
type
)
{
case
"
essay
"
:
...
...
@@ -138,7 +131,17 @@ export const Question = ({
return
<></>;
}
}
const
handleRequired
=
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
{
checked
,
value
}
=
event
.
currentTarget
;
element
[
value
]
=
checked
;
handleQuestion
(
element
.
_id
);
};
const
handleDelete
=
()
=>
{
deleteQuestion
(
element
.
_id
);
};
const
handleEditClick
=
()
=>
{
changeCurrentId
(
element
.
_id
);
};
return
(
<
div
className
=
"flex flex-col container w-4/5 h-auto border-2 border-themeColor items-center m-3 py-2"
>
<
div
className
=
"flex h-16 w-full place-content-between items-center"
>
...
...
@@ -184,12 +187,17 @@ export const Question = ({
{
getContent
(
element
)
}
<
div
className
=
"place-self-end py-2"
>
<
button
type
=
"button"
className
=
"px-1"
>
<
input
type
=
"checkbox"
id
=
"isRequired"
value
=
"isRequired"
onChange
=
{
handleRequired
}
disabled
=
{
currentId
!==
element
.
_id
}
checked
=
{
element
.
isRequired
}
/>
<
label
htmlFor
=
"isRequired"
className
=
"px-1"
>
필수
</
button
>
<
button
type
=
"button"
className
=
"px-1"
>
옵션
</
button
>
</
label
>
<
button
type
=
"button"
className
=
"px-1"
onClick
=
{
handleDelete
}
>
삭제
</
button
>
...
...
frontend/src/questions/RatingForm.tsx
View file @
2c9d5fe2
...
...
@@ -31,7 +31,7 @@ export const RatingForm = ({ element, handleQuestion, currentId }: Props) => {
handleQuestion
(
element
.
_id
);
}
function
addValue
()
{
choices
.
push
({
text
:
"
0
"
,
value
:
choices
.
length
});
choices
.
push
({
text
:
""
,
value
:
choices
.
length
});
element
.
content
.
choices
=
choices
;
handleQuestion
(
element
.
_id
);
}
...
...
frontend/src/survey/EditSurvey.tsx
View file @
2c9d5fe2
import
React
,
{
FormEvent
,
useEffect
,
useState
}
from
"
react
"
;
import
{
useParams
}
from
"
react-router-dom
"
;
import
{
useParams
,
useNavigate
}
from
"
react-router-dom
"
;
import
{
questionApi
,
surveyApi
}
from
"
../apis
"
;
import
{
SpinnerIcon
}
from
"
../icons
"
;
import
{
Question
}
from
"
../questions
"
;
import
{
BasicQuestionType
,
SurveyType
}
from
"
../types
"
;
import
{
catchErrors
}
from
"
../helpers
"
;
export
const
EditSurvey
=
()
=>
{
let
{
surveyId
}
=
useParams
<
{
surveyId
:
string
}
>
();
const
navigate
=
useNavigate
();
useEffect
(()
=>
{
getSurvey
();
},
[
surveyId
]);
...
...
@@ -35,8 +37,10 @@ export const EditSurvey = () => {
setLoading
(
true
);
}
}
catch
(
error
)
{
console
.
log
(
"
에러발생
"
);
// catchErrors(error, setError)
catchErrors
(
error
,
setError
);
// navigate(`/`, {
// replace: false,
// });
}
finally
{
setLoading
(
false
);
}
...
...
@@ -57,13 +61,12 @@ export const EditSurvey = () => {
try
{
const
newSurvey
:
SurveyType
=
await
surveyApi
.
editSurvey
(
survey
);
console
.
log
(
newSurvey
);
//
setSuccess(true);
//
setError("");
setSuccess
(
true
);
setError
(
""
);
}
catch
(
error
)
{
console
.
log
(
"
에러발생
"
);
// catchErrors(error, setError)
catchErrors
(
error
,
setError
);
}
finally
{
//
setLoading(false);
setLoading
(
false
);
}
}
...
...
@@ -71,13 +74,12 @@ export const EditSurvey = () => {
try
{
const
newQuestion
:
BasicQuestionType
=
await
questionApi
.
createQuestion
();
setSurvey
({
...
survey
,
questions
:
[...
survey
.
questions
,
newQuestion
]
});
//
setSuccess(true);
//
setError("");
setSuccess
(
true
);
setError
(
""
);
}
catch
(
error
)
{
console
.
log
(
"
에러발생
"
);
// catchErrors(error, setError)
catchErrors
(
error
,
setError
);
}
finally
{
//
setLoading(false);
setLoading
(
false
);
}
}
...
...
@@ -88,13 +90,12 @@ export const EditSurvey = () => {
id
);
setSurvey
({
...
survey
,
questions
:
newList
.
filter
((
a
)
=>
a
.
_id
!==
id
)
});
//
setSuccess(true);
//
setError("");
setSuccess
(
true
);
setError
(
""
);
}
catch
(
error
)
{
console
.
log
(
"
에러발생
"
);
// catchErrors(error, setError)
catchErrors
(
error
,
setError
);
}
finally
{
//
setLoading(false);
setLoading
(
false
);
}
}
...
...
@@ -102,6 +103,7 @@ export const EditSurvey = () => {
console
.
log
(
questions
);
return
(
<>
{
error
?
alert
(
error
)
:
<></>
}
{
loading
&&
(
<
SpinnerIcon
className
=
"animate-spin h-5 w-5 mr-1 text-slate"
/>
)
}
...
...
@@ -113,6 +115,7 @@ export const EditSurvey = () => {
name
=
"title"
className
=
"font-bold text-4xl text-center m-2 border-b-2"
placeholder
=
"설문지 제목"
value
=
{
survey
.
title
}
onChange
=
{
handleSurvey
}
></
input
>
<
input
...
...
@@ -121,6 +124,7 @@ export const EditSurvey = () => {
className
=
"font-bold text-1xl text-center m-2 resize-none"
placeholder
=
"설문조사에 대한 설명을 입력해주세요"
size
=
{
50
}
value
=
{
survey
.
comment
}
onChange
=
{
handleSurvey
}
></
input
>
</
div
>
...
...
@@ -143,7 +147,7 @@ export const EditSurvey = () => {
type
=
"submit"
className
=
"border bg-themeColor my-5 py-2 px-3 font-bold text-white"
>
설문조사 생성
저장하기
</
button
>
</
div
>
</
div
>
...
...
frontend/src/types/index.ts
View file @
2c9d5fe2
...
...
@@ -16,6 +16,8 @@ export interface SurveyType {
title
:
string
;
comment
:
string
;
questions
:
BasicQuestionType
[];
createdAt
?:
string
;
updatedAt
?:
string
;
}
export
interface
BasicQuestionType
{
...
...
src/controllers/question.controller.ts
View file @
2c9d5fe2
...
...
@@ -41,10 +41,11 @@ export const userByQuestionId = async (
const
req
=
reqExp
as
TypedRequestAuth
<
{
userId
:
string
}
>
;
let
user
=
await
questionDb
.
findUserByQuestionId
(
questionId
);
if
(
!
user
)
{
return
res
.
status
(
404
).
send
(
"
사용자를 찾을 수 없습니다
"
);
return
res
.
status
(
404
).
send
(
"
올바른 접근이 아닙니다
"
);
}
else
{
req
.
user
=
user
;
next
();
}
req
.
user
=
user
;
next
();
}
catch
(
error
:
any
)
{
return
res
.
status
(
500
)
...
...
src/controllers/survey.controller.ts
View file @
2c9d5fe2
...
...
@@ -8,7 +8,7 @@ export interface TypedRequestAuth<T> extends Request {
}
export
const
createSurvey
=
asyncWrap
(
async
(
reqExp
:
Request
,
res
:
Response
,
next
:
NextFunction
)
=>
{
async
(
reqExp
:
Request
,
res
:
Response
)
=>
{
const
req
=
reqExp
as
TypedRequestAuth
<
{
userId
:
string
}
>
;
const
{
userId
}
=
req
.
auth
;
let
survey
=
req
.
body
;
...
...
@@ -21,14 +21,16 @@ export const createSurvey = asyncWrap(
export
const
getSurveyById
=
asyncWrap
(
async
(
req
,
res
)
=>
{
const
{
surveyId
}
=
req
.
params
;
const
survey
=
await
surveyDb
.
getSurveyById
(
surveyId
);
const
survey
:
any
=
await
surveyDb
.
getSurveyById
(
surveyId
);
console
.
log
(
"
Get완료
"
,
survey
);
return
res
.
json
(
survey
);
});
//동혁
export
const
getSurveys
=
asyncWrap
(
async
(
req
,
res
)
=>
{
const
surveys
=
await
surveyDb
.
getSurveys
();
export
const
getSurveys
=
asyncWrap
(
async
(
reqExp
:
Request
,
res
:
Response
)
=>
{
const
req
=
reqExp
as
TypedRequestAuth
<
{
userId
:
string
}
>
;
const
{
userId
}
=
req
.
auth
;
const
surveys
=
await
surveyDb
.
getSurveys
(
userId
);
return
res
.
json
(
surveys
);
});
...
...
@@ -38,6 +40,12 @@ export const updateSurvey = asyncWrap(async (req, res) => {
return
res
.
json
(
newSurvey
);
});
export
const
deleteSurvey
=
asyncWrap
(
async
(
req
,
res
)
=>
{
const
{
surveyId
}
=
req
.
params
;
const
survey
=
await
surveyDb
.
deleteSurvey
(
surveyId
);
return
res
.
json
(
survey
);
});
export
const
userBySurveyId
=
async
(
reqExp
:
Request
,
res
:
Response
,
...
...
@@ -48,10 +56,11 @@ export const userBySurveyId = async (
const
req
=
reqExp
as
TypedRequestAuth
<
{
userId
:
string
}
>
;
let
user
=
await
surveyDb
.
findUserBySurveyId
(
surveyId
);
if
(
!
user
)
{
return
res
.
status
(
404
).
send
(
"
사용자를 찾을 수 없습니다
"
);
return
res
.
status
(
404
).
send
(
"
올바른 접근이 아닙니다.
"
);
}
else
{
req
.
user
=
user
;
next
();
}
req
.
user
=
user
;
next
();
}
catch
(
error
:
any
)
{
return
res
.
status
(
500
)
...
...
src/db/survey.db.ts
View file @
2c9d5fe2
...
...
@@ -20,8 +20,9 @@ export const getSurveyById = async (surveyId: string) => {
const
survey
=
await
Survey
.
findById
(
surveyId
).
populate
(
"
questions
"
);
return
survey
;
};
export
const
getSurveys
=
async
()
=>
{
const
surveys
=
await
Survey
.
find
();
export
const
getSurveys
=
async
(
userId
:
string
)
=>
{
const
surveys
=
await
Survey
.
find
({
user
:
userId
});
return
surveys
;
};
...
...
@@ -29,3 +30,9 @@ export const updateSurvey = async (survey: ISurvey) => {
const
newSurvey
=
await
Survey
.
findOneAndUpdate
({
_id
:
survey
.
_id
},
survey
);
return
newSurvey
;
};
export
const
deleteSurvey
=
async
(
surveyId
:
string
)
=>
{
console
.
log
(
"
survey id
"
,
surveyId
);
const
survey
=
await
Survey
.
findOneAndDelete
({
_id
:
surveyId
});
return
survey
;
};
src/models/survey.model.ts
View file @
2c9d5fe2
import
{
model
,
Schema
,
Types
}
from
"
mongoose
"
;
import
{
Question
}
from
"
.
"
;
export
interface
ISurvey
{
_id
?:
Types
.
ObjectId
;
...
...
@@ -8,11 +9,25 @@ export interface ISurvey {
questions
:
Types
.
ObjectId
[];
}
const
schema
=
new
Schema
<
ISurvey
>
({
title
:
{
type
:
String
},
comment
:
{
type
:
String
},
user
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
User
"
},
questions
:
[{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Question
"
}],
});
const
schema
=
new
Schema
<
ISurvey
>
(
{
title
:
{
type
:
String
},
comment
:
{
type
:
String
},
user
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
User
"
},
questions
:
[{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Question
"
}],
},
{
timestamps
:
true
}
);
schema
.
pre
(
"
findOneAndDelete
"
,
{
document
:
false
,
query
:
true
},
async
function
(
next
)
{
const
doc
=
await
this
.
model
.
findOne
(
this
.
getFilter
());
const
questions
=
doc
.
questions
;
await
Question
.
deleteMany
({
_id
:
{
$in
:
questions
}
});
next
();
}
);
export
default
model
<
ISurvey
>
(
"
Survey
"
,
schema
);
src/routes/survey.route.ts
View file @
2c9d5fe2
...
...
@@ -3,13 +3,20 @@ import { authCtrl, surveyCtrl } from "../controllers";
const
router
=
express
.
Router
();
router
.
route
(
"
/
"
).
get
(
authCtrl
.
requireLogin
,
surveyCtrl
.
getSurveys
);
router
.
route
(
"
/create
"
).
post
(
authCtrl
.
requireLogin
,
surveyCtrl
.
createSurvey
);
router
.
route
(
"
/edit/:surveyId
"
)
.
get
(
authCtrl
.
requireLogin
,
authCtrl
.
authenticate
,
surveyCtrl
.
getSurveyById
)
.
put
(
authCtrl
.
requireLogin
,
authCtrl
.
authenticate
,
surveyCtrl
.
updateSurvey
);
router
.
route
(
"
/
"
)
.
get
(
authCtrl
.
requireLogin
,
surveyCtrl
.
getSurveys
);
router
.
route
(
"
/delete/:surveyId
"
)
.
delete
(
authCtrl
.
requireLogin
,
authCtrl
.
authenticate
,
surveyCtrl
.
deleteSurvey
);
router
.
param
(
"
surveyId
"
,
surveyCtrl
.
userBySurveyId
);
export
default
router
;
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