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
reservation-service
Commits
61a30671
Commit
61a30671
authored
Nov 06, 2020
by
Yoon, Daeki
😅
Browse files
final error
parent
45c8051b
Changes
26
Hide whitespace changes
Inline
Side-by-side
client/package.json
View file @
61a30671
...
...
@@ -8,8 +8,20 @@
"@testing-library/user-event"
:
"^12.1.10"
,
"react"
:
"^17.0.1"
,
"react-dom"
:
"^17.0.1"
,
"react-router-dom"
:
"^5.2.0"
,
"react-scripts"
:
"4.0.0"
,
"web-vitals"
:
"^0.2.4"
"web-vitals"
:
"^0.2.4"
,
"@toast-ui/react-calendar"
:
"^1.0.5"
,
"axios"
:
"^0.20.0"
,
"bcrypt"
:
"^5.0.0"
,
"bootstrap"
:
"^4.5.3"
,
"formik"
:
"^2.1.5"
,
"jquery"
:
"^3.5.1"
,
"moment"
:
"^2.29.0"
,
"popper.js"
:
"^1.16.1"
,
"react-bootstrap"
:
"^1.4.0"
,
"styled-components"
:
"^5.2.0"
,
"yup"
:
"^0.29.3"
},
"scripts"
:
{
"start"
:
"react-scripts start"
,
...
...
@@ -34,5 +46,6 @@
"last 1 firefox version"
,
"last 1 safari version"
]
}
},
"proxy"
:
"http://localhost:3030"
}
client/src/Components/AdminPrivateRoute.js
0 → 100644
View file @
61a30671
// import React from 'react';
// import { Redirect, Route } from "react-router-dom";
// export const AdminPrivateRoute = ({ component: Component, ...rest }) => (
// <Route
// {...rest}
// render={props =>
// (localStorage.getItem("token") !==null) ? (
// <Component {...props} />
// ) : (
// <Redirect to={{
// pathname: "/login",
// state: {match: props.location}
// }} />
// )
// }
// />
// )
\ No newline at end of file
client/src/Components/Card.js
0 → 100644
View file @
61a30671
import
React
,
{
useContext
}
from
'
react
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
axios
from
'
axios
'
;
import
{
Card
,
Accordion
,
Col
,
AccordionContext
,
useAccordionToggle
,
Button
}
from
'
react-bootstrap
'
;
import
styled
from
'
styled-components
'
;
const
Text
=
styled
(
Card
.
Body
)
`
& .WRAP {
display: inline-block;
text-overflow: ellipsis;
width: 100%;
white-space: initial;
}
`
function
Notice
({
card_id
,
card_index
,
title
,
date
,
content
,
admin
})
{
function
ContextAwareToggle
({
children
,
eventKey
,
callback
})
{
const
currentEventKey
=
useContext
(
AccordionContext
);
const
decoratedOnClick
=
useAccordionToggle
(
eventKey
,
()
=>
callback
&&
callback
(
eventKey
),
);
const
isCurrentEventKey
=
currentEventKey
===
eventKey
;
return
(
<
div
className
=
{
isCurrentEventKey
?
"
text-wrap whiteSpace-initial
"
:
"
text-truncate
"
}
onClick
=
{
decoratedOnClick
}
>
{
children
}
<
/div
>
);
}
function
dateForm
(
day
)
{
const
post_day
=
new
Date
(
day
);
let
year
=
post_day
.
getFullYear
();
let
month
=
post_day
.
getMonth
()
+
1
;
let
date
=
post_day
.
getDate
();
month
=
month
<
10
?
'
0
'
+
month
:
month
;
date
=
date
<
10
?
'
0
'
+
date
:
date
;
const
new_date
=
year
+
"
-
"
+
month
+
"
-
"
+
date
;
return
new_date
}
function
remove
(
card_id
)
{
axios
.
delete
(
`/notices/
${
card_id
}
`
)
.
then
(
res
=>
{
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
alert
(
"
삭제되었습니다!
"
);
window
.
location
.
reload
();
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
return
(
<
Card
className
=
"
w-100
"
>
<
Card
.
Header
className
=
"
row flex-row py-3
"
>
<
Col
md
=
{
10
}
xs
=
{
8
}
>
<
ContextAwareToggle
variant
=
"
link
"
eventKey
=
{
card_index
+
1
}
>
{
title
}
<
/ContextAwareToggle
>
<
/Col
>
<
Col
md
=
{
2
}
xs
=
{
4
}
className
=
"
p-0
"
>
{
dateForm
(
date
)}
<
/Col
>
<
/Card.Header
>
<
Accordion
.
Collapse
eventKey
=
{
card_index
+
1
}
>
<
Text
>
{
content
.
split
(
"
\n
"
).
map
((
i
,
key
)
=>
{
return
<
div
key
=
{
key
}
>
{
i
}
<
/div>
;
})}
{
admin
===
"
admin
"
?
(
<
div
className
=
"
d-flex justify-content-end
"
>
<
Button
variant
=
"
primary
"
size
=
"
sm
"
as
=
{
Link
}
to
=
{
`/modify/
${
card_id
}
`
}
>
수정
<
/Button
>
<
Button
variant
=
"
danger
"
size
=
"
sm
"
onClick
=
{()
=>
remove
(
card_id
)}
>
삭제
<
/Button
>
<
/div>
)
: null
}
<
/Text
>
<
/Accordion.Collapse
>
<
/Card
>
)
}
export
default
Notice
;
\ No newline at end of file
client/src/Components/Menu.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Link
,
Redirect
}
from
'
react-router-dom
'
;
import
styled
from
'
styled-components
'
;
import
axios
from
'
axios
'
;
import
{
Navbar
,
Nav
,
NavLink
}
from
'
react-bootstrap
'
;
const
MENU
=
styled
(
Navbar
)
`
background-color: #7B031D;
a {
color : white;
}
`
function
Menu
()
{
const
[
state
,
setState
]
=
useState
()
const
[
user
,
setUser
]
=
useState
({
role
:
""
})
const
name
=
localStorage
.
getItem
(
'
name
'
);
function
logout
()
{
localStorage
.
clear
();
alert
(
"
로그아웃 되었습니다.
"
);
setState
(
true
);
}
useEffect
(()
=>
{
acheck
();
},
[])
function
acheck
()
{
axios
.
get
(
`/users/
${
localStorage
.
getItem
(
'
_id
'
)}
`
,
{
headers
:
{
authorization
:
localStorage
.
getItem
(
'
token
'
)
},
}).
then
(
res
=>
{
if
(
res
.
data
.
role
==
"
admin
"
)
{
setUser
(
res
.
data
)
}
}).
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
if
(
state
)
return
<
Redirect
to
=
"
/
"
/>
return
(
<
MENU
expand
=
"
md
"
variant
=
"
dark
"
>
<
Navbar
.
Brand
as
=
{
Link
}
to
=
"
/home
"
>
대관
서비스
<
/Navbar.Brand
>
<
Navbar
.
Toggle
aria
-
controls
=
"
basic-navbar-nav
"
/>
<
Navbar
.
Collapse
id
=
"
basic-navbar-nav
"
>
<
Nav
className
=
"
mr-auto
"
>
<
NavLink
as
=
{
Link
}
to
=
"
/notice
"
>
공지사항
<
/NavLink
>
<
NavLink
as
=
{
Link
}
to
=
"
/home
"
>
대관
현황
<
/NavLink
>
<
NavLink
as
=
{
Link
}
to
=
{{
pathname
:
`/apply/
${
localStorage
.
getItem
(
'
_id
'
)}
`
,
state
:
{
id
:
localStorage
.
getItem
(
'
_id
'
)
},
}}
className
=
"
nav-link
"
>
대관
신청
<
/NavLink
>
<
NavLink
as
=
{
Link
}
to
=
{{
pathname
:
`/check/
${
localStorage
.
getItem
(
'
_id
'
)}
`
,
state
:
{
id
:
localStorage
.
getItem
(
'
_id
'
)
},
}}
className
=
"
nav-link
"
>
대관
확인
/
취소
<
/NavLink
>
{
/* {user.role === "admin" ? (
<NavLink as={Link} to={{
pathname: `/acheck/${localStorage.getItem('_id')}`,
state: { id: localStorage.getItem('_id') },
}} className="nav-link">
대관 확인/취소(관리자)</NavLink>) : null} */
}
<
/Nav
>
<
Nav
>
<
NavLink
>
<
small
className
=
"
d-flex flex-row justify-content-end
"
>
<
div
className
=
"
text-white text-right font-weight-light pr-2
"
>
{
name
}
님
<
/div
>
<
NavLink
className
=
"
p-0
"
as
=
{
Link
}
to
=
{{
pathname
:
`/change/
${
localStorage
.
getItem
(
'
_id
'
)}
`
,
state
:
{
id
:
localStorage
.
getItem
(
'
_id
'
)
},
}}
>
비밀번호
변경
<
/NavLink> /
<
NavLink
className
=
"
p-0
"
onClick
=
{
logout
}
>
로그아웃
<
/NavLink></
small
>
<
/NavLink
>
<
/Nav
>
<
/Navbar.Collapse
>
<
/MENU
>
)
}
export
default
Menu
\ No newline at end of file
client/src/Components/PrivateRoute.js
0 → 100644
View file @
61a30671
import
React
from
'
react
'
;
import
{
Redirect
,
Route
}
from
"
react-router-dom
"
;
export
const
PrivateRoute
=
({
component
:
Component
,
...
rest
})
=>
(
<
Route
{...
rest
}
render
=
{
props
=>
(
localStorage
.
getItem
(
"
token
"
)
!==
null
)
?
(
<
Component
{...
props
}
/
>
)
:
(
<
Redirect
to
=
{{
pathname
:
"
/login
"
,
state
:
{
match
:
props
.
location
}
}}
/
>
)
}
/
>
)
\ No newline at end of file
client/src/Components/Schedule.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
,
useRef
}
from
'
react
'
;
import
Calendar
from
'
@toast-ui/react-calendar
'
;
import
"
tui-calendar/dist/tui-calendar.css
"
;
import
"
tui-date-picker/dist/tui-date-picker.css
"
;
import
"
tui-time-picker/dist/tui-time-picker.css
"
;
import
moment
from
'
moment
'
;
import
axios
from
'
axios
'
;
import
{
Image
,
Button
}
from
'
react-bootstrap
'
;
import
leftArrow
from
'
../caret-left-fill.svg
'
;
import
rightArrow
from
'
../caret-right-fill.svg
'
;
function
Cal
(
props
)
{
const
calendarRef
=
useRef
(
null
);
const
[
reserve
,
setReserve
]
=
useState
([]);
const
[
period
,
setPeriod
]
=
useState
();
const
[
myTheme
,
setMyTheme
]
=
useState
({
'
common.dayname.color
'
:
'
#333
'
,
'
common.today.color
'
:
'
#333
'
,
'
common.creationGuide.backgroundColor
'
:
'
gray
'
,
});
function
getReserve
(
room
)
{
axios
.
get
(
`/reserves/room/
${
room
}
`
,
{
headers
:
{
authorization
:
localStorage
.
getItem
(
'
token
'
)
},
})
.
then
(
res
=>
{
const
reserves
=
res
.
data
.
map
(
item
=>
({
id
:
item
.
_id
,
start
:
item
.
start
,
end
:
item
.
end
,
calendarId
:
'
Subject
'
,
category
:
'
time
'
,
}))
setReserve
(
reserves
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
function
getDataAction
(
target
)
{
return
target
.
dataset
?
target
.
dataset
.
action
:
target
.
getAttribute
(
'
data-action
'
);
}
function
onClickNavi
(
e
)
{
const
cal
=
calendarRef
.
current
.
getInstance
();
const
action
=
getDataAction
(
e
.
target
);
switch
(
action
)
{
case
'
move-prev
'
:
cal
.
prev
();
break
;
case
'
move-next
'
:
cal
.
next
();
break
;
case
'
move-today
'
:
cal
.
today
();
break
;
default
:
return
;
}
setRenderRangeText
();
}
function
setRenderRangeText
()
{
const
cal
=
calendarRef
.
current
.
getInstance
();
let
html
=
[];
html
.
push
(
moment
(
cal
.
getDateRangeStart
().
getTime
()).
format
(
'
YYYY.MM.DD
'
));
html
.
push
(
'
~
'
);
html
.
push
(
moment
(
cal
.
getDateRangeEnd
().
getTime
()).
format
(
'
MM.DD
'
));
setPeriod
(
html
.
join
(
''
))
}
useEffect
(()
=>
{
setRenderRangeText
();
getReserve
(
props
.
room
);
},
[
props
.
room
])
return
(
<
div
>
<
div
id
=
"
menu
"
className
=
"
p-2
"
>
<
span
id
=
"
menu-navi
"
onClick
=
{(
e
)
=>
onClickNavi
(
e
)}
>
<
Button
variant
=
"
default
"
size
=
"
sm
"
className
=
"
move-today
"
data
-
action
=
"
move-today
"
>
Today
<
/Button
>
<
Button
variant
=
"
default
"
size
=
"
sm
"
className
=
"
move-day
"
data
-
action
=
"
move-prev
"
>
<
Image
class
=
"
calendar-icon
"
src
=
{
leftArrow
}
data
-
action
=
"
move-prev
"
><
/Image
>
<
/Button
>
<
Button
variant
=
"
default
"
size
=
"
sm
"
className
=
"
move-day
"
data
-
action
=
"
move-next
"
>
<
Image
className
=
"
calendar-icon
"
src
=
{
rightArrow
}
data
-
action
=
"
move-next
"
><
/Image
>
<
/Button
>
<
/span
>
<
span
id
=
"
renderRange
"
className
=
"
render-range ml-2
"
style
=
{{
height
:
"
5em
"
}}
>
{
period
}
<
/span
>
<
/div
>
<
Calendar
ref
=
{
calendarRef
}
height
=
"
100%
"
calendars
=
{[
{
id
:
'
Subject
'
,
bgColor
:
'
#a9a9a9
'
,
borderColor
:
'
#a9a9a9
'
,
isReadOnly
:
'
true
'
}
]}
view
=
"
week
"
disableDblClick
=
{
false
}
disableClick
=
{
true
}
isReadOnly
=
{
true
}
schedules
=
{
reserve
}
scheduleView
=
{[
'
time
'
]}
taskView
=
{
false
}
theme
=
{
myTheme
}
timezones
=
{[
{
timezoneOffset
:
540
,
displayLabel
:
'
GMT+09:00
'
,
tooltip
:
'
Seoul
'
},
]}
useDetailPopup
useCreationPopup
view
=
{
"
week
"
}
week
=
{{
workweek
:
true
,
hourStart
:
8
,
hourEnd
:
23
}}
/
>
<
/div
>
)
}
export
default
Cal
\ No newline at end of file
client/src/Pages/ACheckPage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
Menu
from
'
../Components/Menu
'
;
import
axios
from
'
axios
'
;
import
{
Redirect
}
from
'
react-router-dom
'
;
import
{
Container
,
Table
}
from
'
react-bootstrap
'
;
import
styled
from
'
styled-components
'
;
const
Ta
=
styled
(
Table
)
`
& th, & td {
padding: 0;
vertical-align: middle;
};
& tr {
display: d-flex;
width: 50px;
};
& td {
align-items: center;
width: 70px;
};
`
function
ACheck
(
props
)
{
const
[
state
,
setState
]
=
useState
()
const
[
reserve
,
setReserve
]
=
useState
([]);
useEffect
(()
=>
{
getReserve
();
},
[])
function
getReserve
()
{
axios
.
get
(
`/users/admin/
${
props
.
match
.
params
.
id
}
`
,
{
headers
:
{
authorization
:
localStorage
.
getItem
(
'
token
'
)
},
})
.
then
(
res
=>
{
if
(
res
.
status
===
404
)
{
alert
(
res
.
data
.
error
)
setState
(
true
);
}
setReserve
(
res
.
data
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
if
(
state
)
return
<
Redirect
to
=
"
/
"
/>
;
function
remove
(
index
)
{
axios
.
put
(
`/reserves/
${
reserve
[
index
].
_id
}
`
)
.
then
(
res
=>
{
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
alert
(
"
승인을 거절했습니다!
"
);
getReserve
();
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
};
function
admit
(
index
)
{
axios
.
put
(
`/reserves/
${
reserve
[
index
].
_id
}
`
,
{
approve
:
true
,
})
.
then
(
res
=>
{
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
alert
(
"
승인되었습니다!
"
);
getReserve
();
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
};
return
(
<
div
>
<
Menu
/>
<
Container
fluid
>
<
Ta
responsive
=
"
lg
"
>
<
thead
className
=
"
thead-light
"
>
<
tr
>
<
th
>
대표자
<
/th
>
<
th
>
날짜
<
/th
>
<
th
>
시간
<
/th
>
<
th
>
강의실
<
/th
>
<
th
>
사용
인원
<
/th
>
<
th
>
승인
여부
<
/th
>
<
/tr
>
<
/thead
>
<
tbody
>
{
reserve
!=
""
?
(
reserve
.
map
((
reserve
,
index
)
=>
{
return
(
<
tr
key
=
{
index
}
>
<
td
>
{
reserve
.
user
.
name
}
<
/td
>
<
td
>
{
reserve
.
date
}
<
/td
>
<
td
>
{
reserve
.
starttime
}
시
~
{(
Number
(
reserve
.
starttime
)
+
reserve
.
usetime
)}
시
<
/td
>
<
td
>
{
reserve
.
room
}
<
/td
>
<
td
>
{
reserve
.
num
}
<
/td
>
<
td
>
<
button
onClick
=
{()
=>
admit
(
index
)}
className
=
"
btn btn-primary btn-sm
"
>
승인
<
/button
>
<
button
onClick
=
{()
=>
remove
(
index
)}
className
=
"
btn btn-danger btn-sm
"
>
거절
<
/button
>
<
/td
>
<
/tr
>
)
}))
:
<
div
>
최근
대관
신청
내역이
없습니다
.
<
/div>
}
<
/tbody
>
<
/Ta
>
<
/Container
>
<
/div
>
)
}
export
default
ACheck
client/src/Pages/ApplyPage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Formik
,
Field
,
ErrorMessage
,
FieldArray
}
from
'
formik
'
;
import
Menu
from
'
../Components/Menu
'
;
import
axios
from
'
axios
'
;
import
*
as
Yup
from
'
yup
'
;
import
{
Redirect
}
from
'
react-router-dom
'
;
import
{
Col
,
Container
,
Row
}
from
'
react-bootstrap
'
;
function
Apply
(
props
)
{
const
[
state
,
setState
]
=
useState
({
ok
:
""
});
const
[
user
,
setUser
]
=
useState
({
name
:
""
});
const
[
room_Num
,
setRoom_Num
]
=
useState
({
"
9-116
"
:
5
,
"
7-234
"
:
7
,
"
25-101
"
:
10
});
useEffect
(()
=>
{
getUser
();
},
[])
if
(
state
.
ok
===
"
no
"
)
return
<
Redirect
to
=
"
/
"
/>
;
if
(
state
.
ok
===
"
ok
"
)
{
return
<
Redirect
to
=
{{
pathname
:
`/check/
${
props
.
match
.
params
.
id
}
`
,
state
:
{
id
:
props
.
match
.
params
.
id
},
}}
/>
;
}
function
time
(
starttime
)
{
if
(
starttime
==
21
)
{
return
(
<
Field
as
=
"
select
"
name
=
"
usetime
"
className
=
"
col-12
"
>
<
option
value
=
""
>
이용시간선택
<
/option
>
<
option
value
=
"
1
"
>
1
시간
<
/option
>
<
/Field>
)
}
if
(
starttime
==
20
)
{
return
(
<
Field
as
=
"
select
"
name
=
"
usetime
"
className
=
"
col-12
"
>
<
option
value
=
""
>
이용시간선택
<
/option
>
<
option
value
=
"
1
"
>
1
시간
<
/option
>
<
option
value
=
"
2
"
>
2
시간
<
/option
>
<
/Field>
)
}
return
(
<
Field
as
=
"
select
"
name
=
"
usetime
"
className
=
"
col-12
"
>
<
option
value
=
""
>
이용시간선택
<
/option
>
<
option
value
=
"
1
"
>
1
시간
<
/option
>
<
option
value
=
"
2
"
>
2
시간
<
/option
>
<
option
value
=
"
3
"
>
3
시간
<
/option
>
<
/Field>
)
}
function
getUser
()
{
axios
.
get
(
`/users/
${
props
.
match
.
params
.
id
}
`
,
{
headers
:
{
authorization
:
localStorage
.
getItem
(
'
token
'
)
},
})
.
then
(
res
=>
{
if
(
res
.
status
!==
201
)
{
alert
(
res
.
data
.
error
);
localStorage
.
clear
();
setState
({
ok
:
"
no
"
});
}
setUser
(
res
.
data
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
function
addRoomInfo
(
values
)
{
for
(
let
room
in
room_Num
)
{
if
(
room
===
values
.
room
)
{
values
.
roomInfo
=
room_Num
[
room
]
}
};
}
return
(
<
div
>
<
Menu
/>
<
Container
fluid
className
=
"
mt-3
"
>
<
Row
className
=
"
justify-content-center
"
>
<
Col
md
=
{
5
}
>
<
Formik
initialValues
=
{{
_id
:
`
${
props
.
match
.
params
.
id
}
`
,
date
:
''
,
starttime
:
''
,
usetime
:
''
,
room
:
''
,
reason
:
''
,
students
:
[
{
member
:
''
,
},
],
}}
validationSchema
=
{
Yup
.
object
({
date
:
Yup
.
string
()
.
required
(
'
날짜를 입력해주세요.
'
),
reason
:
Yup
.
string
()
.
required
(
'
대관목적을 입력해주세요.
'
),
})}
onSubmit
=
{(
values
,
{
setSubmitting
})
=>
{
addRoomInfo
(
values
);
axios
({
method
:
'
post
'
,
url
:
'
/reserves
'
,
data
:
values
}).
then
(
res
=>
{
if
(
res
.
status
===
404
)
{
alert
(
res
.
data
.
error
)
return
window
.
location
.
reload
();
}
alert
(
"
신청이 완료되었습니다!
"
);
setState
({
ok
:
"
ok
"
});
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
setTimeout
(()
=>
{
setSubmitting
(
false
);
},
400
);
// finish the cycle in handler
}}
>
{({
errors
,
touched
,
values
,
handleSubmit
,
getFieldProps
,
isSubmitting
,
})
=>
(
<
form
onSubmit
=
{
handleSubmit
}
className
=
"
d-flex flex-column
"
>
<
h3
className
=
"
form-group font-weight-bold
"
>
<
label
className
=
"
pr-2
"
>
대표자
:
<
/label>{user.name
}
<
/h3
>
<
div
className
=
"
form-group mb-4
"
>
<
div
className
=
{
touched
.
date
&&
errors
.
date
?
"
text-danger
"
:
""
}
>
신청날짜
<
/div
>
<
input
className
=
{(
touched
.
date
&&
errors
.
date
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
text
"
name
=
"
date
"
{...
getFieldProps
(
'
date
'
)}
placeholder
=
"
yyyy-mm-dd
"
/>
<
/div
>
<
Row
className
=
"
form-group mb-4
"
>
<
div
className
=
"
col-6 pr-0
"
>
<
label
>
이용시작시간
<
/label
>
<
div
>
<
Field
as
=
"
select
"
name
=
"
starttime
"
className
=
"
col-12
"
>
<
option
value
=
""
>
이용시작시간
<
/option
>
<
option
value
=
"
09
"
>
9
시
<
/option
>
<
option
value
=
"
10
"
>
10
시
<
/option
>
<
option
value
=
"
11
"
>
11
시
<
/option
>
<
option
value
=
"
12
"
>
12
시
<
/option
>
<
option
value
=
"
13
"
>
13
시
<
/option
>
<
option
value
=
"
14
"
>
14
시
<
/option
>
<
option
value
=
"
15
"
>
15
시
<
/option
>
<
option
value
=
"
16
"
>
16
시
<
/option
>
<
option
value
=
"
17
"
>
17
시
<
/option
>
<
option
value
=
"
18
"
>
18
시
<
/option
>
<
option
value
=
"
19
"
>
19
시
<
/option
>
<
option
value
=
"
20
"
>
20
시
<
/option
>
<
option
value
=
"
21
"
>
21
시
<
/option
>
<
/Field
>
<
/div
>
<
/div
>
<
div
className
=
"
col-6 pl-0
"
>
<
label
>
이용시간
<
/label
>
<
div
>
{
time
(
values
.
starttime
)}
<
/div
>
<
/div
>
<
/Row
>
<
div
className
=
"
form-group mb-4
"
>
<
div
className
=
{
touched
.
room
&&
errors
.
room
?
"
text-danger
"
:
""
}
>
강의실
<
/div
>
<
Field
as
=
"
select
"
name
=
"
room
"
className
=
"
col-6
"
>
<
option
value
=
""
>
강의실
선택
<
/option
>
<
option
value
=
"
9-116
"
>
9
-
116
(
5
명
)
<
/option
>
<
option
value
=
"
7-234
"
>
7
-
234
(
7
명
)
<
/option
>
<
option
value
=
"
25-101
"
>
25
-
101
(
10
명
)
<
/option
>
<
/Field
>
<
/div
>
<
div
className
=
"
form-group mb-4
"
>
<
div
className
=
{
touched
.
reason
&&
errors
.
reason
?
"
text-danger
"
:
""
}
>
대관
목적
<
/div
>
<
input
className
=
{(
touched
.
reason
&&
errors
.
reason
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
text
"
name
=
"
reason
"
{...
getFieldProps
(
'
reason
'
)}
placeholder
=
"
대관목적을 입력해 주세요.
"
/>
<
/div
>
<
div
className
=
"
form-group mb-4
"
>
<
FieldArray
name
=
"
students
"
>
{({
remove
,
push
})
=>
(
<
div
>
<
div
className
=
{
touched
.
date
&&
errors
.
date
?
"
text-danger
"
:
""
}
>
이용자
<
/div
>
{
values
.
students
.
map
((
student
,
index
)
=>
(
<
div
key
=
{
index
}
>
<
Field
name
=
{
`students.
${
index
}
.member`
}
placeholder
=
"
이용자 이름 입력
"
type
=
"
text
"
className
=
"
col-6 mr-1
"
/>
<
ErrorMessage
name
=
{
`friends.
${
index
}
.name`
}
component
=
"
div
"
className
=
"
field-error
"
/>
<
button
type
=
"
button
"
className
=
"
secondary
"
onClick
=
{()
=>
remove
(
index
)}
>
X
<
/button
>
<
/div
>
))}
<
button
type
=
"
button
"
className
=
"
btn btn-primary
"
onClick
=
{()
=>
push
({
member
:
''
})}
>
추가
<
/button
>
<
/div
>
)}
<
/FieldArray
>
<
/div
>
<
button
type
=
"
submit
"
className
=
"
btn btn-dark
"
disabled
=
{
isSubmitting
}
>
신청하기
<
/button
>
<
/form
>
)}
<
/Formik
>
<
/Col
>
<
/Row
>
<
/Container
>
<
/div
>
)
}
export
default
Apply
\ No newline at end of file
client/src/Pages/ChangePage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
}
from
'
react
'
;
import
{
Formik
}
from
'
formik
'
;
import
*
as
Yup
from
'
yup
'
;
import
axios
from
'
axios
'
;
import
Menu
from
'
../Components/Menu
'
;
import
{
Redirect
}
from
'
react-router-dom
'
;
import
{
Container
,
Button
,
Navbar
,
Col
}
from
'
react-bootstrap
'
;
import
styled
from
'
styled-components
'
;
const
Check
=
styled
.
div
`
& #reCheck::after {
content: '새로운 비밀번호를 다시 입력하세요';
}
& #reCheck:not(.right) {
content: '비밀번호가 일치하지 않습니다.';
color: red;
}
`
function
Change
(
props
)
{
const
[
state
,
setState
]
=
useState
();
const
[
checkPw
,
setCheckPw
]
=
useState
(
true
);
if
(
state
)
{
return
<
Redirect
to
=
"
/
"
/>
;
}
return
(
<
div
className
=
""
>
{(
localStorage
.
getItem
(
"
token
"
)
!==
null
)
?
(
<
Menu
/>
)
:
(
<
Menu
expand
=
"
md
"
variant
=
"
dark
"
>
<
Navbar
.
Brand
>
회원가입
<
/Navbar.Brand
>
<
/Menu
>
)}
<
Container
fluid
className
=
"
p-0 vh-90
"
>
<
Check
className
=
"
row justify-content-center m-0
"
>
<
Col
md
=
{
4
}
className
=
"
pt-5
"
>
<
Formik
initialValues
=
{{
password
:
''
}}
validationSchema
=
{
Yup
.
object
({
password
:
Yup
.
string
()
.
required
(
'
비밀번호를 입력해주세요.
'
)
.
min
(
8
,
'
8자 이상 입력해주세요.
'
),
password2
:
Yup
.
string
()
.
required
(
'
비밀번호를 다시 입력해주세요.
'
)
.
min
(
8
,
'
8자 이상 입력해주세요.
'
)
.
oneOf
([
Yup
.
ref
(
"
password
"
),
null
],
'
비밀번호가 일치하지 않습니다.
'
),
})}
onSubmit
=
{(
values
,
{
setSubmitting
})
=>
{
axios
.
put
(
`/users/change/
${
props
.
location
.
state
.
id
}
`
,
{
...
values
},
)
.
then
(
res
=>
{
console
.
log
(
res
.
data
);
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
alert
(
"
회원정보가 수정되었습니다!
"
)
setState
(
true
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
setTimeout
(()
=>
{
setSubmitting
(
false
);
},
400
);
// finish the cycle in handler
}}
>
{({
errors
,
touched
,
handleSubmit
,
getFieldProps
,
// contain values, handleChange, handleBlur
isSubmitting
,
})
=>
(
<
form
onSubmit
=
{
handleSubmit
}
className
=
"
d-flex flex-column
"
>
<
div
className
=
"
form-group
"
>
<
div
className
=
{
touched
.
password
&&
errors
.
password
?
"
text-danger
"
:
""
}
>
새
비밀번호를
입력하세요
(
8
자리
이상
)
<
/div
>
<
input
className
=
{(
touched
.
password
&&
errors
.
password
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
password
"
name
=
"
password
"
{...
getFieldProps
(
'
password
'
)}
placeholder
=
"
새로운 비밀번호
"
/>
<
/div
>
<
div
className
=
"
form-group
"
>
{
touched
.
password2
&&
errors
.
password2
?
setCheckPw
(
false
)
:
null
}
<
div
id
=
"
reCheck
"
className
=
{
checkPw
?
"
right
"
:
"
err
"
}
><
/div
>
<
input
className
=
{(
touched
.
password2
&&
errors
.
password2
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
password
"
name
=
"
password2
"
{...
getFieldProps
(
'
password2
'
)}
placeholder
=
"
새 비밀번호를 다시 입력해주세요.
"
/>
<
/div
>
<
Button
type
=
"
submit
"
variant
=
"
secondary
"
disabled
=
{
isSubmitting
}
>
저장하기
<
/Button
>
<
/form
>
)}
<
/Formik
>
<
/Col
>
<
/Check
>
<
/Container
>
<
/div
>
);
}
export
default
Change
\ No newline at end of file
client/src/Pages/CheckPage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
Menu
from
'
../Components/Menu
'
;
import
{
Redirect
}
from
'
react-router-dom
'
;
import
axios
from
'
axios
'
;
import
{
Container
,
Table
}
from
'
react-bootstrap
'
;
import
styled
from
'
styled-components
'
;
const
Ta
=
styled
(
Table
)
`
margin-top: 0.5em;
& th, & td {
padding: 0;
vertical-align: middle;
font-size: 0.9rem;
margin-left : auto; margin-right : auto;
border-spacing: initial;
};
& tr {
display: d-flex;
width: 150px;
};
& td {
align-items: center;
margin: 10px;
};
`
function
Check
(
props
)
{
const
[
reserve
,
setReserve
]
=
useState
([]);
const
[
state
,
setState
]
=
useState
()
useEffect
(()
=>
{
getReserve
();
},
[])
if
(
state
)
return
<
Redirect
to
=
"
/
"
/>
;
function
getReserve
()
{
axios
.
get
(
`/reserves/
${
props
.
match
.
params
.
id
}
`
,
{
headers
:
{
authorization
:
localStorage
.
getItem
(
'
token
'
)
},
})
.
then
(
res
=>
{
if
(
res
.
status
===
404
)
{
alert
(
res
.
data
.
error
);
}
if
(
res
.
status
===
419
)
{
alert
(
res
.
data
.
error
);
localStorage
.
clear
();
setState
(
true
);
}
const
reserves
=
res
.
data
.
filter
(
function
(
item
)
{
return
item
!==
''
;
});
setReserve
(
reserves
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
function
remove
(
index
)
{
axios
.
delete
(
`/reserves/
${
reserve
[
index
].
_id
}
`
)
.
then
(
res
=>
{
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
alert
(
"
삭제되었습니다!
"
);
getReserve
();
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
};
return
(
<
div
>
<
Menu
/>
<
Container
fluid
>
<
Ta
responsive
=
"
lg ml-2rem
"
>
<
thead
className
=
"
thead-light
"
>
<
tr
>
<
th
className
=
"
text-center
"
>
날짜
<
/th
>
<
th
className
=
"
text-center
"
>
시간
<
/th
>
<
th
className
=
"
text-center
"
>
강의실
<
/th
>
<
th
className
=
"
text-center
"
>
사용인원
<
/th
>
{
/* <th>승인여부</th> */
}
<
th
className
=
"
text-center
"
>
예약취소
<
/th
>
<
/tr
>
<
/thead
>
<
tbody
>
{
reserve
.
map
((
reserve
,
index
)
=>
{
return
(
<
tr
key
=
{
index
}
>
<
td
className
=
"
text-center
"
>
{
reserve
.
date
}
<
/td
>
<
td
className
=
"
text-center
"
>
{
reserve
.
starttime
}
시
~
{(
Number
(
reserve
.
starttime
)
+
reserve
.
usetime
)}
시
<
/td
>
<
td
className
=
"
text-center
"
>
{
reserve
.
room
}
<
/td
>
<
td
className
=
"
text-center
"
>
{
reserve
.
num
}
<
/td
>
{
/* <td>{reserve.check ? (reserve.approve ? "사용가능" : "사용불가") : "승인대기중"}</td> */
}
<
td
className
=
"
text-center
"
>
<
button
onClick
=
{()
=>
remove
(
index
)}
className
=
"
btn btn-danger btn-sm
"
>
취소
<
/button
>
<
/td
>
<
/tr
>
)
})}
<
/tbody
>
<
/Ta
>
<
/Container
>
<
/div
>
)
}
export
default
Check
\ No newline at end of file
client/src/Pages/FindPage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
}
from
'
react
'
;
import
{
Field
,
Formik
}
from
'
formik
'
;
import
*
as
Yup
from
'
yup
'
;
import
axios
from
'
axios
'
;
import
{
Link
,
Redirect
}
from
'
react-router-dom
'
;
import
styled
from
'
styled-components
'
;
import
{
Navbar
,
Container
,
Row
,
Col
,
Button
}
from
'
react-bootstrap
'
;
const
Menu
=
styled
(
Navbar
)
`
background-color: #7B031D;
a {
color : white;
}
`
function
Find
()
{
const
[
state
,
setState
]
=
useState
(
false
);
if
(
state
)
{
return
<
Redirect
to
=
{{
pathname
:
`/change/
${
localStorage
.
getItem
(
'
_id
'
)}
`
,
state
:
{
id
:
localStorage
.
getItem
(
'
_id
'
)
},
}}
/>
;
}
return
(
<
div
className
=
"
vh-100
"
>
<
Menu
expand
=
"
md
"
variant
=
"
dark
"
>
<
Navbar
.
Brand
>
비밀번호
찾기
<
/Navbar.Brand
>
<
/Menu
>
<
Container
fluid
>
<
Row
className
=
"
justify-content-center
"
>
<
Col
md
=
{
3
}
xs
=
{
11
}
className
=
"
p-0
"
>
<
Formik
initialValues
=
{{
id
:
''
,
question
:
''
,
answer
:
''
}}
validationSchema
=
{
Yup
.
object
({
id
:
Yup
.
string
()
.
required
(
'
학번을 입력해주세요.
'
),
answer
:
Yup
.
string
()
.
required
(
'
답변을 입력해주세요.
'
),
})}
onSubmit
=
{(
values
,
{
setSubmitting
})
=>
{
axios
({
method
:
'
post
'
,
url
:
'
/login/find
'
,
data
:
values
,
}).
then
(
res
=>
{
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
localStorage
.
setItem
(
'
_id
'
,
res
.
data
.
users
.
_id
)
setState
(
true
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
console
.
log
(
values
);
setTimeout
(()
=>
{
setSubmitting
(
false
);
},
400
);
// finish the cycle in handler
}}
>
{({
errors
,
touched
,
handleSubmit
,
getFieldProps
,
// contain values, handleChange, handleBlur
isSubmitting
,
})
=>
(
<
form
onSubmit
=
{
handleSubmit
}
className
=
"
d-flex flex-column pt-5
"
>
<
div
className
=
"
form-group pb-2
"
>
<
div
className
=
{
touched
.
id
&&
errors
.
id
?
"
text-danger
"
:
""
}
>
학번을
입력하세요
<
/div
>
<
input
className
=
{(
touched
.
id
&&
errors
.
id
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
number
"
name
=
"
id
"
{...
getFieldProps
(
'
id
'
)}
placeholder
=
"
Input Student Id
"
/>
<
/div
>
<
div
className
=
"
form-group pb-2
"
>
<
label
className
=
"
pr-2
"
>
본인
확인
질문
<
/label
>
<
Field
as
=
"
select
"
name
=
"
question
"
>
<
option
value
=
""
>
질문을
선택하세요
<
/option
>
<
option
value
=
"
life
"
>
자신의
인생
좌우명은
?
<
/option
>
<
option
value
=
"
school
"
>
자신이
다녔던
초등학교의
이름은
?
<
/option
>
<
option
value
=
"
place
"
>
기억에
남는
추억의
장소는
?
<
/option
>
<
/Field
>
<
/div
>
<
div
className
=
"
form-group pb-2
"
>
<
div
className
=
{
touched
.
answer
&&
errors
.
answer
?
"
text-danger
"
:
""
}
>
답변을
입력해주세요
.
<
/div
>
<
input
className
=
{(
touched
.
answer
&&
errors
.
answer
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
text
"
name
=
"
answer
"
{...
getFieldProps
(
'
answer
'
)}
placeholder
=
"
Input answer
"
/>
<
/div
>
<
Button
className
=
"
mb-2
"
variant
=
"
secondary
"
type
=
"
submit
"
disabled
=
{
isSubmitting
}
>
비밀번호
찾기
<
/Button
>
<
Button
variant
=
"
outline-secondary
"
as
=
{
Link
}
to
=
"
/login
"
>
로그인하러
가기
<
/Button
>
<
/form
>
)}
<
/Formik
>
<
/Col
>
<
/Row
>
<
/Container
>
<
/div
>
);
}
export
default
Find
\ No newline at end of file
client/src/Pages/HomePage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Redirect
}
from
'
react-router-dom
'
;
import
axios
from
'
axios
'
;
import
Menu
from
'
../Components/Menu
'
;
import
Schedule
from
'
../Components/Schedule
'
;
import
{
Container
,
Tabs
,
Tab
}
from
'
react-bootstrap
'
;
function
Home
()
{
const
[
key
,
setKey
]
=
useState
(
'
9-116
'
);
const
[
state
,
setState
]
=
useState
()
useEffect
(()
=>
{
tcheck
();
},
[]);
if
(
state
)
return
<
Redirect
to
=
"
/
"
/>
;
function
tcheck
()
{
axios
.
get
(
`/users/
${
localStorage
.
getItem
(
'
_id
'
)}
`
,
{
headers
:
{
authorization
:
localStorage
.
getItem
(
'
token
'
)
},
})
.
then
(
res
=>
{
if
(
res
.
status
!==
201
)
{
alert
(
res
.
data
.
error
);
localStorage
.
clear
();
setState
(
true
);
}
}).
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
return
(
<
div
>
<
Menu
/>
<
Container
className
=
"
col-md-10 mt-3
"
>
<
h2
>
대관
현황
<
/h2
>
<
p
>
<
strong
>
대관
가능
시간
<
/strong
>
<
ul
className
=
"
pl-4
"
>
<
li
>
평일
:
9
시
-
22
시
/
예약가능
시간
이후
폐쇄
<
/li
>
<
li
>
주말
:
이용
불가
<
/li
>
<
/ul
>
<
/p
>
<
p
>
<
strong
>
유의사항
<
/strong
>
<
ul
className
=
"
pl-4
"
>
<
li
>
강의실
사용시
최소인원
수에
맞춰서
명단
작성이
필요합니다
.
<
/li
>
<
li
>
1
회
대관시
최대
3
시간까지
이용이
가능합니다
.
(
1
시간
단위로
대관
가능
)
<
/li
>
<
li
><
strong
style
=
{{
color
:
"
red
"
}}
>
대관
시간
이외
강의실을
이용하다
적발될
경우
한달
간
강의실
이용이
불가합니다
.
<
/strong></
li
>
<
/ul
>
<
/p
>
<
Tabs
defaultActiveKey
=
"
9-116
"
id
=
"
uncontrolled-tab-example
"
onSelect
=
{(
k
)
=>
setKey
(
k
)}
>
<
Tab
eventKey
=
"
9-116
"
title
=
"
9-116
"
>
<
Schedule
room
=
{
key
}
/
>
<
/Tab
>
<
Tab
eventKey
=
"
7-234
"
title
=
"
7-234
"
>
<
Schedule
room
=
{
key
}
/
>
<
/Tab
>
<
Tab
eventKey
=
"
25-101
"
title
=
"
25-101
"
>
<
Schedule
room
=
{
key
}
/
>
<
/Tab
>
<
/Tabs
>
<
/Container
>
<
/div
>
)
}
export
default
Home
\ No newline at end of file
client/src/Pages/LoginPage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
styled
from
'
styled-components
'
;
import
{
Link
,
Redirect
}
from
'
react-router-dom
'
;
import
{
Formik
}
from
'
formik
'
;
import
*
as
Yup
from
'
yup
'
;
import
axios
from
'
axios
'
;
import
Logo
from
'
../icon.png
'
;
import
{
Container
,
Row
,
Button
}
from
'
react-bootstrap
'
;
const
Col_1
=
styled
.
div
`
background-color: #7B031D;
&.web {
display : flex;
align-items: center;
}
&.mobile {
height : 20vh;
display : flex;
padding:0;
}
& .mob-head {
display: flex;
flex-direction: row;
height : 100%;
width: 100%;
justify-content: space-evenly;
}
& .mob-img {
max-width: 30vw;
}
`
const
Col_2
=
styled
.
div
`
background-color: rgb(239, 218, 200);
a {
color : #7B031D;
}
& .mob-formik {
height : 80vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
& .web-form {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
& .mob-container {
display: flex;
flex-direction: column;
}
& .webb {
flex-direction: column;
}
& .web-container {
display: flex;
height: 12vh;
width: 30vw;
}
& .web-input-form {
width: 80%;
display: flex;
flex-direction: column;
justify-content: space-around;
}
& .mob-input-form {
display: flex;
flex-direction: column;
justify-content: space-around;
}
`
function
Login
()
{
const
[
state
,
setState
]
=
useState
(
false
);
const
[
mobile
,
setMobile
]
=
useState
(
false
);
useEffect
(()
=>
{
if
(
window
.
innerWidth
<
960
)
{
setMobile
(
true
)
}
else
{
setMobile
(
false
)
}
},
[]);
if
(
state
)
{
return
<
Redirect
to
=
"
/home
"
/>
;
}
return
(
<
Container
fluid
className
=
"
p-0
"
>
<
Row
className
=
"
vw-100 vh-100 m-0
"
>
<
Col_1
className
=
{
"
col-md-4 col-12
"
+
(
mobile
?
"
mobile
"
:
"
web
"
)}
>
<
div
className
=
{
mobile
?
"
mob-head
"
:
""
}
>
<
img
className
=
{
mobile
?
"
mob-img
"
:
"
img-fluid
"
}
src
=
{
Logo
}
/
>
<
div
className
=
{
"
d-flex
"
+
(
mobile
?
"
align-items-center
"
:
"
justify-content-center
"
)}
>
<
h1
className
=
"
font-weight-bold text-white text-center
"
>
고려대학교
<
br
/>
대관
서비스
<
/h1
>
<
/div
>
<
/div
>
<
/Col_1
>
<
Col_2
className
=
"
col-md-8 col-12
"
>
<
Formik
initialValues
=
{{
id
:
''
,
password
:
''
}}
validationSchema
=
{
Yup
.
object
({
id
:
Yup
.
string
()
.
required
(
'
학번을 입력해주세요.
'
),
password
:
Yup
.
string
()
.
required
(
'
비밀번호를 입력해주세요.
'
)
.
min
(
8
,
'
8자 이상 입력해주세요.
'
),
})}
onSubmit
=
{(
values
,
{
setSubmitting
})
=>
{
axios
({
method
:
'
post
'
,
url
:
'
/login
'
,
data
:
values
,
}).
then
(
res
=>
{
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
localStorage
.
setItem
(
'
token
'
,
res
.
data
.
token
);
localStorage
.
setItem
(
'
_id
'
,
res
.
data
.
users
.
_id
);
localStorage
.
setItem
(
'
name
'
,
res
.
data
.
users
.
name
);
setState
(
true
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
setTimeout
(()
=>
{
setSubmitting
(
false
);
},
400
);
// finish the cycle in handler
}}
>
{({
errors
,
touched
,
handleSubmit
,
getFieldProps
,
// contain values, handleChange, handleBlur
isSubmitting
,
})
=>
(
<
div
className
=
{
mobile
?
"
mob-formik p-0
"
:
"
web-form
"
}
>
<
form
onSubmit
=
{
handleSubmit
}
className
=
{
mobile
?
"
w-75
"
:
"
d-flex webb
"
}
>
<
div
className
=
{
mobile
?
"
mob-container
"
:
"
web-container
"
}
>
<
div
className
=
{
mobile
?
"
mob-input-form
"
:
"
web-input-form mr-2
"
}
>
<
div
className
=
{
"
form-group m-0
"
+
(
mobile
?
"
mb-2
"
:
"
"
)}
>
<
input
className
=
{(
touched
.
id
&&
errors
.
id
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
text
"
name
=
"
id
"
{...
getFieldProps
(
'
id
'
)}
placeholder
=
"
Input Student Id
"
/>
<
/div
>
<
div
className
=
{
"
form-group m-0
"
+
(
mobile
?
"
mb-2
"
:
"
"
)}
>
<
input
className
=
{(
touched
.
password
&&
errors
.
password
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
password
"
name
=
"
password
"
{...
getFieldProps
(
'
password
'
)}
placeholder
=
"
Input Password
"
/>
<
/div
>
<
/div
>
<
Button
type
=
"
submit
"
variant
=
"
dark
"
className
=
{
mobile
?
"
w-100
"
:
"
w-20
"
}
disabled
=
{
isSubmitting
}
>
Login
<
/Button
>
<
/div
>
<
div
><
Link
to
=
"
/find
"
>
비밀번호를
잊으셨나요
?
<
/Link></
div
>
<
div
><
Link
to
=
"
/signup
"
>
회원이
아니신가요
?
<
/Link></
div
>
<
/form
>
<
/div
>
)}
<
/Formik
>
<
/Col_2
>
<
/Row
>
<
/Container
>
)
}
export
default
Login
\ No newline at end of file
client/src/Pages/ModifyPage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Redirect
}
from
'
react-router-dom
'
;
import
Menu
from
'
../Components/Menu
'
;
import
*
as
Yup
from
'
yup
'
;
import
axios
from
'
axios
'
;
import
{
Container
,
Row
,
Col
,
Button
}
from
'
react-bootstrap
'
;
import
{
Field
,
Formik
}
from
'
formik
'
;
function
Modify
({
match
})
{
const
[
state
,
setState
]
=
useState
(
false
);
const
[
modification
,
setModification
]
=
useState
({
title
:
""
,
content
:
""
});
const
[
isadmin
,
setIsadmin
]
=
useState
({
ok
:
""
});
const
[
user
,
setUser
]
=
useState
({
name
:
""
,
role
:
""
})
useEffect
(()
=>
{
acheck
();
getOne
(
match
.
params
.
id
);
},
[])
if
(
isadmin
.
ok
===
"
no
"
)
return
<
Redirect
to
=
"
/
"
/>
;
if
(
state
)
{
return
<
Redirect
to
=
"
/notice
"
/>
;
}
function
getOne
(
id
)
{
if
(
id
)
{
axios
.
get
(
`/notices/
${
match
.
params
.
id
}
`
)
.
then
(
res
=>
{
if
(
res
.
status
!==
201
)
{
alert
(
res
.
data
.
error
);
}
setModification
({
title
:
res
.
data
.
notice_title
,
content
:
res
.
data
.
notice_content
})
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
};
function
acheck
()
{
axios
.
get
(
`/users/admin/
${
localStorage
.
getItem
(
'
_id
'
)}
`
,
{
headers
:
{
authorization
:
localStorage
.
getItem
(
'
token
'
)
},
})
.
then
(
res
=>
{
if
(
res
.
status
!==
201
)
{
alert
(
res
.
data
.
error
);
setIsadmin
({
ok
:
"
no
"
});
}
setUser
({
name
:
res
.
data
.
name
,
role
:
res
.
data
.
role
})
}).
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
return
(
<
div
>
<
Menu
/>
<
Container
fluid
>
{
console
.
log
(
modification
)}
<
Row
className
=
"
justify-content-center
"
>
<
Col
md
=
{
5
}
xs
=
{
11
}
className
=
"
pt-3
"
>
<
Formik
initialValues
=
{{
name
:
user
.
name
,
title
:
modification
.
title
,
content
:
modification
.
content
}}
enableReinitialize
=
{
true
}
validationSchema
=
{
Yup
.
object
({
title
:
Yup
.
string
()
.
required
(
'
제목을 입력해주세요.
'
),
content
:
Yup
.
string
()
.
required
(
'
내용을 입력해주세요.
'
),
})}
onSubmit
=
{(
values
,
{
setSubmitting
})
=>
{
axios
({
method
:
'
put
'
,
url
:
`/writes/
${
match
.
params
.
id
}
`
,
data
:
values
,
})
.
then
(
res
=>
{
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
alert
(
"
공지 수정이 완료되었습니다.
"
)
setState
(
true
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
setTimeout
(()
=>
{
setSubmitting
(
false
);
},
400
);
// finish the cycle in handler
}}
>
{({
errors
,
touched
,
handleSubmit
,
getFieldProps
,
// contain values, handleChange, handleBlur
isSubmitting
,
})
=>
(
<
form
onSubmit
=
{
handleSubmit
}
className
=
"
d-flex flex-column
"
>
<
div
className
=
"
form-group
"
>
<
div
className
=
{
touched
.
name
&&
errors
.
name
?
"
text-danger
"
:
""
}
>
제목
<
/div
>
<
input
className
=
{(
touched
.
name
&&
errors
.
name
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
text
"
title
=
"
title
"
{...
getFieldProps
(
'
title
'
)}
disabled
/>
<
/div
>
<
div
className
=
"
form-group
"
>
<
div
className
=
{
touched
.
name
&&
errors
.
name
?
"
text-danger
"
:
""
}
>
내용
<
/div
>
<
Field
as
=
"
textarea
"
rows
=
{
8
}
style
=
{{
"
min-width
"
:
"
100%
"
}}
{...
getFieldProps
(
'
content
'
)}
/
>
<
/div
>
<
Button
className
=
"
mb-2
"
variant
=
"
dark
"
type
=
"
submit
"
disabled
=
{
isSubmitting
}
>
공지
수정
<
/Button
>
<
/form
>
)}
<
/Formik
>
<
/Col
>
<
/Row
>
<
/Container
>
<
/div
>
)
}
export
default
Modify
\ No newline at end of file
client/src/Pages/NoticePage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
Menu
from
'
../Components/Menu
'
;
import
axios
from
'
axios
'
;
import
{
Link
,
Redirect
}
from
'
react-router-dom
'
;
import
{
Container
,
Row
,
Col
,
Accordion
,
Button
}
from
'
react-bootstrap
'
;
import
CARD
from
'
../Components/Card
'
;
function
Notice
()
{
const
[
notices
,
setNotices
]
=
useState
([]);
const
[
user
,
setUser
]
=
useState
({
role
:
""
})
const
[
state
,
setState
]
=
useState
()
useEffect
(()
=>
{
acheck
();
getNotice
();
},
[]);
if
(
state
)
return
<
Redirect
to
=
"
/
"
/>
;
function
acheck
()
{
axios
.
get
(
`/users/
${
localStorage
.
getItem
(
'
_id
'
)}
`
,
{
headers
:
{
authorization
:
localStorage
.
getItem
(
'
token
'
)
},
})
.
then
(
res
=>
{
if
(
res
.
status
!==
201
)
{
alert
(
res
.
data
.
error
);
localStorage
.
clear
();
setState
(
true
);
}
if
(
res
.
data
.
role
==
"
admin
"
)
{
setUser
(
res
.
data
)
}
}).
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
function
getNotice
()
{
axios
.
get
(
`/notices`
)
.
then
(
res
=>
{
console
.
log
(
'
res.data=
'
,
res
.
data
)
if
(
res
.
status
!==
201
)
{
alert
(
res
.
data
.
error
);
}
setNotices
(
res
.
data
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
return
(
<
div
>
<
Menu
/>
<
Container
fluid
>
<
Row
className
=
"
justify-content-center vw-100 vh-90
"
>
<
Col
md
=
{
7
}
>
<
h2
className
=
"
p-3 border-bottom d-flex justify-content-between
"
>
공지사항
{
user
.
role
===
"
admin
"
?
(
<
Button
as
=
{
Link
}
to
=
"
/write
"
>
글
작성
<
/Button>
)
: null}</
h2
>
<
Accordion
>
{
notices
.
map
((
notice
,
index
)
=>
<
CARD
card_id
=
{
notice
.
_id
}
card_index
=
{
index
}
title
=
{
notice
.
notice_title
}
date
=
{
notice
.
post_date
}
content
=
{
notice
.
notice_content
}
admin
=
{
user
.
role
}
/
>
)}
<
/Accordion
>
<
/Col
>
<
/Row
>
<
/Container
>
<
/div
>
)
}
export
default
Notice
\ No newline at end of file
client/src/Pages/SignupPage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
}
from
'
react
'
;
import
{
Field
,
Formik
}
from
'
formik
'
;
import
*
as
Yup
from
'
yup
'
;
import
axios
from
'
axios
'
;
import
{
Link
,
Redirect
}
from
'
react-router-dom
'
;
import
styled
from
'
styled-components
'
;
import
{
Col
,
Container
,
Navbar
,
Button
}
from
'
react-bootstrap
'
;
const
Menu
=
styled
(
Navbar
)
`
background-color: #7B031D;
a {
color : white;
}
`
const
Wow
=
styled
.
div
`
height: 90vh;
& #reCheck::after {
content: '비밀번호를 다시 입력하세요';
}
& #reCheck:not(.right) {
content: '비밀번호가 일치하지 않습니다.';
color: red;
}
`
function
Signup
()
{
const
[
state
,
setState
]
=
useState
(
false
);
const
[
checkPw
,
setCheckPw
]
=
useState
(
true
);
if
(
state
)
{
return
<
Redirect
to
=
"
/login
"
/>
;
}
return
(
<
div
className
=
"
vh-100
"
>
<
Menu
expand
=
"
md
"
variant
=
"
dark
"
>
<
Navbar
.
Brand
>
회원가입
<
/Navbar.Brand
>
<
/Menu
>
<
Container
fluid
>
<
Wow
className
=
"
row justify-content-center
"
>
<
Col
md
=
{
3
}
xs
=
{
11
}
className
=
"
p-0
"
>
<
Formik
initialValues
=
{{
name
:
''
,
id
:
''
,
password
:
''
,
password2
:
''
,
question
:
''
,
answer
:
''
}}
validationSchema
=
{
Yup
.
object
({
name
:
Yup
.
string
()
.
required
(
'
이름을 입력해주세요.
'
),
id
:
Yup
.
string
()
.
required
(
'
학번을 입력해주세요.
'
),
password
:
Yup
.
string
()
.
required
(
'
비밀번호를 입력해주세요.
'
)
.
min
(
8
,
'
8자 이상 입력해주세요.
'
),
password2
:
Yup
.
string
()
.
required
(
'
비밀번호를 다시 입력해주세요.
'
)
.
min
(
8
,
'
8자 이상 입력해주세요.
'
)
.
oneOf
([
Yup
.
ref
(
"
password
"
),
null
],
'
비밀번호가 일치하지 않습니다.
'
),
answer
:
Yup
.
string
()
.
required
(
'
답변을 입력해주세요.
'
),
})}
onSubmit
=
{(
values
,
{
setSubmitting
})
=>
{
axios
({
method
:
'
post
'
,
url
:
'
/users
'
,
data
:
values
,
}).
then
(
res
=>
{
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
alert
(
"
회원가입이 완료되었습니다!
"
)
setState
(
true
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
setTimeout
(()
=>
{
setSubmitting
(
false
);
},
400
);
// finish the cycle in handler
}}
>
{({
errors
,
touched
,
handleSubmit
,
getFieldProps
,
// contain values, handleChange, handleBlur
isSubmitting
,
})
=>
(
<
form
onSubmit
=
{
handleSubmit
}
className
=
"
d-flex flex-column pt-3
"
>
<
div
className
=
"
form-group
"
>
<
div
className
=
{
touched
.
name
&&
errors
.
name
?
"
text-danger
"
:
""
}
>
이름을
입력하세요
<
/div
>
<
input
className
=
{(
touched
.
name
&&
errors
.
name
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
text
"
name
=
"
name
"
{...
getFieldProps
(
'
name
'
)}
placeholder
=
"
이름
"
/>
<
/div
>
<
div
className
=
"
form-group
"
>
<
div
className
=
{
touched
.
id
&&
errors
.
id
?
"
text-danger
"
:
""
}
>
학번을
입력하세요
<
/div
>
<
input
className
=
{(
touched
.
id
&&
errors
.
id
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
text
"
name
=
"
id
"
{...
getFieldProps
(
'
id
'
)}
placeholder
=
"
학번/교번
"
/>
<
/div
>
<
div
className
=
"
form-group
"
>
<
div
className
=
{
touched
.
password
&&
errors
.
password
?
"
text-danger
"
:
""
}
>
비밀번호를
입력하세요
(
8
자리
이상
)
<
/div
>
<
input
className
=
{(
touched
.
password
&&
errors
.
password
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
password
"
name
=
"
password
"
{...
getFieldProps
(
'
password
'
)}
placeholder
=
"
비밀번호
"
/>
<
/div
>
<
div
className
=
"
form-group
"
>
{
touched
.
password2
&&
errors
.
password2
?
setCheckPw
(
false
)
:
null
}
<
div
id
=
"
reCheck
"
className
=
{
checkPw
?
"
right
"
:
"
err
"
}
><
/div
>
<
input
className
=
{
touched
.
password2
&&
errors
.
password2
?
"
form-control is-invalid
"
:
"
form-control
"
}
type
=
"
password
"
name
=
"
password2
"
{...
getFieldProps
(
'
password2
'
)}
placeholder
=
"
비밀번호 확인
"
/>
<
/div
>
<
div
className
=
"
form-group
"
>
<
label
>
본인
확인
질문
<
/label
>
<
Field
as
=
"
select
"
name
=
"
question
"
>
<
option
value
=
""
>
질문을
선택하세요
<
/option
>
<
option
value
=
"
life
"
>
자신의
인생
좌우명은
?
<
/option
>
<
option
value
=
"
school
"
>
자신이
다녔던
초등학교의
이름은
?
<
/option
>
<
option
value
=
"
place
"
>
기억에
남는
추억의
장소는
?
<
/option
>
<
/Field
>
<
/div
>
<
div
className
=
"
form-group
"
>
<
div
className
=
{
touched
.
answer
&&
errors
.
answer
?
"
text-danger
"
:
""
}
>
답변을
입력해주세요
.
<
/div
>
<
input
className
=
{(
touched
.
answer
&&
errors
.
answer
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
text
"
name
=
"
answer
"
{...
getFieldProps
(
'
answer
'
)}
placeholder
=
"
Input answer
"
/>
<
/div
>
<
Button
type
=
"
submit
"
variant
=
"
secondary
"
className
=
"
mb-2
"
disabled
=
{
isSubmitting
}
>
회원가입
<
/Button
>
<
Button
variant
=
"
outline-secondary
"
as
=
{
Link
}
to
=
"
/login
"
>
로그인하러
가기
<
/Button
>
<
/form
>
)}
<
/Formik
>
<
/Col
>
<
/Wow
>
<
/Container
>
<
/div
>
);
}
export
default
Signup
\ No newline at end of file
client/src/Pages/WritePage.js
0 → 100644
View file @
61a30671
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Redirect
}
from
'
react-router-dom
'
;
import
Menu
from
'
../Components/Menu
'
;
import
*
as
Yup
from
'
yup
'
;
import
axios
from
'
axios
'
;
import
{
Container
,
Row
,
Col
,
Button
}
from
'
react-bootstrap
'
;
import
{
Field
,
Formik
}
from
'
formik
'
;
function
Write
()
{
const
[
state
,
setState
]
=
useState
(
false
);
const
[
isadmin
,
setIsadmin
]
=
useState
({
ok
:
""
});
const
[
user
,
setUser
]
=
useState
({
name
:
""
})
useEffect
(()
=>
{
acheck
();
},
[])
if
(
isadmin
.
ok
===
"
no
"
)
return
<
Redirect
to
=
"
/
"
/>
;
if
(
state
)
{
return
<
Redirect
to
=
"
/notice
"
/>
;
}
function
acheck
()
{
axios
.
get
(
`/users/admin/
${
localStorage
.
getItem
(
'
_id
'
)}
`
,
{
headers
:
{
authorization
:
localStorage
.
getItem
(
'
token
'
)
},
})
.
then
(
res
=>
{
if
(
res
.
status
!==
201
)
{
alert
(
res
.
data
.
error
);
console
.
log
(
res
.
data
)
setIsadmin
({
ok
:
"
no
"
});
}
setUser
({
name
:
res
.
data
.
name
})
}).
catch
(
err
=>
{
alert
(
err
.
error
)
});
}
return
(
<
div
>
<
Menu
/>
<
Container
fluid
>
<
Row
className
=
"
justify-content-center
"
>
<
Col
md
=
{
5
}
xs
=
{
11
}
className
=
"
pt-3
"
>
<
Formik
initialValues
=
{{
name
:
user
.
name
,
title
:
''
,
content
:
''
}}
enableReinitialize
=
{
true
}
validationSchema
=
{
Yup
.
object
({
title
:
Yup
.
string
()
.
required
(
'
제목을 입력해주세요.
'
),
content
:
Yup
.
string
()
.
required
(
'
내용을 입력해주세요.
'
),
})}
onSubmit
=
{(
values
,
{
setSubmitting
})
=>
{
console
.
log
(
values
)
axios
({
method
:
'
post
'
,
url
:
'
/writes
'
,
data
:
values
,
}).
then
(
res
=>
{
if
(
res
.
status
===
404
)
return
alert
(
res
.
data
.
error
)
alert
(
"
공지 등록이 완료되었습니다.
"
)
setState
(
true
);
})
.
catch
(
err
=>
{
alert
(
err
.
error
)
});
setTimeout
(()
=>
{
setSubmitting
(
false
);
},
400
);
// finish the cycle in handler
}}
>
{({
errors
,
touched
,
handleSubmit
,
getFieldProps
,
// contain values, handleChange, handleBlur
isSubmitting
,
})
=>
(
<
form
onSubmit
=
{
handleSubmit
}
className
=
"
d-flex flex-column
"
>
<
div
className
=
"
form-group
"
>
<
div
className
=
{
touched
.
name
&&
errors
.
name
?
"
text-danger
"
:
""
}
>
제목
<
/div
>
<
input
className
=
{(
touched
.
name
&&
errors
.
name
?
'
form-control is-invalid
'
:
"
form-control
"
)}
type
=
"
text
"
title
=
"
title
"
{...
getFieldProps
(
'
title
'
)}
placeholder
=
"
제목
"
/>
<
/div
>
<
div
className
=
"
form-group
"
>
<
div
className
=
{
touched
.
name
&&
errors
.
name
?
"
text-danger
"
:
""
}
>
내용
<
/div
>
<
Field
as
=
"
textarea
"
rows
=
{
8
}
style
=
{{
"
min-width
"
:
"
100%
"
}}
{...
getFieldProps
(
'
content
'
)}
/
>
<
/div
>
<
Button
className
=
"
mb-2
"
variant
=
"
dark
"
type
=
"
submit
"
disabled
=
{
isSubmitting
}
>
공지
등록
<
/Button
>
<
/form
>
)}
<
/Formik
>
<
/Col
>
<
/Row
>
<
/Container
>
<
/div
>
)
}
export
default
Write
\ No newline at end of file
client/src/caret-left-fill.svg
0 → 100644
View file @
61a30671
<svg
width=
"1em"
height=
"1em"
viewBox=
"0 0 16 16"
class=
"bi bi-caret-left-fill"
fill=
"currentColor"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M3.86 8.753l5.482 4.796c.646.566 1.658.106 1.658-.753V3.204a1 1 0 0 0-1.659-.753l-5.48 4.796a1 1 0 0 0 0 1.506z"
/>
</svg>
\ No newline at end of file
client/src/caret-right-fill.svg
0 → 100644
View file @
61a30671
<svg
width=
"1em"
height=
"1em"
viewBox=
"0 0 16 16"
class=
"bi bi-caret-right-fill"
fill=
"currentColor"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M12.14 8.753l-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z"
/>
</svg>
\ No newline at end of file
client/src/icon.png
0 → 100644
View file @
61a30671
2.44 MB
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