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
travel
Commits
deade4a1
Commit
deade4a1
authored
Jul 20, 2022
by
Lee Soobeom
Browse files
editpost 기능
parent
4415469c
Changes
11
Hide whitespace changes
Inline
Side-by-side
frontend/src/App.tsx
View file @
deade4a1
...
...
@@ -7,6 +7,7 @@ import { Header, Body } from "./home";
import
{
Board
}
from
"
./board
"
;
import
Posting
from
"
./post/posting
"
;
import
{
Layout
}
from
"
./commons
"
;
import
{
EditPost
}
from
"
./post/editpost
"
;
export
const
App
=
()
=>
{
return
(
...
...
@@ -26,7 +27,9 @@ export const App = () => {
}
/>
<
Route
path
=
"board"
element
=
{
<
Board
/>
}
/>
<
Route
path
=
"post/:postId"
element
=
{
<
IntoPost
/>
}
/>
<
Route
path
=
"post/:postId/"
element
=
{
<
IntoPost
/>
}
>
<
Route
path
=
"edit"
element
=
{
<
EditPost
/>
}
/>
</
Route
>
<
Route
path
=
"profile"
element
=
{
...
...
frontend/src/apis/post.api.ts
View file @
deade4a1
...
...
@@ -4,7 +4,6 @@ import { PostType } from "../types";
export
const
posting
=
async
(
post
:
PostType
)
=>
{
const
{
data
}
=
await
axios
.
post
(
`
${
baseUrl
}
/posts/`
,
post
);
return
data
;
};
...
...
@@ -24,3 +23,13 @@ export const getPostByPostId = async (_id: string) => {
const
{
data
}
=
await
axios
.
get
(
`
${
baseUrl
}
/posts/
${
_id
}
`
);
return
data
;
};
export
const
deletePost
=
async
(
_id
:
string
)
=>
{
const
{
data
}
=
await
axios
.
delete
(
`
${
baseUrl
}
/posts/
${
_id
}
`
);
return
data
;
};
export
const
updating
=
async
(
post
:
PostType
)
=>
{
const
{
data
}
=
await
axios
.
put
(
`
${
baseUrl
}
/posts/
${
post
.
_id
}
`
,
post
);
return
data
;
};
frontend/src/post/editpost.tsx
0 → 100644
View file @
deade4a1
import
React
,
{
FormEvent
,
useState
}
from
"
react
"
;
import
{
useNavigate
,
useLocation
}
from
"
react-router-dom
"
;
import
isLength
from
"
validator/lib/isLength
"
;
import
equals
from
"
validator/lib/equals
"
;
import
{
catchErrors
}
from
"
../helpers
"
;
import
{
PostType
}
from
"
../types
"
;
import
{
postApi
}
from
"
../apis
"
;
import
{
PostState
}
from
"
./intopost
"
;
export
function
EditPost
()
{
const
[
city
,
setCity
]
=
useState
<
string
>
(
"
질문종류
"
);
const
[
theme
,
setTheme
]
=
useState
<
string
>
(
"
질문종류
"
);
const
[
title
,
setTitle
]
=
useState
<
string
>
(
""
);
const
[
text
,
setText
]
=
useState
<
string
>
(
""
);
const
navigate
=
useNavigate
();
const
location
=
useLocation
()
as
PostState
;
const
post
=
location
.
state
;
const
[
user
,
setUser
]
=
useState
<
PostType
>
({
title
:
post
.
title
,
text
:
post
.
text
,
theme
:
post
.
theme
,
city
:
post
.
city
,
date
:
post
.
date
,
user
:
post
.
user
,
counts
:
0
,
_id
:
post
.
_id
,
});
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
error
,
setError
]
=
useState
(
""
);
const
[
disabled
,
setDisabled
]
=
useState
(
false
);
const
[
success
,
setSuccess
]
=
useState
(
false
);
async
function
handlePostSubmit
(
event
:
FormEvent
)
{
event
.
preventDefault
();
try
{
setError
(
""
);
console
.
log
(
"
user data
"
,
user
);
if
(
postingFormMatch
())
{
setLoading
(
true
);
const
res
=
await
postApi
.
updating
(
user
);
navigate
(
"
/board
"
,
{
replace
:
true
});
setSuccess
(
true
);
setError
(
""
);
}
}
catch
(
error
)
{
console
.
log
(
"
에러발생
"
);
catchErrors
(
error
,
setError
);
}
finally
{
setLoading
(
false
);
}
}
function
postingFormMatch
()
{
if
(
!
isLength
(
user
.
title
??
""
,
{
min
:
1
}))
{
setError
(
"
제목을 입력해 주세요.
"
);
return
false
;
}
else
if
(
!
isLength
(
user
.
text
??
""
,
{
min
:
1
}))
{
setError
(
"
내용을 입력해 주세요.
"
);
return
false
;
}
else
if
(
equals
(
city
,
"
질문종류
"
))
{
setError
(
"
테마를 선택해 주세요.
"
);
return
false
;
}
else
if
(
equals
(
theme
,
"
질문종류
"
))
{
setError
(
"
도시를 선택해 주세요.
"
);
return
false
;
}
else
{
return
true
;
}
}
const
titleChange
=
(
event
:
React
.
ChangeEvent
<
HTMLTextAreaElement
>
)
=>
{
const
title
=
event
.
currentTarget
.
value
;
const
newUser
=
{
...
user
,
title
:
title
};
console
.
log
(
event
.
currentTarget
.
value
);
setTitle
(
event
.
currentTarget
.
value
);
setUser
(
newUser
);
};
const
textChange
=
(
event
:
React
.
ChangeEvent
<
HTMLTextAreaElement
>
)
=>
{
const
text
=
event
.
currentTarget
.
value
;
const
newUser
=
{
...
user
,
text
:
text
};
console
.
log
(
event
.
currentTarget
.
value
);
setText
(
event
.
currentTarget
.
value
);
setUser
(
newUser
);
};
const
cityChange
=
(
event
:
React
.
ChangeEvent
<
HTMLSelectElement
>
)
=>
{
const
city
=
event
.
currentTarget
.
value
;
const
newUser
=
{
...
user
,
city
:
city
};
console
.
log
(
event
.
currentTarget
.
value
);
setCity
(
event
.
currentTarget
.
value
);
setUser
(
newUser
);
};
const
themeChange
=
(
event
:
React
.
ChangeEvent
<
HTMLSelectElement
>
)
=>
{
const
theme
=
event
.
currentTarget
.
value
;
const
newUser
=
{
...
user
,
theme
:
theme
};
console
.
log
(
event
.
currentTarget
.
value
);
setTheme
(
event
.
currentTarget
.
value
);
setUser
(
newUser
);
};
return
(
<
div
className
=
"flex flex-col border-3"
>
<
form
onSubmit
=
{
handlePostSubmit
}
className
=
"w-full items-center"
>
<
div
className
=
"flex flex-row relative"
>
<
p
className
=
"basis-1/12 gap-x-8"
>
Id
</
p
>
<
p
className
=
"basis-8/12 invisible"
>
empty
</
p
>
<
select
name
=
"city"
id
=
"Questions"
className
=
"border border-3 border-black w-1/12"
onChange
=
{
cityChange
}
defaultValue
=
"질문종류"
>
<
option
value
=
"질문종류"
>
도시
</
option
>
<
option
value
=
"Seoul"
>
서울
</
option
>
<
option
value
=
"Busan"
>
부산
</
option
>
<
option
value
=
"Incheon"
>
인천
</
option
>
<
option
value
=
"Daegoo"
>
대구
</
option
>
<
option
value
=
"Kwangjoo"
>
광주
</
option
>
<
option
value
=
"Daejeon"
>
대전
</
option
>
<
option
value
=
"Woolsan"
>
울산
</
option
>
<
option
value
=
"Sejong"
>
세종
</
option
>
<
option
value
=
"Dokdo"
>
독도
</
option
>
<
option
value
=
"Jeju"
>
제주
</
option
>
</
select
>
<
select
name
=
"theme"
id
=
"Questions"
className
=
"border border-3 border-black w-1/12"
onChange
=
{
themeChange
}
defaultValue
=
"질문종류"
>
<
option
value
=
"질문종류"
>
테마
</
option
>
<
option
value
=
"cycling"
>
사이클링
</
option
>
<
option
value
=
"surfing"
>
서핑
</
option
>
<
option
value
=
"activity"
>
액티비티
</
option
>
<
option
value
=
"camping"
>
캠핑
</
option
>
<
option
value
=
"sking"
>
스키
</
option
>
<
option
value
=
"boat"
>
보트
</
option
>
<
option
value
=
"desert"
>
사막
</
option
>
<
option
value
=
"golf"
>
골프
</
option
>
<
option
value
=
"cave"
>
동굴
</
option
>
<
option
value
=
"history"
>
문화재
</
option
>
<
option
value
=
"zoo"
>
동물원
</
option
>
<
option
value
=
"cycling"
>
사이클링
</
option
>
</
select
>
<
button
type
=
"submit"
className
=
"border border-black basis-1/12 gap-x-8"
>
글쓰기
</
button
>
</
div
>
<
div
className
=
"flex border-4"
>
<
textarea
name
=
"title"
onChange
=
{
titleChange
}
placeholder
=
"title"
className
=
"w-full h-8"
></
textarea
>
</
div
>
<
div
className
=
"flex border-2"
>
<
textarea
onChange
=
{
textChange
}
name
=
"text"
placeholder
=
"text"
className
=
"w-full h-96"
></
textarea
>
</
div
>
</
form
>
</
div
>
);
}
frontend/src/post/intopost.tsx
View file @
deade4a1
import
React
from
"
react
"
;
import
{
useLocation
}
from
"
react-router-dom
"
;
import
React
,
{
MouseEvent
}
from
"
react
"
;
import
{
useLocation
,
useNavigate
,
Link
}
from
"
react-router-dom
"
;
import
{
postApi
}
from
"
../apis
"
;
import
{
PostType
}
from
"
../types
"
;
interface
PostState
{
export
interface
PostState
{
state
:
PostType
;
}
export
function
IntoPost
()
{
const
location
=
useLocation
()
as
PostState
;
const
post
=
location
.
state
;
const
navigate
=
useNavigate
();
// console.log(post);
const
handleDeleteClick
=
async
(
event
:
MouseEvent
<
HTMLButtonElement
>
)
=>
{
const
postId
=
event
.
currentTarget
.
id
;
const
res
=
await
postApi
.
deletePost
(
postId
);
navigate
(
"
/board
"
,
{
replace
:
true
});
console
.
log
(
"
delete post
"
,
res
);
};
return
(
<
div
>
<
div
>
<
div
className
=
"flex flex-row basis-8"
>
<
div
className
=
"border-2 border-current rounded"
>
<
button
id
=
{
post
.
_id
}
onClick
=
{
handleDeleteClick
}
>
delete
</
button
>
</
div
>
<
div
className
=
"border-2 border-current rounded"
>
<
Link
to
=
{
`/post/
${
post
.
_id
}
/edit`
}
state
=
{
post
}
>
<
button
>
update
</
button
>
</
Link
>
</
div
>
</
div
>
<
div
className
=
"flex flex-row"
>
<
div
className
=
"flex basis-3/4"
>
제목:
{
post
.
title
}
</
div
>
<
div
className
=
"flex basis-1/4"
>
작성자: nickname
</
div
>
<
div
className
=
"flex basis-3/4 border-2 border-black rounded"
>
제목:
{
post
.
title
}
</
div
>
<
div
className
=
"flex basis-1/4 border-2 border-black rounded"
>
작성자: nickname
</
div
>
</
div
>
<
div
className
=
"flex flex-row"
>
<
div
className
=
"flex basis-1/4"
>
도시:
{
post
.
city
}
</
div
>
<
div
className
=
"flex basis-1/4"
>
테마:
{
post
.
theme
}
</
div
>
<
div
className
=
"flex basis-1/4"
>
작성일:
{
post
.
date
}
</
div
>
<
div
className
=
"flex basis-1/4"
>
조회수:
{
post
.
counts
}
</
div
>
<
div
className
=
"flex basis-1/4 border-2 border-black rounded"
>
도시:
{
post
.
city
}
</
div
>
<
div
className
=
"flex basis-1/4 border-2 border-black rounded"
>
테마:
{
post
.
theme
}
</
div
>
<
div
className
=
"flex basis-1/4 border-2 border-black rounded"
>
작성일:
{
post
.
date
}
</
div
>
<
div
className
=
"flex basis-1/4 border-2 border-black rounded"
>
조회수:
{
post
.
counts
}
</
div
>
</
div
>
</
div
>
<
div
>
{
post
.
text
}
</
div
>
<
div
className
=
"border-2 border-black rounded h-96"
>
{
post
.
text
}
</
div
>
</
div
>
);
}
frontend/src/post/post.tsx
View file @
deade4a1
...
...
@@ -7,7 +7,7 @@ export type Props = {
post
:
PostType
;
handleClick
:
MouseEventHandler
;
};
// Link opts = state : send obj , useLocation location.state
export
default
function
Post
({
handleClick
,
post
}:
Props
)
{
return
(
<
div
className
=
"flex flex-row h-16 divide-x-2 border-2 border-solid"
>
...
...
frontend/src/post/posting.tsx
View file @
deade4a1
...
...
@@ -30,14 +30,15 @@ export default function Posting() {
const
[
success
,
setSuccess
]
=
useState
(
false
);
async
function
handlePostSubmit
(
event
:
FormEvent
)
{
event
.
preventDefault
();
// prevent onSubmit -> rerendering
event
.
preventDefault
();
try
{
setError
(
""
);
console
.
log
(
"
user data
"
,
user
);
if
(
postingFormMatch
())
{
setLoading
(
true
);
const
res
=
await
postApi
.
posting
(
user
);
//
console.log("서버연결됬나요", res);
console
.
log
(
"
서버연결됬나요
"
,
res
);
// console.log("user save");
navigate
(
"
/board
"
,
{
replace
:
true
});
setSuccess
(
true
);
...
...
frontend/src/types/index.tsx
View file @
deade4a1
...
...
@@ -16,7 +16,7 @@ export interface PostType {
text
:
string
;
theme
:
string
;
city
:
string
;
date
:
string
;
date
:
string
|
number
;
counts
:
number
;
_id
:
string
;
user
:
string
;
...
...
src/controllers/post.controller.ts
View file @
deade4a1
...
...
@@ -15,10 +15,9 @@ export const postCreate = asyncWrap(async (reqExp, res, next) => {
theme
:
string
;
city
:
string
;
date
:
Date
;
counts
:
number
;
};
console
.
log
(
"
body
"
,
req
.
body
);
// 1) title 빈 문자열인지 확인
if
(
!
isLength
(
title
??
""
,
{
min
:
1
}))
{
return
res
.
status
(
422
).
send
(
"
제목을 한 글자 이상 입력해주세요
"
);
...
...
@@ -46,10 +45,12 @@ export const postCreate = asyncWrap(async (reqExp, res, next) => {
text
,
theme
,
city
,
date
,
date
:
Date
.
now
()
,
user
:
userId
,
});
console
.
log
(
"
post
"
,
newPost
);
return
res
.
json
(
newPost
);
});
...
...
@@ -90,3 +91,44 @@ export const getOnePost = asyncWrap(async (req, res) => {
return
res
.
json
(
post
);
});
export
const
deleteOnePost
=
asyncWrap
(
async
(
req
,
res
)
=>
{
const
{
postId
}
=
req
.
params
;
console
.
log
(
postId
);
const
deleteCount
=
await
postDb
.
deletePost
(
postId
);
return
res
.
json
(
deleteCount
);
});
export
const
updatePost
=
asyncWrap
(
async
(
reqExp
,
res
)
=>
{
const
req
=
reqExp
as
TypedRequestAuth
<
{
userId
:
string
}
>
;
const
{
title
,
text
,
theme
,
city
,
date
}
=
req
.
body
as
{
title
:
string
;
text
:
string
;
theme
:
string
;
city
:
string
;
date
:
Date
;
counts
:
number
;
};
const
userId
=
req
.
auth
.
userId
;
const
{
postId
}
=
req
.
params
;
const
updatePost
=
await
postDb
.
updateOnePost
(
{
title
,
text
,
theme
,
city
,
date
:
Date
.
now
(),
counts
:
req
.
body
.
counts
,
user
:
userId
,
},
postId
);
console
.
log
(
"
게시글 수정 후
"
,
updatePost
);
return
res
.
json
(
updatePost
);
});
src/db/post.db.ts
View file @
deade4a1
...
...
@@ -24,7 +24,6 @@ export const addOneCount = async (_id: string, counts: number) => {
{
counts
:
counts
},
{
new
:
true
}
);
// console.log(newCounts);
return
newCounts
;
...
...
@@ -34,3 +33,17 @@ export const getPost = async (_id: string) => {
const
post
=
await
Post
.
findOne
({
_id
:
_id
});
return
post
;
};
export
const
deletePost
=
async
(
_id
:
string
)
=>
{
const
res
=
await
Post
.
deleteOne
({
_id
:
_id
});
return
res
;
};
export
const
updateOnePost
=
async
(
post
:
PostType
,
_id
:
string
)
=>
{
const
newPost
=
await
Post
.
findOneAndUpdate
(
{
_id
:
_id
},
{
post
},
{
new
:
true
}
);
return
newPost
;
};
src/models/post.model.ts
View file @
deade4a1
...
...
@@ -6,7 +6,7 @@ export interface PostType {
theme
:
string
;
city
:
string
;
user
:
Types
.
ObjectId
|
string
;
date
:
Date
;
date
:
Date
|
number
;
counts
?:
number
;
}
...
...
@@ -31,7 +31,7 @@ const PostSchema = new Schema<PostType>({
},
date
:
{
type
:
Date
,
default
:
Date
.
now
,
default
:
Date
.
now
()
,
},
counts
:
{
type
:
Number
,
...
...
src/routes/post.route.ts
View file @
deade4a1
...
...
@@ -4,5 +4,16 @@ import { postCtrl, authCtrl } from "../controllers";
const
router
=
express
.
Router
();
router
.
route
(
"
/
"
).
post
(
authCtrl
.
requireLogin
,
postCtrl
.
postCreate
);
router
.
route
(
"
/
"
).
get
(
postCtrl
.
getAllPost
);
router
.
route
(
"
/:postId
"
)
.
post
(
authCtrl
.
requireLogin
,
postCtrl
.
addCounts
)
.
get
(
authCtrl
.
requireLogin
,
postCtrl
.
getOnePost
);
router
.
route
(
"
/:postId
"
).
delete
(
authCtrl
.
requireLogin
,
postCtrl
.
deleteOnePost
);
// authenticate
router
.
route
(
"
/:postId
"
).
put
(
authCtrl
.
requireLogin
,
postCtrl
.
updatePost
);
router
.
param
(
"
postId
"
,
postCtrl
.
userByPostId
);
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