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
14bcff90
Commit
14bcff90
authored
Jul 25, 2022
by
Lee Soobeom
Browse files
Merge remote-tracking branch 'origin/MK20' into develop
parents
35f41d6b
154cb55a
Changes
22
Show whitespace changes
Inline
Side-by-side
frontend/src/App.tsx
View file @
14bcff90
...
...
@@ -14,9 +14,9 @@ export const App = () => {
<
BrowserRouter
>
<
Routes
>
<
Route
element
=
{
<
Layout
/>
}
>
<
Route
path
=
"/"
element
=
{
<
Header
/>
}
>
<
Route
path
=
"login"
element
=
{
<
Login
/>
}
/>
<
Route
path
=
"signup"
element
=
{
<
Signup
/>
}
/>
<
Route
path
=
"/"
element
=
{
<
Header
/>
}
>
<
Route
index
element
=
{
<
Body
/>
}
/>
<
Route
path
=
"posting"
...
...
frontend/src/apis/mainimg.api.ts
View file @
14bcff90
...
...
@@ -7,7 +7,7 @@ export const mainimg = async (formdata: FormData) => {
return
data
;
};
export
const
delmainimg
=
async
(
_id
:
string
)
=>
{
export
const
delmainimg
=
async
(
_id
:
string
)
=>
{
const
{
data
}
=
await
axios
.
delete
(
`
${
baseUrl
}
/mainimg/
${
_id
}
`
);
return
data
;
};
...
...
@@ -17,7 +17,7 @@ export const getmainimg = async () => {
return
data
;
};
export
const
updateimg
=
async
(
formdata
:
FormData
,
_id
:
string
)
=>
{
export
const
updateimg
=
async
(
formdata
:
FormData
,
_id
:
string
)
=>
{
const
{
data
}
=
await
axios
.
put
(
`
${
baseUrl
}
/mainimg/
${
_id
}
`
,
formdata
);
return
data
;
};
\ No newline at end of file
};
frontend/src/apis/profile.api.ts
View file @
14bcff90
...
...
@@ -6,14 +6,11 @@ export const profile = async () => {
return
data
;
};
export
const
picture
=
async
(
formdata
:
FormData
)
=>
{
await
axios
.
post
(
`
${
baseUrl
}
/profile`
,
formdata
);
};
export
const
nickname
=
async
(
formdata
:
FormData
)
=>
{
export
const
profileUpload
=
async
(
formdata
:
FormData
)
=>
{
await
axios
.
post
(
`
${
baseUrl
}
/profile`
,
formdata
);
};
export
const
deleteUser
=
async
()
=>
{
await
axios
.
post
(
`
${
baseUrl
}
/profile/delete`
);
const
success
=
await
axios
.
delete
(
`
${
baseUrl
}
/profile/delete`
);
return
success
;
};
frontend/src/auth/RequireAuth.tsx
View file @
14bcff90
...
...
@@ -7,9 +7,7 @@ export const RequireAuth: FC<{ children: JSX.Element }> = ({ children }) => {
const
location
=
useLocation
();
if
(
!
user
.
isLoggedIn
)
{
return
(
<
Navigate
to
=
{
"
/login
"
}
state
=
{
{
from
:
location
.
pathname
}
}
replace
/>
);
return
<
Navigate
to
=
{
"
/
"
}
state
=
{
{
from
:
location
.
pathname
}
}
replace
/>;
}
return
children
;
};
frontend/src/auth/admin.tsx
View file @
14bcff90
import
React
,
{
FormEvent
,
useEffect
,
useState
,
MouseEvent
}
from
"
react
"
;
import
{
Link
}
from
"
react-router-dom
"
;
import
{
mainimgApi
}
from
"
../apis
"
;
// import { profileUpload } from "../apis/profile.api";
import
{
catchErrors
}
from
"
../helpers
"
;
import
{
MainimgType
}
from
"
../types
"
;
import
{
picture
}
from
"
../apis/profile.api
"
;
import
{
catchErrors
}
from
"
../helpers
"
;
import
{
MySlide
}
from
"
./adminslide
"
;
// export interface ImgState {
// state: MainimgType;
// }
export
default
function
Admin
()
{
// 이미지 전체 불러오기
const
[
getimgs
,
setGetimgs
]
=
useState
<
MainimgType
[]
>
([]);
async
function
imgsData
()
{
const
imgs
=
await
mainimgApi
.
getmainimg
();
setGetimgs
(
imgs
)
}
;
setGetimgs
(
imgs
)
;
}
useEffect
(()
=>
{
imgsData
();
},
[]);
...
...
@@ -39,13 +39,13 @@ export default function Admin() {
function
handleSelectChange
(
event
:
React
.
ChangeEvent
<
HTMLSelectElement
>
)
{
const
{
name
,
value
}
=
event
.
currentTarget
;
console
.
log
(
value
)
console
.
log
(
value
)
;
setAddimg
({
...
addimg
,
[
name
]:
value
});
}
function
handleInputeChange
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
{
const
{
name
,
value
}
=
event
.
currentTarget
;
setAddimg
({
...
addimg
,
[
name
]:
value
});
}
;
}
function
handleFileChange
(
e
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
{
const
file
=
e
.
target
.
files
?.[
0
];
...
...
@@ -67,15 +67,15 @@ export default function Admin() {
const
res
=
await
mainimgApi
.
mainimg
(
formdata
);
console
.
log
(
"
확인 중
"
,
res
);
alert
(
"
img 추가되었습니다
"
);
}
;
}
;
}
}
// 이미지 삭제하기
async
function
handleDeleteClick
(
event
:
MouseEvent
<
HTMLButtonElement
>
)
{
try
{
if
(
confirm
(
"
삭제하시겠습니까?
"
)
==
true
)
{
const
picId
=
event
.
currentTarget
.
id
;
console
.
log
(
"
picId :
"
,
picId
)
console
.
log
(
"
picId :
"
,
picId
)
;
const
res
=
await
mainimgApi
.
delmainimg
(
picId
);
console
.
log
(
"
delete img
"
,
res
);
// setGetimgs(getimgs)
...
...
@@ -85,14 +85,13 @@ export default function Admin() {
}
else
{
return
false
;
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
log
(
"
에러발생
"
);
catchErrors
(
error
,
setError
);
}
finally
{
setLoading
(
false
);
}
;
}
;
}
}
let
limit
=
15
;
const
numPages
=
Math
.
ceil
(
getimgs
.
length
/
15
);
...
...
@@ -100,10 +99,12 @@ export default function Admin() {
// const location = useLocation() as ImgState;
// const img = location.state;
const
slides
=
[]
const
slides
=
[]
;
for
(
let
i
=
0
;
i
<
numPages
;
i
++
)
{
const
k
=
[
getimgs
.
slice
(
i
*
limit
,
i
*
limit
+
limit
).
map
((
picture
,
index
:
number
)
=>
(
getimgs
.
slice
(
i
*
limit
,
i
*
limit
+
limit
)
.
map
((
picture
,
index
:
number
)
=>
(
<
div
key
=
{
index
}
>
<
div
className
=
{
`m-1 shrink-0 bg-gray-200 rounded shadow-md `
}
>
<
img
...
...
@@ -118,12 +119,17 @@ export default function Admin() {
수정
</
Link
>
</
button
>
<
button
id
=
{
picture
.
_id
}
onClick
=
{
handleDeleteClick
}
className
=
"text-xs"
>
<
button
id
=
{
picture
.
_id
}
onClick
=
{
handleDeleteClick
}
className
=
"text-xs"
>
삭제
</
button
>
</
div
>
</
div
>
))]
)),
];
slides
.
push
(
k
);
}
...
...
@@ -182,12 +188,14 @@ export default function Admin() {
<
label
htmlFor
=
"files"
className
=
"border-2 m-5"
>
이미지 선택
</
label
>
</
div
>
<
div
className
=
"flex items-center justify-end gap-3 mt-2 md:mt-0"
>
<
p
>
title :
</
p
>
<
input
name
=
"title"
className
=
"border-2 border-sky-500"
onChange
=
{
handleInputeChange
}
/>
<
input
name
=
"title"
className
=
"border-2 border-sky-500"
onChange
=
{
handleInputeChange
}
/>
</
div
>
</
div
>
<
div
className
=
"my-5 flex items-center"
>
...
...
@@ -196,11 +204,8 @@ export default function Admin() {
</
div
>
</
form
>
<
div
className
=
"flex justify-center"
>
<
MySlide
key
=
{
Math
.
random
()
}
slides
=
{
slides
}
/>
<
MySlide
key
=
{
Math
.
random
()
}
slides
=
{
slides
}
/>
</
div
>
</
div
>
);
}
;
}
frontend/src/auth/index.tsx
View file @
14bcff90
...
...
@@ -3,4 +3,4 @@ export { default as Signup } from "./signup";
export
{
default
as
Profile
}
from
"
./profile
"
;
export
{
RequireAuth
}
from
"
./RequireAuth
"
;
export
{
default
as
Admin
}
from
"
./admin
"
;
export
{
default
as
ImgRewrite
}
from
"
./imgrewrite
"
export
{
default
as
ImgRewrite
}
from
"
./imgrewrite
"
;
frontend/src/auth/login.tsx
View file @
14bcff90
...
...
@@ -36,7 +36,7 @@ export default function Login() {
setLoading
(
true
);
await
login
(
user
.
email
,
user
.
password
,
()
=>
{
if
(
user
.
email
==
"
admin@korea.ac.kr
"
&&
user
.
password
==
"
111111
"
)
{
navigate
(
"
/admin
"
,
{
replace
:
true
})
navigate
(
"
/admin
"
,
{
replace
:
true
})
;
}
else
{
navigate
(
"
/
"
,
{
replace
:
true
});
}
...
...
@@ -54,9 +54,9 @@ export default function Login() {
return
(
<
div
className
=
"flex flex-col items-center my-10"
>
<
div
className
=
"bg-white w-1/2 md:w-1/3 my-8 text-center text-2xl"
>
<
Link
to
=
"/"
>
Travel Report
</
Link
>
<
Link
to
=
"/"
>
로그인
</
Link
>
</
div
>
<
div
className
=
"flex flex-col w-full md:w-
2
/5 p-8 md:p-4"
>
<
div
className
=
"flex flex-col w-full md:w-
3
/5 p-8 md:p-4"
>
<
form
onSubmit
=
{
handleSubmit
}
className
=
"flex flex-col md:flex-row md:justify-around border-2 border-black rounded-xl p-8 gap-y-4"
...
...
frontend/src/auth/profile.tsx
View file @
14bcff90
...
...
@@ -47,32 +47,39 @@ export default function Profile() {
const
userChange
=
async
()
=>
{
const
profile
=
await
handleProfile
();
setEmail
(
profile
.
email
);
setPicturename
(
profile
.
avatar
.
newfilename
);
setPlaceholder
(
profile
.
avatar
.
nickname
);
setPicturename
(
profile
.
fileInfo
.
newfilename
);
setPlaceholder
(
profile
.
fileInfo
.
nickname
);
};
const
handleClick
=
async
(
e
:
React
.
MouseEvent
<
HTMLButtonElement
,
globalThis
.
MouseEvent
>
)
=>
{
e
.
preventDefault
();
const
formdata
=
new
FormData
();
if
(
!
(
file
===
undefined
||
nickname
===
""
))
{
formdata
.
append
(
"
picture
"
,
file
);
formdata
.
append
(
"
nickname
"
,
nickname
);
console
.
log
(
"
both
"
);
await
profileApi
.
picture
(
formdata
);
}
else
if
(
!
(
nickname
===
""
))
{
console
.
log
(
formdata
);
await
profileApi
.
profileUpload
(
formdata
);
}
else
if
(
!
(
file
===
undefined
)
&&
nickname
===
""
)
{
formdata
.
append
(
"
picture
"
,
file
);
await
profileApi
.
profileUpload
(
formdata
);
}
else
if
(
file
===
undefined
&&
!
(
nickname
===
""
))
{
formdata
.
append
(
"
nickname
"
,
nickname
);
console
.
log
(
"
picture
"
);
await
profileApi
.
picture
(
formdata
);
await
profileApi
.
profileUpload
(
formdata
);
}
else
{
alert
(
"
수정할 정보를 입력해주세요.
"
);
}
};
const
deleteClick
=
async
()
=>
{
await
profileApi
.
deleteUser
().
then
(()
=>
{
logout
();
console
.
log
(
"
test
"
);
});
if
(
confirm
(
"
삭제하시겠습니까?
"
)
==
true
)
{
const
success
=
await
profileApi
.
deleteUser
();
if
(
success
)
{
await
logout
();
}
}
else
{
}
};
useEffect
(()
=>
{
...
...
@@ -80,22 +87,24 @@ export default function Profile() {
},
[]);
return
(
<
div
className
=
"grid
md:px-60
"
>
<
div
className
=
"grid "
>
<
form
className
=
"justify-items-center"
>
<
div
className
=
"
ml-20
mt-10"
>
프로필 수정
</
div
>
<
div
className
=
"grid mt-
2
0 border-0 border-y-2 "
>
<
div
className
=
"flex"
>
<
div
className
=
"
py-10
basis-1/5 border-0 border-r-2 bg-gray-100 grid place-items-center shrink-0"
>
<
div
className
=
" mt-10"
>
프로필 수정
</
div
>
<
div
className
=
"grid mt-
1
0 border-0 border-y-2
border-gray-400
"
>
<
div
className
=
"flex
h-20
"
>
<
div
className
=
" basis-1/5 border-0 border-r-2 bg-gray-100 grid place-items-center shrink-0"
>
Email
</
div
>
<
div
className
=
"basis-full my-5 p-5"
>
{
email
}
</
div
>
<
div
className
=
" basis-full grid place-items-center justify-items-stretch px-4"
>
{
email
}
</
div
>
</
div
>
<
div
className
=
"flex border-0 border-t-2"
>
<
div
className
=
"
py-10
basis-1/5 border-0 border-r-2 bg-gray-100 grid place-items-center shrink-0"
>
<
div
className
=
"basis-1/5 border-0 border-r-2 bg-gray-100 grid place-items-center shrink-0"
>
사진
</
div
>
<
div
className
=
"basis-full p
-2
"
>
<
div
className
=
"overflow-hidden w-
40
h-
40
rounded-full border-2 m-5"
>
<
div
className
=
"basis-full p
y-4
"
>
<
div
className
=
"overflow-hidden w-
28
h-
28
rounded-full border-2 m-5"
>
{
imageSrc
?
(
<
img
src
=
{
imageSrc
}
...
...
@@ -119,19 +128,18 @@ export default function Profile() {
</
label
>
</
div
>
</
div
>
<
div
className
=
"flex border-0 border-t-2"
>
<
div
className
=
"
py-10
basis-1/5 border-0 border-r-2 bg-gray-100 grid place-items-center shrink-0"
>
<
div
className
=
"flex border-0 border-t-2
h-20
"
>
<
div
className
=
"basis-1/5 border-0 border-r-2 bg-gray-100 grid place-items-center shrink-0"
>
별명
</
div
>
<
div
className
=
"basis-full "
>
<
input
placeholder
=
{
placeholder
}
className
=
"basis-
full
placeholder:text-black my-
10
ml-5 border-2"
className
=
"basis-
1/5
placeholder:text-black my-
6
ml-5 border-2
"
onChange
=
{
onNickChange
}
/>
</
div
>
</
div
>
</
div
>
<
div
className
=
"grid grid-cols-2 my-4 md:mb-20 justify-items-center"
>
<
button
onClick
=
{
handleClick
}
...
...
frontend/src/auth/signup.tsx
View file @
14bcff90
...
...
@@ -69,61 +69,61 @@ export default function Signup() {
return
(
<
div
className
=
"flex flex-col items-center"
>
<
div
className
=
"
p-12
md:w-40 mt-8
bg-red-400
rounded-2xl"
>
<
Link
to
=
"/"
>
Travel Report
</
Link
>
<
div
className
=
" md:w-40 mt-8
text-center text-2xl
rounded-2xl"
>
<
Link
to
=
"/"
>
회원가입
</
Link
>
</
div
>
<
form
onSubmit
=
{
handleSubmit
}
className
=
"flex flex-col items-center mt-16 gap-y-4"
>
<
form
onSubmit
=
{
handleSubmit
}
className
=
"flex flex-col mt-16 gap-y-4"
>
<
div
className
=
"flex flex-col"
>
<
div
className
=
"flex"
>
<
div
className
=
"basis-1/5 shrink-0"
>
이름
</
div
>
<
input
className
=
"placeholder:text-slate-300 bg-white border border-slate-500 rounded-2xl py-2 pl-9 pr-3 focus:border-black"
placeholder
=
"이름"
className
=
"border-2 focus:border-black"
type
=
"text"
name
=
"name"
onChange
=
{
handleChange
}
/>
</
div
>
<
div
className
=
"flex"
>
<
div
className
=
"basis-1/5 shrink-0"
>
이메일
</
div
>
<
input
className
=
"placeholder:text-slate-300 bg-white border border-slate-500 rounded-2xl py-2 pl-9 pr-3 focus:border-black"
placeholder
=
"이메일"
className
=
"border-2 focus:border-black"
type
=
"email"
name
=
"email"
onChange
=
{
handleChange
}
/>
</
div
>
<
div
className
=
"flex"
>
<
div
className
=
"basis-1/5 shrink-0"
>
비밀번호
</
div
>
<
input
className
=
"
placeholder
:
text
-
slate
-
300
bg
-
white
border
border
-
slate
-
500
rounded
-
2xl
py
-
2
pl
-
9
pr
-
3
focus
:
border
-
black
"
placeholder
=
"비밀번호"
className
=
"border-2 focus:border-black"
type
=
"password"
name
=
"password"
onChange
=
{
handleChange
}
/>
</
div
>
<
div
className
=
"flex"
>
<
div
className
=
"basis-1/5 shrink-0"
>
비밀번호 확인
</
div
>
<
input
className
=
"
placeholder
:
text
-
slate
-
300
bg
-
white
border
border
-
slate
-
500
rounded
-
2xl
py
-
2
pl
-
9
pr
-
3
focus
:
border
-
black
"
placeholder
=
"비밀번호 확인"
className
=
"border-2 focus:border-black"
type
=
"password"
name
=
"password2"
onChange
=
{
handleChange
}
/>
</
div
>
{
error
&&
(
<
div
className
=
"text-red-500 text-sm"
>
<
p
>
{
error
}
</
p
>
</
div
>
)
}
<
button
disabled
=
{
disabled
}
className
=
"border-b border-white"
>
{
loading
&&
(
<
SpinnerIcon
className
=
"animate-spin h-5 w-5 mr-1 text-slate"
/>
)
}
회원가입
</
button
>
</
div
>
</
form
>
</
div
>
);
...
...
frontend/src/home/header.tsx
View file @
14bcff90
...
...
@@ -6,46 +6,56 @@ import "tailwindcss/tailwind.css";
export
default
function
Header
()
{
const
{
logout
}
=
useAuth
();
const
[
search
,
setSearch
]
=
useState
(
""
);
const
handleChange
=
(
e
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
newvalue
=
e
.
target
.
value
;
setSearch
(
newvalue
);
};
return
(
<
div
className
=
"flex flex-col "
>
<
div
className
=
"flex py-10 "
>
<
button
className
=
"shrink-0 mx-5"
>
<
Link
to
=
"/"
className
=
"hover:text-sky-300 focus:text-purple-500"
>
<
div
className
=
"flex flex-col md:px-56 "
>
<
div
className
=
"flex flex-col-reverse pt-3 pb-12 border-b-2 "
>
<
div
className
=
"flex mt-5 justify-between pr-3"
>
<
button
className
=
"ml-3 shrink-0 text-2xl"
>
<
Link
to
=
"/"
className
=
"hover:text-sky-300 active:text-purple-500"
>
Travel Report
</
Link
>
</
button
>
<
div
className
=
"flex "
>
<
input
className
=
"m
d:ml-20 placeholder:text-white
focus:outline-none focus:border-y-4 focus:border-l-4 focus:border-sky-500
md:placeholder:text-slate-40
0 w-
2
0 md:w-
1/2
border-y-4 border-l-4 border-sky-300 pl-9 rounded-l-full focus:border-0"
placeholder
=
"어디로 여행가고 싶나요?"
className
=
"m
l-10
focus:outline-none focus:border-y-4 focus:border-l-4 focus:border-sky-500
w-2
0 w-
4
0 md:w-
4/5
border-y-4 border-l-4 border-sky-300 pl-9 rounded-l-full focus:border-0"
onChange
=
{
handleChange
}
/>
<
button
className
=
"shrink-0 border-y-4 border-r-4 border-sky-500 rounded-r-full pr-4"
>
<
button
className
=
"shrink-0
bg-white
border-y-4 border-r-4 border-sky-500 rounded-r-full pr-4"
>
검색
</
button
>
<
div
className
=
"shrink-0 p-3 md:ml-40 h-12"
>
</
div
>
</
div
>
<
div
className
=
"flex justify-end"
>
<
div
className
=
" p-3 bg-transparent "
>
{
useAuth
().
user
.
isLoggedIn
?
(
<
div
className
=
"flex"
>
<
div
className
=
"flex
text-xs
"
>
<
Link
to
=
"/profile"
className
=
"mr-2 "
>
프로필
</
Link
>
<
div
className
=
"border-0 border-r-2"
></
div
>
<
div
className
=
"border-0 border-r-2
border-black
"
></
div
>
<
div
></
div
>
<
button
className
=
"ml-2 mr-2"
className
=
"ml-2 mr-2
text-xs
"
onClick
=
{
()
=>
{
logout
();
}
}
>
로그아웃
</
button
>
<
div
className
=
"border-0 border-r-2"
></
div
>
<
div
className
=
"border-0 border-r-2
border-black
"
></
div
>
<
div
></
div
>
</
div
>
)
:
(
<
button
className
=
"shrink-0 bg-
white
"
>
<
button
className
=
"shrink-0 bg-
transparent pb-1
"
>
<
Link
className
=
"hover:text-sky-300 focus:text-purple-500"
className
=
"hover:text-sky-300 focus:text-purple-500
text-xs
"
to
=
"/login"
>
로그인
...
...
@@ -53,7 +63,7 @@ export default function Header() {
</
button
>
)
}
</
div
>
<
button
className
=
"shrink-0 bg-
white
"
>
<
button
className
=
"shrink-0 bg-
transparent pr-3 text-xs
"
>
<
Link
to
=
"/board"
className
=
"hover:text-sky-300 focus:text-purple-500"
...
...
@@ -62,6 +72,7 @@ export default function Header() {
</
Link
>
</
button
>
</
div
>
</
div
>
<
Outlet
/>
</
div
>
...
...
frontend/src/home/theme.tsx
View file @
14bcff90
...
...
@@ -6,38 +6,82 @@ type ThemeProps = {
export
default
function
Theme
({
handleClick
}:
ThemeProps
)
{
return
(
<
div
className
=
"overflow-x-auto flex rounded md:justify-center"
>
<
button
id
=
{
"
서핑
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
div
className
=
"overflow-x-auto flex rounded md:justify-center py-2 border-b-2 divide-x-2"
>
<
button
id
=
{
"
surfing
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
서핑
</
button
>
<
button
id
=
{
"
액티비티
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
button
id
=
{
"
activity
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
액티비티
</
button
>
<
button
id
=
{
"
캠핑
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300 "
>
<
button
id
=
{
"
camping
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300 "
>
캠핑
</
button
>
<
button
id
=
{
"
스키
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
button
id
=
{
"
sking
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
스키
</
button
>
<
button
id
=
{
"
보트
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
button
id
=
{
"
boat
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
보트
</
button
>
<
button
id
=
{
"
사막
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
button
id
=
{
"
desert
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
사막
</
button
>
<
button
id
=
{
"
골프
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
button
id
=
{
"
golf
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
골프
</
button
>
<
button
id
=
{
"
동굴
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
button
id
=
{
"
cave
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
동굴
</
button
>
<
button
id
=
{
"
문화재
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
button
id
=
{
"
history
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
문화재
</
button
>
<
button
id
=
{
"
동물원
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
button
id
=
{
"
zoo
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
동물원
</
button
>
<
button
id
=
{
"
사이클링
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
<
button
id
=
{
"
cycling
"
}
onClick
=
{
handleClick
}
className
=
"shrink-0 px-5 hover:text-sky-300"
>
사이클링
</
button
>
</
div
>
...
...
frontend/src/pages/citylist.tsx
View file @
14bcff90
...
...
@@ -7,74 +7,74 @@ type CityProps = {
export
default
function
Citylist
({
handleClick
}:
CityProps
)
{
return
(
<
div
className
=
"overflow-auto w-full flex flex-row md:flex-col md:mr-24 bg-sky-100"
>
<
div
className
=
"text-
center
px-5 py-2 bg-
sky-300
shrink-0"
>
도시
</
div
>
<
div
className
=
"text-
start
px-5 py-2 bg-
white
shrink-0"
>
도시
</
div
>
<
button
id
=
{
"
서울
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
서울
</
button
>
<
button
id
=
{
"
부산
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
부산
</
button
>
<
button
id
=
{
"
인천
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
인천
</
button
>
<
button
id
=
{
"
대구
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
대구
</
button
>
<
button
id
=
{
"
광주
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
광주
</
button
>
<
button
id
=
{
"
대전
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
대전
</
button
>
<
button
id
=
{
"
울산
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
울산
</
button
>
<
button
id
=
{
"
세종
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
세종
</
button
>
<
button
id
=
{
"
독도
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
독도
</
button
>
<
button
id
=
{
"
제주
"
}
onClick
=
{
handleClick
}
className
=
"px-5 py-2 hover:underline shrink-0"
className
=
"
text-start
px-5 py-2 hover:underline shrink-0"
>
제주
</
button
>
...
...
frontend/src/types/index.tsx
View file @
14bcff90
...
...
@@ -31,7 +31,7 @@ export interface SignupUser {
export
interface
Profile
{
_id
:
string
;
email
:
string
;
avatar
:
{
fileInfo
:
{
originalfilename
:
string
;
newfilename
:
string
;
picturepath
:
string
;
...
...
@@ -44,7 +44,7 @@ export interface MainimgType {
theme
:
string
;
city
:
string
;
title
:
string
;
pic
:
{
pic
:
{
originalfilename
:
string
;
newfilename
:
string
;
};
...
...
src/controllers/mainimg.controller.ts
View file @
14bcff90
...
...
@@ -3,21 +3,13 @@ import isLength from "validator/lib/isLength";
import
{
TypedRequestAuth
}
from
"
./auth.controller
"
;
import
{
asyncWrap
}
from
"
../helpers
"
;
import
{
mainimgDb
}
from
"
../db
"
;
import
{
TypedRequest
}
from
"
../types
"
;
import
{
ObjectId
}
from
"
mongoose
"
;
import
formidable
from
"
formidable
"
;
export
const
createMainimg
=
asyncWrap
(
async
(
reqExp
,
res
)
=>
{
const
req
=
reqExp
as
TypedRequestAuth
<
{
userId
:
ObjectId
}
>
;
const
{
userId
}
=
req
.
auth
// const { theme, city, url, title } = req.body as {
// theme: string;
// city: string;
// url: string;
// title: string;
// };
// console.log("body", req.body);
const
{
userId
}
=
req
.
auth
;
const
form
=
formidable
({
uploadDir
:
"
uploads
"
,
...
...
@@ -55,7 +47,6 @@ export const createMainimg = asyncWrap(async (reqExp, res) => {
res
.
json
();
});
// if (!isLength(url ?? "", { min: 1 })) {
// return res.status(422).send("이미지 url을 입력해주세요");
// }
...
...
@@ -79,7 +70,6 @@ export const getMainimg = asyncWrap(async (req, res) => {
return
res
.
json
(
mainimgs
);
});
export
const
deleteMainimg
=
asyncWrap
(
async
(
req
,
res
)
=>
{
const
{
imgId
}
=
req
.
params
;
console
.
log
(
imgId
);
...
...
@@ -91,7 +81,6 @@ export const deleteMainimg = asyncWrap(async (req, res) => {
export
const
updateMainimg
=
asyncWrap
(
async
(
reqExp
,
res
)
=>
{
const
req
=
reqExp
as
TypedRequestAuth
<
{
userId
:
ObjectId
}
>
;
const
form
=
formidable
({
uploadDir
:
"
uploads
"
,
keepExtensions
:
true
,
...
...
@@ -102,7 +91,8 @@ export const updateMainimg = asyncWrap(async (reqExp, res) => {
if
(
!
Array
.
isArray
(
files
.
updatemainimg
))
{
//파일 좁히기 중
if
(
!
(
Array
.
isArray
(
fields
.
id
)
||
!
(
Array
.
isArray
(
fields
.
id
)
||
Array
.
isArray
(
fields
.
city
)
||
Array
.
isArray
(
fields
.
title
)
||
Array
.
isArray
(
fields
.
theme
)
...
...
@@ -112,8 +102,8 @@ export const updateMainimg = asyncWrap(async (reqExp, res) => {
const
city
=
fields
.
city
;
const
title
=
fields
.
title
;
const
theme
=
fields
.
theme
;
console
.
log
(
"
error
"
)
if
(
!
(
files
.
updatemainimg
===
undefined
)){
console
.
log
(
"
error
"
)
;
if
(
!
(
files
.
updatemainimg
===
undefined
))
{
const
originalfilename
=
files
.
updatemainimg
?.
originalFilename
;
const
newfilename
=
files
.
updatemainimg
.
newFilename
;
if
(
!
(
originalfilename
===
null
||
newfilename
===
undefined
))
{
...
...
@@ -126,14 +116,11 @@ export const updateMainimg = asyncWrap(async (reqExp, res) => {
newfilename
);
}
}
else
{
mainimgDb
.
updateOneMainimg
(
id
,
theme
,
city
,
title
);
}
else
{
mainimgDb
.
updateOneMainimg
(
id
,
theme
,
city
,
title
)}
}
}
});
res
.
json
();
});
src/controllers/user.controller.ts
View file @
14bcff90
...
...
@@ -4,6 +4,7 @@ import { Request } from "express";
import
formidable
from
"
formidable
"
;
import
{
ObjectId
}
from
"
mongoose
"
;
import
fs
from
"
fs
"
;
import
{
TypedRequest
}
from
"
../types
"
;
export
interface
TypedRequestAuth
<
T
>
extends
Request
{
auth
:
T
;
...
...
@@ -30,24 +31,19 @@ export const getProfile = asyncWrap(async (reqExp, res) => {
});
export
const
postPicture
=
asyncWrap
(
async
(
reqExp
,
res
)
=>
{
const
req
=
reqExp
as
TypedRequest
Auth
<
{
userId
:
ObjectId
}
>
;
const
req
=
reqExp
as
TypedRequest
;
const
{
userId
}
=
req
.
auth
;
const
field
=
req
.
body
;
const
file
=
req
.
files
;
const
form
=
formidable
({
uploadDir
:
"
uploads
"
,
keepExtensions
:
true
,
multiples
:
false
,
});
form
.
parse
(
req
,
(
err
,
fields
,
files
)
=>
{
if
(
!
Array
.
isArray
(
files
.
picture
))
{
if
(
!
Array
.
isArray
(
file
.
picture
))
{
//파일 좁히기 중
if
(
!
Array
.
isArray
(
field
s
.
nickname
))
{
const
nickname
=
field
s
.
nickname
;
if
(
!
(
file
s
.
picture
===
undefined
))
{
const
originalfilename
=
file
s
.
picture
.
originalFilename
;
const
newfilename
=
file
s
.
picture
.
newFilename
;
const
picturepath
=
file
s
.
picture
.
filepath
;
if
(
!
Array
.
isArray
(
field
.
nickname
))
{
const
nickname
=
field
.
nickname
;
if
(
!
(
file
.
picture
===
undefined
))
{
const
originalfilename
=
file
.
picture
.
originalFilename
;
const
newfilename
=
file
.
picture
.
newFilename
;
const
picturepath
=
file
.
picture
.
filepath
;
userDb
.
postPicture
(
userId
,
nickname
,
...
...
@@ -60,15 +56,18 @@ export const postPicture = asyncWrap(async (reqExp, res) => {
}
}
}
});
res
.
json
();
});
export
const
deleteUser
=
asyncWrap
(
async
(
reqExp
,
res
)
=>
{
const
req
=
reqExp
as
TypedRequestAuth
<
{
userId
:
ObjectId
}
>
;
// 앞에서는 토큰으로써 사용하기 때문에 JwtPayload 를 사용하고 여기서는 verify 에서 토큰을 디코딩했기에 ObjectId 타입의 string으로 바뀌게 된다.
const
req
=
reqExp
as
TypedRequestAuth
<
{
userId
:
string
}
>
;
// 앞에서는 토큰으로써 사용하기 때문에 JwtPayload 를 사용하고 여기서는 verify 에서 토큰을 디코딩했기에 ObjectId 타입의 string으로 바뀌게 된다.
const
{
userId
}
=
req
.
auth
;
const
profile
=
await
userDb
.
deleteUser
(
userId
);
res
.
json
(
profile
);
const
finish
=
await
userDb
.
deleteUser
(
userId
);
if
(
finish
?.
deletedCount
===
1
)
{
res
.
json
(
true
);
}
else
{
res
.
status
(
422
).
send
(
"
삭제에 실패하였습니다.
"
);
}
});
src/db/mainimg.db.ts
View file @
14bcff90
import
{
Avatar
,
IAvatar
,
Mainimg
,
MainimgType
}
from
"
../models
"
;
import
{
ObjectId
}
from
"
mongoose
"
;
import
{
FileInfo
,
IFileInfo
,
Mainimg
,
MainimgType
}
from
"
../models
"
;
export
const
createMainimg
=
async
(
mainimg
:
MainimgType
,
pic
:
I
Avatar
)
=>
{
const
newPic
=
await
Avatar
.
create
({
export
const
createMainimg
=
async
(
mainimg
:
MainimgType
,
pic
:
I
FileInfo
)
=>
{
const
newPic
=
await
FileInfo
.
create
({
originalfilename
:
pic
.
originalfilename
,
newfilename
:
pic
.
newfilename
,
pictureauth
:
pic
.
picturepath
,
...
...
@@ -34,36 +34,40 @@ export const updateOneMainimg = async (
city
:
string
,
title
:
string
,
originalfilename
?:
string
|
null
,
newfilename
?:
string
,
newfilename
?:
string
)
=>
{
const
newMainimg
=
await
Mainimg
.
findById
(
_Id
);
console
.
log
(
"
error2
"
,
_Id
)
console
.
log
(
"
error2
"
,
_Id
)
;
if
(
!
(
newMainimg
?.
pic
===
undefined
))
{
if
(
originalfilename
===
undefined
)
{
await
Mainimg
.
findByIdAndUpdate
(
newMainimg
.
_id
,
{
theme
:
theme
,
city
:
city
,
title
:
title
,
})
console
.
log
(
"
errrror4
"
)
}
else
if
(
!
(
originalfilename
===
undefined
)
&&
(
!
(
theme
===
undefined
)
||!
(
city
===
undefined
)
||!
(
title
===
undefined
))){
});
console
.
log
(
"
errrror4
"
);
}
else
if
(
!
(
originalfilename
===
undefined
)
&&
(
!
(
theme
===
undefined
)
||
!
(
city
===
undefined
)
||
!
(
title
===
undefined
))
)
{
await
Mainimg
.
findByIdAndUpdate
(
newMainimg
.
_id
,
{
theme
:
theme
,
city
:
city
,
title
:
title
,
})
await
Avatar
.
findByIdAndUpdate
(
newMainimg
.
pic
.
_id
,
{
})
;
await
FileInfo
.
findByIdAndUpdate
(
newMainimg
.
pic
.
_id
,
{
originalfilename
:
originalfilename
,
newfilename
:
newfilename
,
})
console
.
log
(
"
error6
"
)
}
else
{
await
Avatar
.
findByIdAndUpdate
(
newMainimg
.
pic
.
_id
,
{
});
console
.
log
(
"
error6
"
);
}
else
{
await
FileInfo
.
findByIdAndUpdate
(
newMainimg
.
pic
.
_id
,
{
originalfilename
:
originalfilename
,
newfilename
:
newfilename
,
})
console
.
log
(
"
error5
"
,
newfilename
,
originalfilename
,
theme
,
city
,
title
)}
}
else
(
console
.
log
(
"
error3
"
,
newMainimg
))
}
\ No newline at end of file
});
console
.
log
(
"
error5
"
,
newfilename
,
originalfilename
,
theme
,
city
,
title
);
}
}
else
console
.
log
(
"
error3
"
,
newMainimg
);
};
src/db/user.db.ts
View file @
14bcff90
...
...
@@ -6,7 +6,7 @@ import fs from "fs/promises";
export
const
createUser
=
async
(
user
:
IUser
)
=>
{
// 비밀번호 암호화
const
hash
=
await
bcrypt
.
hash
(
user
.
password
,
10
);
const
new
Avatar
=
await
FileInfo
.
create
({});
const
new
FileInfo
=
await
FileInfo
.
create
({});
// 사용자 역할 추가: 기본값은 "user"
let
userRole
=
null
;
if
(
user
.
role
)
{
...
...
@@ -19,7 +19,7 @@ export const createUser = async (user: IUser) => {
password
:
hash
,
role
:
userRole
,
isNew
:
true
,
avatar
:
newAvatar
,
fileInfo
:
newFileInfo
.
_id
,
});
const
retUser
=
await
newUser
.
save
();
return
retUser
;
...
...
@@ -44,7 +44,7 @@ export const findUserByPostId = async (postId: string) => {
};
export
const
getProfile
=
async
(
userId
:
string
)
=>
{
const
profile
=
await
User
.
findById
(
userId
).
populate
(
"
avatar
"
);
const
profile
=
await
User
.
findById
(
userId
).
populate
(
"
fileInfo
"
);
return
profile
;
//이름 수정
};
...
...
@@ -80,19 +80,22 @@ export const postPicture = async (
)
=>
{
const
profile
=
await
User
.
findById
(
userId
);
if
(
!
(
profile
?.
avatar
===
undefined
))
{
if
(
!
(
profile
?.
fileInfo
===
undefined
))
{
if
(
originalfilename
===
null
)
{
await
FileInfo
.
findByIdAndUpdate
(
profile
.
avatar
.
_id
,
{
await
FileInfo
.
findByIdAndUpdate
(
profile
.
fileInfo
.
_id
,
{
nickname
:
nickname
,
});
}
else
if
(
nickname
===
""
)
{
await
FileInfo
.
findByIdAndUpdate
(
profile
.
avatar
.
_id
,
{
const
ref
=
FileInfo
.
findById
(
profile
.
fileInfo
.
_id
);
console
.
log
(
ref
);
await
FileInfo
.
findByIdAndUpdate
(
profile
.
fileInfo
.
_id
,
{
originalfilename
:
originalfilename
,
newfilename
:
newfilename
,
picturepath
:
picturepath
,
});
}
else
{
await
FileInfo
.
findByIdAndUpdate
(
profile
.
avatar
.
_id
,
{
const
ref
=
await
FileInfo
.
findByIdAndUpdate
(
profile
.
fileInfo
.
_id
,
{
originalfilename
:
originalfilename
,
newfilename
:
newfilename
,
picturepath
:
picturepath
,
...
...
@@ -102,12 +105,15 @@ export const postPicture = async (
}
};
export
const
deleteUser
=
async
(
userId
:
ObjectId
)
=>
{
export
const
deleteUser
=
async
(
userId
:
string
)
=>
{
const
user
=
await
User
.
findById
(
userId
);
if
(
user
&&
user
.
avatar
)
{
const
file
=
await
FileInfo
.
findById
(
user
.
avatar
.
_id
);
await
fs
.
unlink
(
"
../travel/uploads/
"
+
file
?.
newfilename
);
await
FileInfo
.
deleteOne
({
_id
:
user
.
avatar
.
_id
});
return
await
user
.
deleteOne
();
if
(
!
(
user
?.
fileInfo
===
undefined
))
{
const
ref
=
await
FileInfo
.
findById
(
user
.
fileInfo
.
_id
);
if
(
!
(
ref
?.
newfilename
===
undefined
))
{
await
fs
.
unlink
(
"
../travel/uploads/
"
+
ref
?.
newfilename
);
}
await
FileInfo
.
deleteOne
({
_id
:
user
.
fileInfo
.
_id
});
const
finish
=
await
User
.
deleteOne
({
_id
:
userId
});
return
finish
;
}
};
src/models/fileinfo.model.ts
View file @
14bcff90
...
...
@@ -8,7 +8,7 @@ export interface IFileInfo {
}
const
schema
=
new
Schema
<
IFileInfo
>
({
originalfilename
:
{
type
:
String
},
originalfilename
:
{
type
:
String
,
unique
:
true
},
newfilename
:
{
type
:
String
},
nickname
:
{
type
:
String
},
picturepath
:
{
type
:
String
},
...
...
src/models/mainimg.model.ts
View file @
14bcff90
import
{
model
,
Schema
,
Types
}
from
"
mongoose
"
;
import
{
model
,
Schema
,
Types
}
from
"
mongoose
"
;
export
interface
MainimgType
{
theme
:
string
;
city
:
string
;
title
:
string
;
pic
?:
Types
.
ObjectId
;
fileInfo
?:
Types
.
ObjectId
;
}
const
MainimgSchema
=
new
Schema
<
MainimgType
>
({
...
...
@@ -19,11 +18,7 @@ const MainimgSchema = new Schema<MainimgType>({
type
:
String
,
required
:
true
,
},
pic
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Avatar
"
}
fileInfo
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Fileinfo
"
},
});
export
default
model
<
MainimgType
>
(
"
Mainimg
"
,
MainimgSchema
);
src/models/user.model.ts
View file @
14bcff90
...
...
@@ -5,7 +5,7 @@ export interface IUser {
name
?:
string
;
password
:
string
;
role
?:
Types
.
ObjectId
;
avatar
?:
Types
.
ObjectId
;
fileInfo
?:
Types
.
ObjectId
;
}
const
validateEmail
=
(
email
:
string
)
=>
{
...
...
@@ -22,7 +22,7 @@ const schema = new Schema<IUser>(
validate
:
[
validateEmail
,
"
이메일을 입력해주세요
"
],
},
name
:
{
type
:
String
},
avatar
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Avatar
"
},
fileInfo
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
FileInfo
"
},
password
:
{
type
:
String
,
required
:
true
,
select
:
false
},
role
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Role
"
},
},
...
...
Prev
1
2
Next
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