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
butter-studio
Commits
d837894e
Commit
d837894e
authored
Jul 28, 2021
by
Jiwon Yoon
Browse files
좌석예매/로그인여부 판단 및 이메일 api
parent
91911f85
Changes
23
Hide whitespace changes
Inline
Side-by-side
client/package-lock.json
View file @
d837894e
...
...
@@ -3073,14 +3073,6 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.2.3.tgz",
"integrity": "sha512-pXnVMfJKSIWU2Ml4JHP7pZEPIrgBO1Fd3WGx+fPBsS+KRGhE4vxooD8XBGWbQOIVSZsVK7pUDBBkCicNu80yzQ=="
},
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
...
...
@@ -3873,11 +3865,6 @@
}
}
},
"buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
...
...
@@ -4938,11 +4925,6 @@
"whatwg-url": "^8.0.0"
}
},
"dayjs": {
"version": "1.10.6",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz",
"integrity": "sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw=="
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
...
...
@@ -5380,14 +5362,6 @@
"safer-buffer": "^2.1.0"
}
},
"ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
...
...
@@ -9968,30 +9942,6 @@
"universalify": "^2.0.0"
}
},
"jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"requires": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
}
}
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
...
...
@@ -10012,25 +9962,6 @@
"object.assign": "^4.1.2"
}
},
"jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"requires": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
...
...
@@ -10162,36 +10093,6 @@
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
"lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
},
"lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
},
"lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
},
"lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
},
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
},
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
...
...
@@ -10202,11 +10103,6 @@
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
"lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
},
"lodash.template": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
...
...
@@ -11521,11 +11417,6 @@
"ts-pnp": "^1.1.6"
}
},
"pop-iterate": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pop-iterate/-/pop-iterate-1.0.1.tgz",
"integrity": "sha1-zqz9q0q/NT16DyqqLB/Hs/lBO6M="
},
"portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
...
...
@@ -13758,11 +13649,6 @@
}
}
},
"rootpath": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/rootpath/-/rootpath-0.1.2.tgz",
"integrity": "sha1-Wzeah9ypBum5HWkKWZQ5vvJn6ms="
},
"rsvp": {
"version": "4.8.5",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
...
...
@@ -14004,11 +13890,6 @@
"ajv-keywords": "^3.5.2"
}
},
"scmp": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz",
"integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q=="
},
"scss-tokenizer": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
...
...
@@ -15425,44 +15306,6 @@
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
"twilio": {
"version": "3.66.0",
"resolved": "https://registry.npmjs.org/twilio/-/twilio-3.66.0.tgz",
"integrity": "sha512-2jek7akXcRMusoR20EWA1+e5TQp9Ahosvo81wTUoeS7H24A1xbVQJV4LfSWQN4DLUY1oZ4d6tH2oCe/+ELcpNA==",
"requires": {
"axios": "^0.21.1",
"dayjs": "^1.8.29",
"https-proxy-agent": "^5.0.0",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"q": "2.0.x",
"qs": "^6.9.4",
"rootpath": "^0.1.2",
"scmp": "^2.1.0",
"url-parse": "^1.5.0",
"xmlbuilder": "^13.0.2"
},
"dependencies": {
"q": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz",
"integrity": "sha1-dbjbAlWhpa+C9Yw/Oqoe/sfQ0TQ=",
"requires": {
"asap": "^2.0.0",
"pop-iterate": "^1.0.1",
"weak-map": "^1.0.5"
}
},
"qs": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
"integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
"requires": {
"side-channel": "^1.0.4"
}
}
}
},
"type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
...
...
@@ -16080,11 +15923,6 @@
"minimalistic-assert": "^1.0.0"
}
},
"weak-map": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.5.tgz",
"integrity": "sha1-eWkVhNmGB/UHC9O3CkDmuyLkAes="
},
"web-vitals": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-1.1.2.tgz",
...
...
@@ -17109,11 +16947,6 @@
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
},
"xmlbuilder": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz",
"integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ=="
},
"xmlchars": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
...
...
client/package.json
View file @
d837894e
...
...
@@ -15,7 +15,6 @@
"react-dom"
:
"^17.0.2"
,
"react-router-dom"
:
"^5.2.0"
,
"react-scripts"
:
"4.0.3"
,
"twilio"
:
"^3.66.0"
,
"web-vitals"
:
"^1.0.1"
},
"scripts"
:
{
...
...
client/src/components/SeatTable/SeatTable.js
View file @
d837894e
...
...
@@ -3,37 +3,45 @@ import styles from './seatTable.module.scss'
const
SeatTable
=
(
props
)
=>
{
const
table
=
[]
for
(
let
rowIndex
=
0
;
rowIndex
<
props
.
allSeat
.
row
;
rowIndex
++
)
{
table
.
push
(
<
span
className
=
"
me-3
"
style
=
{{
color
:
"
gray
"
}}
>
{
String
.
fromCharCode
(
rowIndex
+
65
)}
<
/span>
)
// console.log(String.fromCharCode(rowIndex+65))
for
(
let
colIndex
=
0
;
colIndex
<
props
.
allSeat
.
col
;
colIndex
++
)
{
table
.
push
(
<
span
>
<
button
className
=
{
props
.
selectedSeats
.
find
(
el
=>
el
===
String
.
fromCharCode
(
rowIndex
+
65
)
+
String
(
colIndex
+
1
))
?
styles
.
on
:
styles
.
btn
}
name
=
{
`
${
String
.
fromCharCode
(
rowIndex
+
65
)}${
colIndex
+
1
}
`
}
type
=
"
button
"
onClick
=
{
handleClick
}
>
{
colIndex
+
1
}
<
/button
>
<
/span
>
)
if
(
props
.
theaterInfo
)
{
for
(
let
rowIndex
=
0
;
rowIndex
<
props
.
theaterInfo
.
rows
;
rowIndex
++
)
{
table
.
push
(
<
span
className
=
"
me-3
"
style
=
{{
color
:
"
gray
"
}}
>
{
String
.
fromCharCode
(
rowIndex
+
65
)}
<
/span>
)
for
(
let
colIndex
=
0
;
colIndex
<
props
.
theaterInfo
.
columns
;
colIndex
++
)
{
table
.
push
(
<
span
>
{
props
.
reservedSeats
.
find
(
el
=>
el
===
String
(
rowIndex
+
1
)
+
'
-
'
+
String
(
colIndex
+
1
))
?
<
button
className
=
{
styles
.
btnBlock
}
name
=
{
rowIndex
+
1
}
id
=
{
colIndex
+
1
}
type
=
"
button
"
disabled
>
{
colIndex
+
1
}
<
/button
>
:
<
button
className
=
{
props
.
selectedSeats
.
find
(
el
=>
el
===
String
(
rowIndex
+
1
)
+
'
-
'
+
String
(
colIndex
+
1
))
?
styles
.
on
:
styles
.
btn
}
name
=
{
rowIndex
+
1
}
id
=
{
colIndex
+
1
}
type
=
"
button
"
onClick
=
{
handleClick
}
>
{
colIndex
+
1
}
<
/button
>
}
<
/span
>
)
}
table
.
push
(
<
br
/>
)
}
table
.
push
(
<
br
/>
)
}
function
handleClick
(
event
)
{
const
num
=
Object
.
values
(
props
.
count
).
reduce
((
a
,
b
)
=>
(
a
+
b
))
if
(
props
.
selectedSeats
.
find
(
el
=>
el
===
event
.
target
.
name
))
{
if
(
props
.
selectedSeats
.
find
(
el
=>
el
===
event
.
target
.
name
+
'
-
'
+
event
.
target
.
id
))
{
//제거
const
deleted
=
props
.
selectedSeats
.
filter
((
element
)
=>
element
!==
event
.
target
.
name
);
const
deleted
=
props
.
selectedSeats
.
filter
((
element
)
=>
element
!==
event
.
target
.
name
+
'
-
'
+
event
.
target
.
id
);
props
.
setSelectedSeats
(
deleted
)
}
else
{
if
(
props
.
selectedSeats
.
length
>
num
-
1
)
{
alert
(
"
선택한 좌석이 예매인원보다 많습니다.
"
)
}
else
{
//추가
props
.
setSelectedSeats
([...
props
.
selectedSeats
,
event
.
target
.
name
])
props
.
setSelectedSeats
([...
props
.
selectedSeats
,
event
.
target
.
name
+
'
-
'
+
event
.
target
.
id
])
}
}
}
return
(
<
div
className
=
"
text-center
"
>
{
/* {console.log(props.theaterInfo)} */
}
{
console
.
log
(
props
.
selectedSeats
)}
<
div
className
=
"
mb-2
"
style
=
{{
backgroundColor
:
"
gray
"
}}
>
Screen
<
/div
>
{
table
}
...
...
client/src/components/SeatTable/seatTable.module.scss
View file @
d837894e
...
...
@@ -12,4 +12,10 @@
border
:
0
;
background
:
red
;
color
:white
}
.btnBlock
{
background
:
gray
;
border
:
0
;
color
:white
;
}
\ No newline at end of file
client/src/components/TicketingTheater/TicketingTheater.js
View file @
d837894e
...
...
@@ -4,17 +4,13 @@ const TicketingTheater = (props) => {
function
handleClick
(
event
)
{
// event.preventDefault()
console
.
log
(
event
.
target
.
name
)
props
.
setTicketInfo
({
...
props
.
ticketInfo
,
theater
:
event
.
target
.
name
})
props
.
setTicketInfo
({
...
props
.
ticketInfo
,
cinema
:
event
.
target
.
name
})
}
return
(
<
div
>
<
div
className
=
"
d-grid gap-2
"
>
{
props
.
theaterInfo
.
theater
.
length
>
0
?
props
.
theaterInfo
.
theater
.
map
(
name
=>
(
<
button
name
=
{
name
}
className
=
{
`
${
props
.
ticketInfo
.
theater
===
name
?
styles
.
on
:
styles
.
btn
}
`
}
onClick
=
{
handleClick
}
>
{
name
}
<
/button
>
))
:
<
div
>
영화관
정보가
존재하지
않습니다
.
<
/div>
}
<
button
name
=
{
props
.
cinemaInfo
.
cinemaName
}
className
=
{
`
${
props
.
ticketInfo
.
cinema
===
props
.
cinemaInfo
.
cinemaName
?
styles
.
on
:
styles
.
btn
}
`
}
onClick
=
{
handleClick
}
>
{
props
.
cinemaInfo
.
cinemaName
}
<
/button
>
<
/div
>
<
/div
>
)
...
...
client/src/context/auth_context.js
View file @
d837894e
...
...
@@ -41,7 +41,7 @@ const AuthProvider = ({ children }) => {
const
logout
=
useCallback
(
async
()
=>
{
try
{
setError
(
""
);
setUser
(
null
);
setUser
(
{
id
:
0
,
user
:
"
user
"
}
);
alert
(
"
로그아웃되었습니다.
"
);
localStorage
.
removeItem
(
config
.
loginUser
);
setLoading
(
true
);
...
...
client/src/pages/PaymentPage.js
View file @
d837894e
import
axios
from
'
axios
'
import
{
useState
}
from
'
react
'
import
{
useEffect
,
useState
}
from
'
react
'
import
Kakaopay
from
'
../components/Kakaopay
'
import
{
useAuth
}
from
'
../context/auth_context
'
import
catchErrors
from
'
../utils/catchErrors
'
const
Payment
=
({
location
})
=>
{
const
[
ticketInfo
,
setTicketInfo
]
=
useState
({
...
location
.
state
})
const
[
error
,
setError
]
=
useState
(
""
)
const
[
userInfo
,
setUserInfo
]
=
useState
()
const
{
user
}
=
useAuth
()
useEffect
(()
=>
{
getUserInfo
()
},
[])
async
function
getUserInfo
()
{
try
{
const
response
=
await
axios
.
post
(
`/api/auth/getuserinfo`
,
{
id
:
user
.
id
})
setUserInfo
(
response
.
data
)
}
catch
(
error
)
{
catchErrors
(
error
,
setError
)
}
}
async
function
SendMail
(
e
)
{
try
{
const
response
=
await
axios
.
post
(
'
/api/email/send
'
,{
email
:
e
.
target
.
name
const
response
=
await
axios
.
post
(
'
/api/email/send
'
,
{
...
ticketInfo
,
...
userInfo
})
console
.
log
(
response
.
data
)
}
catch
(
error
)
{
...
...
@@ -19,6 +42,7 @@ const Payment = ({ location }) => {
return
(
<
div
className
=
"
container
"
style
=
{{
color
:
"
white
"
}}
>
{
console
.
log
(
ticketInfo
)}
{
console
.
log
(
userInfo
)}
<
div
className
=
"
row justify-content-center my-5
"
>
<
div
className
=
"
col-sm-4 mb-3
"
>
<
h3
className
=
"
py-2 text-white text-center
"
style
=
{{
border
:
"
3px solid #000000
"
,
borderBottom
:
"
3px solid #FEDC00
"
}}
>
결제하기
<
/h3
>
...
...
@@ -26,27 +50,40 @@ const Payment = ({ location }) => {
<
/div
>
<
div
className
=
"
row justify-content-center
"
>
<
div
className
=
"
col-sm-8 text-center
"
>
{
user
?.
id
>
0
?
<
div
>
<
h5
className
=
"
mb-3
"
>
회원정보
<
/h5
>
<
/div
>
:
<
div
>
<
h5
className
=
"
mb-3
"
>
비회원예매
정보입력
<
/h5
>
<
/div
>
}
<
h5
className
=
"
mb-3
"
>
결제방법
<
/h5
>
<
img
src
=
"
/images/naverpay_button.png
"
/>
<
img
src
=
"
/images/naverpay_button.png
"
/>
<
Kakaopay
ticketInfo
=
{
ticketInfo
}
setTicketInfo
=
{
setTicketInfo
}
/
>
<
div
className
=
"
my-5
"
>
<
button
className
=
"
btn btn-warning
"
type
=
"
button
"
onClick
=
{
SendMail
}
>
결제완료
<
/button
>
<
/div
>
<
/div
>
<
div
className
=
"
col-sm-4 p-3 text-center rounded-3
"
style
=
{{
backgroundColor
:
"
#252525
"
}}
>
<
img
style
=
{{
maxHeight
:
"
10rem
"
}}
src
=
{
`https://image.tmdb.org/t/p/original
${
ticketInfo
.
poster_path
}
`
}
alt
=
"
영화포스터
"
/>
<
h5
className
=
"
my-3
"
>
{
ticketInfo
.
title
}
<
/h5
>
<
div
>
{
ticketInfo
.
theater
}
<
/div
>
<
div
>
{
ticketInfo
.
cinema
}
<
/div
>
<
div
>
{
ticketInfo
.
time
}
<
/div
>
<
div
className
=
"
mb-3
"
>
{
ticketInfo
.
selected
CinemaNum
}
관
{
ticketInfo
.
selectedSeats
}
<
/div
>
<
div
className
=
"
rounded-3 p-3
"
style
=
{{
backgroundColor
:
'
#404040
'
}}
>
<
div
className
=
"
mb-3
"
>
{
ticketInfo
.
selected
Theater
}
관
{
ticketInfo
.
selectedSeats
}
<
/div
>
<
div
className
=
"
rounded-3 p-3
"
style
=
{{
backgroundColor
:
'
#404040
'
}}
>
<
div
>
청소년
:
{
ticketInfo
.
teenager
}
명
<
/div
>
<
div
>
성인
:
{
ticketInfo
.
adult
}
명
<
/div
>
<
div
>
경로우대
:
{
ticketInfo
.
elderly
}
명
<
/div
>
<
div
>
총
결제금액
:
{
ticketInfo
.
teenager
*
7000
+
ticketInfo
.
adult
*
8000
+
ticketInfo
.
elderly
*
6000
}
<
/div
>
<
div
>
총
결제금액
:
{
ticketInfo
.
teenager
*
7000
+
ticketInfo
.
adult
*
8000
+
ticketInfo
.
elderly
*
6000
}
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
div
>
<
button
type
=
"
button
"
name
=
"
jiwon5393@naver.com
"
onClick
=
{
SendMail
}
>
메일발송
<
/button
>
<
/div
>
<
/div
>
)
}
...
...
client/src/pages/TicketingPage.js
View file @
d837894e
import
axios
from
'
axios
'
import
{
useState
,
useEffect
}
from
'
react
'
import
{
Link
}
from
'
react-router-dom
'
import
movieApi
from
'
../apis/movie.api.js
'
...
...
@@ -8,16 +9,17 @@ import TicketingTimeTable from "../components/TicketingTimeTable/TicketingTimeTa
const
TicketingPage
=
({
location
})
=>
{
const
[
ticketInfo
,
setTicketInfo
]
=
useState
({
...
location
.
state
,
theater
:
""
,
selected
CinemaNum
:
3
,
cinema
:
""
,
selected
Theater
:
1
,
time
:
"
2021/07/21 10:00
"
})
const
[
theaterInfo
,
setTheaterInfo
]
=
useState
({
theater
:
[
"
Butter Studio 조치원
"
],
cinemaNum
:
[
1
,
2
,
3
,
4
]
})
const
[
cinemaInfo
,
setCinemaInfo
]
=
useState
({})
const
[
movieInfo
,
setMovieInfo
]
=
useState
()
useEffect
(()
=>
{
getCinemaInfo
()
},
[])
useEffect
(()
=>
{
getMovieInfo
()
},
[
ticketInfo
])
...
...
@@ -30,7 +32,15 @@ const TicketingPage = ({ location }) => {
console
.
log
(
error
)
}
}
async
function
getCinemaInfo
()
{
try
{
const
response
=
await
axios
.
get
(
'
/api/info/cinema
'
)
console
.
log
(
response
.
data
)
setCinemaInfo
(
response
.
data
)
}
catch
(
error
)
{
console
.
log
(
error
)
}
}
return
(
<
div
className
=
"
container
"
style
=
{{
backgroundColor
:
"
black
"
}}
>
<
div
>
...
...
@@ -43,11 +53,11 @@ const TicketingPage = ({ location }) => {
<
/div
>
<
div
className
=
"
col-sm-3 mb-4
"
>
<
h3
className
=
"
py-2 mb-3 text-white text-center
"
style
=
{{
border
:
"
3px solid #000000
"
,
borderBottom
:
"
3px solid #FEDC00
"
}}
>
극장
<
/h3
>
<
TicketingTheater
theaterInfo
=
{
theater
Info
}
ticketInfo
=
{
ticketInfo
}
setTicketInfo
=
{
setTicketInfo
}
/
>
<
TicketingTheater
cinemaInfo
=
{
cinema
Info
}
ticketInfo
=
{
ticketInfo
}
setTicketInfo
=
{
setTicketInfo
}
/
>
<
/div
>
<
div
className
=
"
col-sm-5 mb-4
"
>
<
h3
className
=
"
py-2 text-white text-center
"
style
=
{{
border
:
"
3px solid #000000
"
,
borderBottom
:
"
3px solid #FEDC00
"
}}
>
시간표
<
/h3
>
<
TicketingTimeTable
ticketInfo
=
{
ticketInfo
}
theaterInfo
=
{
theater
Info
}
/
>
<
TicketingTimeTable
ticketInfo
=
{
ticketInfo
}
cinemaInfo
=
{
cinema
Info
}
/
>
<
/div
>
<
/div
>
<
div
className
=
"
row p-3
"
style
=
{{
backgroundColor
:
"
#252525
"
}}
>
...
...
@@ -58,18 +68,18 @@ const TicketingPage = ({ location }) => {
<
/div
>
<
div
className
=
"
col-sm-6 border-end
"
style
=
{{
color
:
"
white
"
}}
>
<
div
className
=
"
mb-2 text-center
"
>
극장선택
<
/div
>
{
movieInfo
&&
ticketInfo
.
theater
{
movieInfo
&&
ticketInfo
.
cinema
?
<
ul
>
<
li
>
영화
:
{
movieInfo
.
title
}
<
/li
>
<
li
>
극장
:
{
ticketInfo
.
theater
}
<
/li
>
<
li
>
극장
:
{
ticketInfo
.
cinema
}
<
/li
>
<
li
>
일시
:
{
ticketInfo
.
time
}
<
/li
>
<
li
>
상영관
:
{
ticketInfo
.
selected
CinemaNum
}
<
/li
>
<
li
>
상영관
:
{
ticketInfo
.
selected
Theater
}
<
/li
>
<
/ul
>
:
<
div
><
/div>
}
<
/div
>
<
div
className
=
"
col-sm-3 text-center
"
>
<
div
className
=
"
mb-2
"
style
=
{{
color
:
"
white
"
}}
>
좌석선택
<
/div
>
{
movieInfo
&&
ticketInfo
.
theater
{
movieInfo
&&
ticketInfo
.
cinema
?
<
Link
to
=
{{
pathname
:
`/ticket/seat`
,
...
...
client/src/pages/TicketingSeatPage.js
View file @
d837894e
import
{
Link
}
from
'
react-router-dom
'
import
{
useState
}
from
'
react
'
import
{
Link
,
useHistory
}
from
'
react-router-dom
'
import
{
useState
,
useEffect
,
useRef
}
from
'
react
'
import
{
Modal
}
from
'
bootstrap
'
import
CountButton
from
'
../components/CountButton
'
import
SeatTable
from
'
../components/SeatTable/SeatTable
'
import
styles
from
'
../components/SeatTable/seatTable.module.scss
'
import
axios
from
'
axios
'
import
{
useAuth
}
from
'
../context/auth_context.js
'
const
TicketingSeatPage
=
({
location
})
=>
{
const
history
=
useHistory
()
const
modalRef
=
useRef
(
null
)
const
modal
=
useRef
()
const
{
user
}
=
useAuth
()
const
[
ticketInfo
,
setTicketInfo
]
=
useState
({
...
location
.
state
})
const
[
theaterInfo
,
setTheaterInfo
]
=
useState
()
const
[
selectedSeats
,
setSelectedSeats
]
=
useState
([])
const
[
reservedSeats
,
setReservedSeats
]
=
useState
([])
const
[
count
,
setCount
]
=
useState
({
adult
:
0
,
teenager
:
0
,
elderly
:
0
})
const
allSeat
=
{
row
:
6
,
col
:
10
}
return
(
<
div
className
=
"
container
"
style
=
{{
color
:
"
white
"
}}
>
{
console
.
log
(
ticketInfo
)}
<
div
className
=
"
row justify-content-center my-5
"
>
<
div
className
=
"
col-sm-4 mb-3
"
>
<
h3
className
=
"
py-2 text-white text-center
"
style
=
{{
border
:
"
3px solid #000000
"
,
borderBottom
:
"
3px solid #FEDC00
"
}}
>
좌석선택
<
/h3
>
<
/div
>
<
/div
>
<
div
className
=
"
row justify-content-center my-3
"
>
<
div
className
=
"
col-sm-6 mb-4 text-center
"
>
<
div
className
=
"
row
"
>
<
div
className
=
"
col-sm-6 text-end
"
>
<
div
className
=
"
my-1
"
>
일반
<
/div
>
<
div
className
=
"
my-1
"
>
청소년
<
/div
>
<
div
className
=
"
my-1
"
>
경로우대
<
/div
>
<
/div
>
<
div
className
=
"
col-sm-6 text-start
"
>
<
CountButton
name
=
"
adult
"
count
=
{
count
}
setCount
=
{
setCount
}
/
>
<
CountButton
name
=
"
teenager
"
count
=
{
count
}
setCount
=
{
setCount
}
/
>
<
CountButton
name
=
"
elderly
"
count
=
{
count
}
setCount
=
{
setCount
}
/
>
<
/div
>
<
/div
>
{
/* <span className="">일반</span>
<CountButton name="adult" count={count} setCount={setCount} />
useEffect
(()
=>
{
getInfo
()
},
[])
<span className="">청소년</span>
<CountButton name="teenager" count={count} setCount={setCount} />
async
function
getInfo
()
{
try
{
const
response
=
await
axios
.
post
(
'
/api/theater/getInfo
'
,
{
theaterNum
:
ticketInfo
.
selectedTheater
})
console
.
log
(
response
.
data
)
setTheaterInfo
(
response
.
data
)
const
response2
=
await
axios
.
post
(
'
/api/reservation/findreservation
'
,
{
timetable
:
1
})
console
.
log
(
response2
.
data
)
const
reserve
=
response2
.
data
.
map
((
el
)
=>
el
.
row
+
'
-
'
+
el
.
col
)
setReservedSeats
(
reserve
)
}
catch
(
error
)
{
console
.
log
(
error
)
}
}
<span className="">경로우대</span>
<CountButton name="elderly" count={count} setCount={setCount} /> */
}
function
loginModal
()
{
if
(
user
)
{
history
.
push
(
"
/payment
"
,
{
...
ticketInfo
,
selectedSeats
:
selectedSeats
,
...
count
});
}
else
{
modal
.
current
=
new
Modal
(
modalRef
.
current
)
modal
.
current
?.
show
()
}
}
<
/div
>
<
div
className
=
"
col-sm-6 mb-4 p-2 text-center
"
style
=
{{
backgroundColor
:
'
#252525
'
}}
>
<
div
>
{
ticketInfo
.
theater
}
|
{
ticketInfo
.
selectedCinemaNum
}
관
<
/div
>
<
div
>
{
ticketInfo
.
title
}
<
/div
>
<
div
>
{
ticketInfo
.
time
}
<
/div
>
return
(
<>
<
div
ref
=
{
modalRef
}
className
=
"
modal fade
"
id
=
"
staticBackdrop
"
data
-
bs
-
backdrop
=
"
static
"
data
-
bs
-
keyboard
=
"
false
"
tabindex
=
"
-1
"
aria
-
labelledby
=
"
staticBackdropLabel
"
aria
-
hidden
=
{
modal
}
>
<
div
className
=
"
modal-dialog
"
>
<
div
className
=
"
modal-content
"
>
{
}
<
div
className
=
"
modal-header
"
>
<
h5
className
=
"
modal-title
"
id
=
"
staticBackdropLabel
"
>
로그인이
필요한
서비스입니다
.
<
/h5
>
<
button
type
=
"
button
"
className
=
"
btn-close
"
data
-
bs
-
dismiss
=
"
modal
"
aria
-
label
=
"
Close
"
><
/button
>
<
/div
>
<
div
className
=
"
modal-body
"
>
로그인을
하시겠습니까
?
비회원예매로
진행하시겠습니까
?
<
/div
>
<
div
className
=
"
modal-footer
"
>
<
Link
to
=
{{
pathname
:
'
/login
'
}}
>
<
button
type
=
"
button
"
className
=
"
btn btn-secondary
"
data
-
bs
-
dismiss
=
"
modal
"
>
로그인
<
/button
>
<
/Link
>
<
Link
to
=
{{
pathname
:
`/payment`
,
state
:
{
...
ticketInfo
,
selectedSeats
:
selectedSeats
,
...
count
}
}}
>
<
button
type
=
"
button
"
className
=
"
btn btn-primary
"
data
-
bs
-
dismiss
=
"
modal
"
>
비회원예매
<
/button
>
<
/Link
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
div
className
=
"
row justify-content-center border p-5
"
>
<
div
className
=
"
col-sm-8
"
>
<
SeatTable
count
=
{
count
}
setSelectedSeats
=
{
setSelectedSeats
}
selectedSeats
=
{
selectedSeats
}
allSeat
=
{
allSeat
}
/
>
<
/
div
>
<
div
className
=
"
col-sm-4 m
t-5
"
>
<
p
>
선택
됨
<
/
p
>
<
p
>
선택불가
<
/p
>
<
div
className
=
"
container
"
style
=
{{
color
:
"
white
"
}}
>
{
console
.
log
(
ticketInfo
)}
{
console
.
log
(
reservedSeats
)}
<
div
className
=
"
row justify-content-center my-5
"
>
<
div
className
=
"
col-sm-4 m
b-3
"
>
<
h3
className
=
"
py-2 text-white text-center
"
style
=
{{
border
:
"
3px solid #000000
"
,
borderBottom
:
"
3px solid #FEDC00
"
}}
>
좌석
선택
<
/
h3
>
<
/div
>
<
/div
>
<
/div
>
<
div
className
=
"
row p-3 mt-5
"
style
=
{{
backgroundColor
:
"
#252525
"
}}
>
<
div
className
=
"
col-sm-3 border-end text-center
"
>
{
ticketInfo
?
<
img
style
=
{{
maxHeight
:
"
10rem
"
}}
src
=
{
`https://image.tmdb.org/t/p/original
${
ticketInfo
.
poster_path
}
`
}
alt
=
"
영화포스터
"
/>
:
<
div
className
=
"
mb-2
"
style
=
{{
color
:
"
white
"
}}
>
영화선택
<
/div>
}
<
div
className
=
"
row justify-content-center my-3
"
>
<
div
className
=
"
col-sm-6 mb-4 text-center
"
>
<
div
className
=
"
row
"
>
<
div
className
=
"
col-sm-6 text-end
"
>
<
div
className
=
"
my-1
"
>
일반
<
/div
>
<
div
className
=
"
my-1
"
>
청소년
<
/div
>
<
div
className
=
"
my-1
"
>
경로우대
<
/div
>
<
/div
>
<
div
className
=
"
col-sm-6 text-start
"
>
<
CountButton
name
=
"
adult
"
count
=
{
count
}
setCount
=
{
setCount
}
/
>
<
CountButton
name
=
"
teenager
"
count
=
{
count
}
setCount
=
{
setCount
}
/
>
<
CountButton
name
=
"
elderly
"
count
=
{
count
}
setCount
=
{
setCount
}
/
>
<
/div
>
<
/div
>
<
/div
>
<
div
className
=
"
col-sm-6 mb-4 p-2 text-center
"
style
=
{{
backgroundColor
:
'
#252525
'
}}
>
<
div
>
{
ticketInfo
.
cinema
}
|
{
ticketInfo
.
selectedTheater
}
관
<
/div
>
<
div
>
{
ticketInfo
.
title
}
<
/div
>
<
div
>
{
ticketInfo
.
time
}
<
/div
>
<
/div
>
<
/div
>
<
div
className
=
"
col-sm-6 border-end
"
style
=
{{
color
:
"
white
"
}}
>
<
div
className
=
"
mb-2 text-center
"
>
극장선택
<
/div
>
{
ticketInfo
?
<
ul
>
<
li
>
영화
:
{
ticketInfo
.
title
}
<
/li
>
<
li
>
극장
:
{
ticketInfo
.
theater
}
<
/li
>
<
li
>
일시
:
2021
/
07
/
21
10
:
00
<
/li
>
<
li
>
상영관
:
3
관
<
/li
>
<
li
>
좌석
:
{
selectedSeats
}
<
/li
>
<
/ul
>
:
<
div
><
/div>
}
<
div
className
=
"
row justify-content-center border p-5
"
>
<
div
className
=
"
col-sm-8
"
>
<
SeatTable
count
=
{
count
}
setSelectedSeats
=
{
setSelectedSeats
}
selectedSeats
=
{
selectedSeats
}
theaterInfo
=
{
theaterInfo
}
reservedSeats
=
{
reservedSeats
}
/
>
<
/div
>
<
div
className
=
"
col-sm-4 mt-5
"
>
<
div
>
<
button
className
=
{
styles
.
on
}
style
=
{{
height
:
'
1rem
'
,
width
:
'
1rem
'
}}
disabled
><
/button
>
<
span
>
선택됨
<
/span
>
<
/div
>
<
div
>
<
button
className
=
{
styles
.
btnBlock
}
style
=
{{
height
:
'
1rem
'
,
width
:
'
1rem
'
}}
disabled
><
/button
>
<
span
>
선택불가
<
/span
>
<
/div
>
<
/div
>
<
/div
>
<
div
className
=
"
col-sm-3 text-center
"
>
<
div
className
=
"
mb-2
"
style
=
{{
color
:
"
white
"
}}
>
결제하기
<
/div
>
{
ticketInfo
?
<
Link
to
=
{{
pathname
:
`/payment`
,
state
:
{
...
ticketInfo
,
selectedSeats
:
selectedSeats
,
...
count
}
}}
>
<
img
className
=
"
border border-3 rounded-3
"
src
=
"
/images/icons8-arrow-white.png
"
alt
=
"
예매하기
"
/>
<
/Link
>
:
<
img
className
=
"
border border-3 rounded-3
"
src
=
"
/images/icons8-arrow-white.png
"
alt
=
"
예매하기
"
/>
<
div
className
=
"
row p-3 mt-5
"
style
=
{{
backgroundColor
:
"
#252525
"
}}
>
<
div
className
=
"
col-sm-3 border-end text-center
"
>
{
ticketInfo
?
<
img
style
=
{{
maxHeight
:
"
10rem
"
}}
src
=
{
`https://image.tmdb.org/t/p/original
${
ticketInfo
.
poster_path
}
`
}
alt
=
"
영화포스터
"
/>
:
<
div
className
=
"
mb-2
"
style
=
{{
color
:
"
white
"
}}
>
영화선택
<
/div>
}
<
/div
>
<
div
className
=
"
col-sm-6 border-end
"
style
=
{{
color
:
"
white
"
}}
>
<
div
className
=
"
mb-2 text-center
"
>
극장선택
<
/div
>
{
ticketInfo
?
<
ul
>
<
li
>
영화
:
{
ticketInfo
.
title
}
<
/li
>
<
li
>
극장
:
{
ticketInfo
.
cinema
}
<
/li
>
<
li
>
일시
:
2021
/
07
/
21
10
:
00
<
/li
>
<
li
>
상영관
:
3
관
<
/li
>
<
li
>
좌석
:
{
selectedSeats
}
<
/li
>
<
/ul
>
:
<
div
><
/div>
}
<
/div
>
<
div
className
=
"
col-sm-3 text-center
"
>
<
div
className
=
"
mb-2
"
style
=
{{
color
:
"
white
"
}}
>
결제하기
<
/div
>
{
ticketInfo
?
<
button
onClick
=
{
loginModal
}
style
=
{{
backgroundColor
:
'
#252525
'
,
border
:
0
}}
>
<
img
className
=
"
border border-3 rounded-3
"
src
=
"
/images/icons8-arrow-white.png
"
alt
=
"
결제하기
"
/>
<
/button
>
:
<
button
disabled
>
<
img
className
=
"
border border-3 rounded-3
"
src
=
"
/images/icons8-arrow-white.png
"
alt
=
"
결제하기
"
/>
<
/button
>
}
}
<
/div
>
<
/div
>
<
/div
>
<
/
div
>
<
/
>
)
}
...
...
package-lock.json
View file @
d837894e
...
...
@@ -39,29 +39,6 @@
"negotiator"
:
"0.6.2"
}
},
"agent-base"
:
{
"version"
:
"6.0.2"
,
"resolved"
:
"https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
,
"integrity"
:
"sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="
,
"requires"
:
{
"debug"
:
"4"
},
"dependencies"
:
{
"debug"
:
{
"version"
:
"4.3.2"
,
"resolved"
:
"https://registry.npmjs.org/debug/-/debug-4.3.2.tgz"
,
"integrity"
:
"sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw=="
,
"requires"
:
{
"ms"
:
"2.1.2"
}
},
"ms"
:
{
"version"
:
"2.1.2"
,
"resolved"
:
"https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
,
"integrity"
:
"sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"ansi-align"
:
{
"version"
:
"3.0.0"
,
"resolved"
:
"https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz"
,
...
...
@@ -124,11 +101,6 @@
"resolved"
:
"https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz"
,
"integrity"
:
"sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"asap"
:
{
"version"
:
"2.0.6"
,
"resolved"
:
"https://registry.npmjs.org/asap/-/asap-2.0.6.tgz"
,
"integrity"
:
"sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"axios"
:
{
"version"
:
"0.21.1"
,
"resolved"
:
"https://registry.npmjs.org/axios/-/axios-0.21.1.tgz"
,
...
...
@@ -267,15 +239,6 @@
}
}
},
"call-bind"
:
{
"version"
:
"1.0.2"
,
"resolved"
:
"https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz"
,
"integrity"
:
"sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA=="
,
"requires"
:
{
"function-bind"
:
"^1.1.1"
,
"get-intrinsic"
:
"^1.0.2"
}
},
"camelcase"
:
{
"version"
:
"5.3.1"
,
"resolved"
:
"https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz"
,
...
...
@@ -464,11 +427,6 @@
"integrity"
:
"sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="
,
"dev"
:
true
},
"dayjs"
:
{
"version"
:
"1.10.6"
,
"resolved"
:
"https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz"
,
"integrity"
:
"sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw=="
},
"debug"
:
{
"version"
:
"2.6.9"
,
"resolved"
:
"https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
,
...
...
@@ -673,21 +631,6 @@
"dev"
:
true
,
"optional"
:
true
},
"function-bind"
:
{
"version"
:
"1.1.1"
,
"resolved"
:
"https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
,
"integrity"
:
"sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"get-intrinsic"
:
{
"version"
:
"1.1.1"
,
"resolved"
:
"https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz"
,
"integrity"
:
"sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q=="
,
"requires"
:
{
"function-bind"
:
"^1.1.1"
,
"has"
:
"^1.0.3"
,
"has-symbols"
:
"^1.0.1"
}
},
"get-stream"
:
{
"version"
:
"4.1.0"
,
"resolved"
:
"https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz"
,
...
...
@@ -740,25 +683,12 @@
"integrity"
:
"sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
,
"dev"
:
true
},
"has"
:
{
"version"
:
"1.0.3"
,
"resolved"
:
"https://registry.npmjs.org/has/-/has-1.0.3.tgz"
,
"integrity"
:
"sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw=="
,
"requires"
:
{
"function-bind"
:
"^1.1.1"
}
},
"has-flag"
:
{
"version"
:
"3.0.0"
,
"resolved"
:
"https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
,
"integrity"
:
"sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
,
"dev"
:
true
},
"has-symbols"
:
{
"version"
:
"1.0.2"
,
"resolved"
:
"https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz"
,
"integrity"
:
"sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
},
"has-yarn"
:
{
"version"
:
"2.1.0"
,
"resolved"
:
"https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz"
,
...
...
@@ -783,30 +713,6 @@
"toidentifier"
:
"1.0.0"
}
},
"https-proxy-agent"
:
{
"version"
:
"5.0.0"
,
"resolved"
:
"https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz"
,
"integrity"
:
"sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA=="
,
"requires"
:
{
"agent-base"
:
"6"
,
"debug"
:
"4"
},
"dependencies"
:
{
"debug"
:
{
"version"
:
"4.3.2"
,
"resolved"
:
"https://registry.npmjs.org/debug/-/debug-4.3.2.tgz"
,
"integrity"
:
"sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw=="
,
"requires"
:
{
"ms"
:
"2.1.2"
}
},
"ms"
:
{
"version"
:
"2.1.2"
,
"resolved"
:
"https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
,
"integrity"
:
"sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"iconv-lite"
:
{
"version"
:
"0.4.24"
,
"resolved"
:
"https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
,
...
...
@@ -1247,11 +1153,6 @@
"resolved"
:
"https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
,
"integrity"
:
"sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-inspect"
:
{
"version"
:
"1.11.0"
,
"resolved"
:
"https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz"
,
"integrity"
:
"sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
},
"on-finished"
:
{
"version"
:
"2.3.0"
,
"resolved"
:
"https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz"
,
...
...
@@ -1378,11 +1279,6 @@
"integrity"
:
"sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
,
"dev"
:
true
},
"pop-iterate"
:
{
"version"
:
"1.0.1"
,
"resolved"
:
"https://registry.npmjs.org/pop-iterate/-/pop-iterate-1.0.1.tgz"
,
"integrity"
:
"sha1-zqz9q0q/NT16DyqqLB/Hs/lBO6M="
},
"postgres-array"
:
{
"version"
:
"2.0.0"
,
"resolved"
:
"https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz"
,
...
...
@@ -1451,26 +1347,11 @@
"escape-goat"
:
"^2.0.0"
}
},
"q"
:
{
"version"
:
"2.0.3"
,
"resolved"
:
"https://registry.npmjs.org/q/-/q-2.0.3.tgz"
,
"integrity"
:
"sha1-dbjbAlWhpa+C9Yw/Oqoe/sfQ0TQ="
,
"requires"
:
{
"asap"
:
"^2.0.0"
,
"pop-iterate"
:
"^1.0.1"
,
"weak-map"
:
"^1.0.5"
}
},
"qs"
:
{
"version"
:
"6.7.0"
,
"resolved"
:
"https://registry.npmjs.org/qs/-/qs-6.7.0.tgz"
,
"integrity"
:
"sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"querystringify"
:
{
"version"
:
"2.2.0"
,
"resolved"
:
"https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz"
,
"integrity"
:
"sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
},
"range-parser"
:
{
"version"
:
"1.2.1"
,
"resolved"
:
"https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz"
,
...
...
@@ -1537,11 +1418,6 @@
"rc"
:
"^1.2.8"
}
},
"requires-port"
:
{
"version"
:
"1.0.0"
,
"resolved"
:
"https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz"
,
"integrity"
:
"sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
},
"responselike"
:
{
"version"
:
"1.0.2"
,
"resolved"
:
"https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz"
,
...
...
@@ -1559,11 +1435,6 @@
"any-promise"
:
"^1.3.0"
}
},
"rootpath"
:
{
"version"
:
"0.1.2"
,
"resolved"
:
"https://registry.npmjs.org/rootpath/-/rootpath-0.1.2.tgz"
,
"integrity"
:
"sha1-Wzeah9ypBum5HWkKWZQ5vvJn6ms="
},
"safe-buffer"
:
{
"version"
:
"5.1.2"
,
"resolved"
:
"https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
,
...
...
@@ -1574,11 +1445,6 @@
"resolved"
:
"https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
,
"integrity"
:
"sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"scmp"
:
{
"version"
:
"2.1.0"
,
"resolved"
:
"https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz"
,
"integrity"
:
"sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q=="
},
"semver"
:
{
"version"
:
"5.7.1"
,
"resolved"
:
"https://registry.npmjs.org/semver/-/semver-5.7.1.tgz"
,
...
...
@@ -1692,16 +1558,6 @@
"resolved"
:
"https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz"
,
"integrity"
:
"sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
},
"side-channel"
:
{
"version"
:
"1.0.4"
,
"resolved"
:
"https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz"
,
"integrity"
:
"sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw=="
,
"requires"
:
{
"call-bind"
:
"^1.0.0"
,
"get-intrinsic"
:
"^1.0.2"
,
"object-inspect"
:
"^1.9.0"
}
},
"signal-exit"
:
{
"version"
:
"3.0.3"
,
"resolved"
:
"https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz"
,
...
...
@@ -1860,34 +1716,6 @@
"nopt"
:
"~1.0.10"
}
},
"twilio"
:
{
"version"
:
"3.66.0"
,
"resolved"
:
"https://registry.npmjs.org/twilio/-/twilio-3.66.0.tgz"
,
"integrity"
:
"sha512-2jek7akXcRMusoR20EWA1+e5TQp9Ahosvo81wTUoeS7H24A1xbVQJV4LfSWQN4DLUY1oZ4d6tH2oCe/+ELcpNA=="
,
"requires"
:
{
"axios"
:
"^0.21.1"
,
"dayjs"
:
"^1.8.29"
,
"https-proxy-agent"
:
"^5.0.0"
,
"jsonwebtoken"
:
"^8.5.1"
,
"lodash"
:
"^4.17.21"
,
"q"
:
"2.0.x"
,
"qs"
:
"^6.9.4"
,
"rootpath"
:
"^0.1.2"
,
"scmp"
:
"^2.1.0"
,
"url-parse"
:
"^1.5.0"
,
"xmlbuilder"
:
"^13.0.2"
},
"dependencies"
:
{
"qs"
:
{
"version"
:
"6.10.1"
,
"resolved"
:
"https://registry.npmjs.org/qs/-/qs-6.10.1.tgz"
,
"integrity"
:
"sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg=="
,
"requires"
:
{
"side-channel"
:
"^1.0.4"
}
}
}
},
"type-fest"
:
{
"version"
:
"0.8.1"
,
"resolved"
:
"https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz"
,
...
...
@@ -1966,15 +1794,6 @@
"xdg-basedir"
:
"^4.0.0"
}
},
"url-parse"
:
{
"version"
:
"1.5.3"
,
"resolved"
:
"https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz"
,
"integrity"
:
"sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ=="
,
"requires"
:
{
"querystringify"
:
"^2.1.1"
,
"requires-port"
:
"^1.0.0"
}
},
"url-parse-lax"
:
{
"version"
:
"3.0.0"
,
"resolved"
:
"https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz"
,
...
...
@@ -2009,11 +1828,6 @@
"resolved"
:
"https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
,
"integrity"
:
"sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"weak-map"
:
{
"version"
:
"1.0.5"
,
"resolved"
:
"https://registry.npmjs.org/weak-map/-/weak-map-1.0.5.tgz"
,
"integrity"
:
"sha1-eWkVhNmGB/UHC9O3CkDmuyLkAes="
},
"widest-line"
:
{
"version"
:
"3.1.0"
,
"resolved"
:
"https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz"
,
...
...
@@ -2055,11 +1869,6 @@
"integrity"
:
"sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q=="
,
"dev"
:
true
},
"xmlbuilder"
:
{
"version"
:
"13.0.2"
,
"resolved"
:
"https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz"
,
"integrity"
:
"sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ=="
},
"xtend"
:
{
"version"
:
"4.0.2"
,
"resolved"
:
"https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz"
,
...
...
package.json
View file @
d837894e
...
...
@@ -26,8 +26,7 @@
"
nodemailer
"
:
"
^6.6.3
"
,
"
pg
"
:
"
^8.6.0
"
,
"
pg-hstore
"
:
"
^2.3.4
"
,
"
sequelize
"
:
"
^6.6.4
"
,
"
twilio
"
:
"
^3.66.0
"
"
sequelize
"
:
"
^6.6.4
"
},
"devDependencies"
:
{
"
nodemon
"
:
"
^2.0.12
"
...
...
server/controllers/cinema.controller.js
View file @
d837894e
...
...
@@ -6,6 +6,7 @@ const getAll = async (req, res) => {
where
:
{
id
:
1
},
attributes
:
[
'
cinemaName
'
,
'
transportation
'
,
'
parking
'
,
'
address
'
,
'
moreFeeInfo
'
]
})
console
.
log
(
"
INfo====
"
,
info
)
return
res
.
json
(
info
)
}
catch
(
error
)
{
return
res
.
status
(
500
).
send
(
error
.
message
||
"
영화관 정보 가져오는 중 에러 발생
"
)
...
...
server/controllers/email.controller.js
View file @
d837894e
import
nodemailer
from
"
nodemailer
"
const
SendMail
=
async
(
req
,
res
)
=>
{
// console.log(req.body)
const
{
email
}
=
req
.
body
console
.
log
(
email
)
const
sendMail
=
async
(
email
)
=>
{
const
{
email
,
title
,
cinema
,
selectedTheater
,
time
,
nickname
}
=
req
.
body
const
selectedSeats
=
req
.
body
.
selectedSeats
const
sendMail
=
async
(
email
,
title
,
cinema
,
selectedTheater
,
time
,
nickname
,
selectedSeats
)
=>
{
// 메일을 전달해줄 객체
const
transporter
=
nodemailer
.
createTransport
({
// service: "gmail",
host
:
'
smtp.gmail.com
'
,
port
:
465
,
secure
:
true
,
...
...
@@ -16,7 +14,6 @@ const SendMail = async (req,res) => {
user
:
"
angelayoon99@gmail.com
"
,
clientId
:
process
.
env
.
GMAIL_CLIENTID
,
clientSecret
:
process
.
env
.
GMAIL_CLIENTSECRET
,
accessToken
:
process
.
env
.
GMAIL_ACCESS_TOKEN
,
refreshToken
:
process
.
env
.
GMAIL_REFRESH_TOKEN
,
},
tls
:
{
...
...
@@ -26,10 +23,10 @@ const SendMail = async (req,res) => {
// 메일 옵션
const
mailOptions
=
{
from
:
`
윤지원
<angelayoon99@gmail.com>`
,
to
:
"
jiwon5393@naver.com
"
,
subject
:
"
사용자 계정 확인용 메일.
"
,
text
:
"
Test Mail from Test Server.
"
,
from
:
`
${
cinema
}
<angelayoon99@gmail.com>`
,
to
:
`
${
email
}
`
,
subject
:
`
${
cinema
}
예매확인내역:
${
title
}
`
,
text
:
`
${
nickname
}
님의 예매:
${
title
}
/
${
cinema
}
/
${
selectedTheater
}
관 / 일시:
${
time
}
/
${
selectedSeats
}
/`
,
};
// 메일 전송
...
...
@@ -42,7 +39,7 @@ const SendMail = async (req,res) => {
}
}
sendMail
(
email
);
sendMail
(
email
,
title
,
cinema
,
selectedTheater
,
time
,
nickname
,
selectedSeats
);
}
...
...
server/controllers/reservation.controller.js
0 → 100644
View file @
d837894e
import
axios
from
'
axios
'
import
{
Reservation
,
Theater
}
from
'
../db/index.js
'
import
sequelize
from
'
sequelize
'
const
{
Op
}
=
sequelize
const
findReservation
=
async
(
req
,
res
)
=>
{
const
{
timetable
}
=
req
.
body
try
{
const
reservedSeats
=
await
Reservation
.
findAll
({
where
:
{
timetable
:
timetable
}
})
console
.
log
(
reservedSeats
)
res
.
json
(
reservedSeats
)
}
catch
(
error
)
{
return
res
.
status
(
500
).
send
(
error
.
message
||
"
이미 예매되어있는 좌석을 찾는 중 오류발생
"
)
}
}
export
default
{
findReservation
}
\ No newline at end of file
server/controllers/theater.controller.js
0 → 100644
View file @
d837894e
import
{
Theater
}
from
"
../db/index.js
"
;
const
getTheaterInfo
=
async
(
req
,
res
)
=>
{
const
{
theaterNum
}
=
req
.
body
try
{
const
theaterInfo
=
await
Theater
.
findOne
({
where
:
{
theaterNum
:
theaterNum
},
attributes
:
[
'
theaterNum
'
,
'
rows
'
,
'
columns
'
,
'
theaterType
'
]
})
// console.log("theaterInfo====",theaterInfo)
return
res
.
json
(
theaterInfo
)
}
catch
(
error
)
{
return
res
.
status
(
500
).
send
(
error
.
message
||
"
상영관 정보 가져오는 중 에러 발생
"
)
}
}
export
default
{
getTheaterInfo
}
\ No newline at end of file
server/controllers/user.controller.js
View file @
d837894e
import
jwt
from
"
jsonwebtoken
"
;
import
config
from
"
../config/app.config.js
"
;
import
{
User
,
Role
}
from
'
../db/index.js
'
;
import
Twilio
from
"
twilio
"
;
//
import Twilio from "twilio";
const
login
=
async
(
req
,
res
)
=>
{
try
{
...
...
@@ -73,21 +73,21 @@ const compareId = async (req, res) => {
}
const
confirmMbnum
=
async
(
req
,
res
)
=>
{
const
id
=
req
.
params
.
id
;
const
token
=
req
.
params
.
token
;
//
const id = req.params.id;
//
const token = req.params.token;
const
client
=
Twilio
(
id
,
token
);
// console.log(client);
client
.
messages
.
create
({
to
:
'
+8201086074580
'
,
from
:
'
+14159428621
'
,
body
:
'
[ButterStudio] 인증번호[1234]를 입력해주세요
'
,
})
.
then
(
message
=>
console
.
log
(
message
.
sid
))
.
catch
(
e
=>
console
.
log
(
error
));
// console.log("id = ", id, "token = ", token);
return
res
.
json
(
true
);
// //
const client = Twilio(id, token);
//
//
console.log(client);
//
client.messages
//
.create({
//
to: '+8201086074580',
//
from: '+14159428621',
//
body: '[ButterStudio] 인증번호[1234]를 입력해주세요',
//
})
//
.then(message => console.log(message.sid))
//
.catch(e => console.log(error));
//
//
console.log("id = ", id, "token = ", token);
//
return res.json(true);
}
const
signup
=
async
(
req
,
res
)
=>
{
...
...
@@ -130,11 +130,26 @@ const getNickName = async (req, res) => {
}
}
const
getUserInfo
=
async
(
req
,
res
)
=>
{
const
{
id
}
=
req
.
body
console
.
log
(
id
)
try
{
const
userInfo
=
await
User
.
findOne
({
where
:{
id
:
id
},
attributes
:[
"
userId
"
,
"
email
"
,
"
nickname
"
,
"
birth
"
,
"
phoneNumber
"
]
})
res
.
json
(
userInfo
)
}
catch
(
error
)
{
console
.
log
(
error
)
}
}
export
default
{
login
,
logout
,
compareId
,
confirmMbnum
,
signup
,
getNickName
getNickName
,
getUserInfo
}
server/index.js
View file @
d837894e
...
...
@@ -19,8 +19,8 @@ sequelize
);
const
adminRole
=
await
Role
.
findOne
({
where
:
{
name
:
"
admin
"
}
});
console
.
log
(
"
adminRole :
"
,
adminRole
);
//
if (!adminRole) {
//
console.log("adminRole : ", adminRole);
if
(
!
adminRole
)
{
await
User
.
create
({
userId
:
"
admin
"
,
email
:
"
han35799@naver.com
"
,
...
...
@@ -30,7 +30,7 @@ sequelize
password
:
"
admin!
"
,
roleId
:
adminRole
?.
id
,
});
// }else{
}
}
app
.
listen
(
appConfig
.
port
,
()
=>
{
console
.
log
(
`Server is running on port
${
appConfig
.
port
}
`
);
...
...
server/models/reservation.model.js
View file @
d837894e
...
...
@@ -18,7 +18,7 @@ const ReservationModel = (sequelize) => {
type
:
DataTypes
.
INTEGER
,
},
row
:
{
type
:
DataTypes
.
STRING
,
type
:
DataTypes
.
INTEGER
,
},
col
:
{
type
:
DataTypes
.
INTEGER
,
...
...
server/models/theater.model.js
View file @
d837894e
...
...
@@ -11,7 +11,7 @@ const TheaterModel = (sequelize) => {
primaryKey
:
true
,
},
rows
:
{
type
:
DataTypes
.
STRING
,
type
:
DataTypes
.
INTEGER
,
},
columns
:
{
type
:
DataTypes
.
INTEGER
,
...
...
server/routes/index.js
View file @
d837894e
...
...
@@ -4,6 +4,8 @@ import movieRouter from './movie.route.js'
import
cinemaRouter
from
"
./cinema.route.js
"
;
import
kakaopayRouter
from
"
./kakaopay.route.js
"
;
import
emailRouter
from
'
./email.route.js
'
import
theaterRouter
from
'
./theater.route.js
'
import
reservationRouter
from
'
./reservation.route.js
'
const
router
=
express
.
Router
();
...
...
@@ -12,5 +14,7 @@ router.use('/auth', userRouter)
router
.
use
(
'
/kakaopay
'
,
kakaopayRouter
)
router
.
use
(
'
/email
'
,
emailRouter
)
router
.
use
(
'
/info
'
,
cinemaRouter
)
router
.
use
(
'
/theater
'
,
theaterRouter
)
router
.
use
(
'
/reservation
'
,
reservationRouter
)
export
default
router
;
\ No newline at end of file
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