Commit ba5429cf authored by Kim, Subin's avatar Kim, Subin
Browse files

master 병합

parent c465b924
import { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import movieApi from '../apis/movie.api.js'
import Video from '../components/Video.js'
import Video from '../components/Video.js';
import movieApi from '../apis/movie.api.js';
import catchErrors from "../utils/catchErrors.js";
const MoviePage = ({ location }) => {
const [movieInfo, setMovieInfo] = useState({
...location.state,
stillCuts: [],
cast: "",
director: "",
// genres: [],
attendance: ""
cast: [],
director: []
})
const [state, setState] = useState(0)
const [error, setError] = useState("")
useEffect(() => {
getImagesAndCredits()
......@@ -24,32 +24,20 @@ const MoviePage = ({ location }) => {
const still = images.backdrops.map(el => el.file_path)
const credits = await movieApi.getCreditsfromTM(movieInfo.id)
const castsInfo = credits.cast.map(el => el.name)
const casts = castsInfo.reduce((acc, cur, idx) => {
if (idx !== 0) return acc + ', ' + cur
else return acc + cur
}, "")
console.log(castsInfo)
const directorsInfo = await credits.crew.filter(element => element.job === "Director")
const directors = directorsInfo.reduce((acc, cur, idx) => {
if (idx !== 0) return acc + ', ' + cur.name
else return acc + cur.name
}, "")
console.log("directorInfo=", directorsInfo)
const directorsInfo = await credits.crew.filter(element => element.job === "Director").map(el => el.name)
setMovieInfo({
...movieInfo,
stillCuts: still,
cast: casts,
director: directors
cast: castsInfo,
director: directorsInfo
})
} catch (error) {
console.log(error)
catchErrors(error, setError)
}
}
return (
<div className="container" style={{ backgroundColor: "black" }}>
{console.log(movieInfo)}
<div id="carouselExampleInterval" className="carousel slide py-4" data-bs-ride="carousel">
<div className="carousel-inner">
{movieInfo.stillCuts.length > 0
......@@ -76,11 +64,18 @@ const MoviePage = ({ location }) => {
<div className="col-sm-3 mb-5">
<img className="img-thumbnail" src={`https://image.tmdb.org/t/p/original${movieInfo.poster_path}`} alt="영화포스터" />
</div>
<div className="col-sm-6 " style={{ color: "white" }}>
<div className="col-sm-6" style={{ color: "white" }}>
<h1 className="pb-3">{movieInfo.title}</h1>
<p>예매율: 0% 누적관객수: {movieInfo.attendance}</p>
<p>감독: {movieInfo.director}</p>
<p>출연: {movieInfo.cast}</p>
<p>예매율:{Math.round((movieInfo.ticket_sales / (movieInfo.totalReservationRate.totalReservationRate || 1)) * 100)}% 누적관객수: {movieInfo.ticket_sales}</p>
{movieInfo.director || movieInfo.cast
?
<>
<p>감독: {movieInfo.director.map(el => el) + ' '}</p>
<p>출연: {movieInfo.cast.slice(0, 5).map(el => el) + ' '}</p>
</>
:
<></>
}
<p>장르: {movieInfo.genres.reduce((acc, cur, idx) => {
if (idx !== 0) return acc + ', ' + cur.name
else return acc + cur.name
......@@ -98,7 +93,7 @@ const MoviePage = ({ location }) => {
</div>
</div>
</div>
<div className="">
<div>
<ul className="nav nav-tabs justify-content-center mt-4 border-0" id="myTab" role="tablist">
<li className="nav-item" role="presentation">
<button className="nav-link active mx-auto" style={{ color: "white", borderColor: "black", backgroundColor: "black", borderBottom: state === 0 ? "3px solid" : "none", borderBottomColor: state === 0 ? "#FEDC00" : "black" }} id="overview-tab" data-bs-toggle="tab" data-bs-target="#overview" type="button" role="tab" aria-controls="overview" aria-selected="true" onClick={() => setState(0)}>상세정보</button>
......@@ -113,13 +108,13 @@ const MoviePage = ({ location }) => {
</div>
<div className="tab-content text-center" id="myTabContent" style={{ color: "white" }}>
<div className="tab-pane fade show active" id="overview" role="tabpanel" aria-labelledby="overview-tab">
<div>{movieInfo.overview}</div>
<div className="mt-5 pb-5 px-5">{movieInfo.overview}</div>
</div>
<div className="tab-pane fade" id="stillcut" role="tabpanel" aria-labelledby="stillcut-tab">
<Video movieId={movieInfo.id} />
</div>
<div className="tab-pane fade" id="review" role="tabpanel" aria-labelledby="review-tab">
<div>관람평</div>
<div className="mt-5 pb-5 px-5">관람평</div>
</div>
</div>
</div>
......
import MyInfo from "../components/MyInfo/MyInfo"
import ReservationDetails from "../components/ReservationDetails";
const MyPage = () => {
return (
<div className="d-flex justify-content-center py-5">
<div className="d-flex flex-column justify-content-center align-items-center py-4">
<MyInfo/>
<ReservationDetails/>
</div>
)
}
......
import axios from 'axios'
import { useEffect, useState } from 'react'
import { useAuth } from '../context/auth_context'
import catchErrors from '../utils/catchErrors'
const PaymentCompletePage = () => {
const { user } = useAuth()
const [error, setError] = useState()
useEffect(() => {
if (user.role === "member") {
getUserInfo()
} else {
getGuestInfo()
}
}, [user])
async function getGuestInfo() {
try {
if (user.id > 0) {
const response = await axios.get(`/api/auth/guestinfo/${user.id}`)
const response2 = await axios.post(`/api/reservation/findonereservation`, {
userType: "guest",
user: user.id
})
if (response.data || response2.data) {
const responseEmail = await axios.post('/api/email/send', {
reservationData: [...response2.data],
userData: { ...response.data },
cinema: "Butter Studio 조치원",
title: "더 수어사이드 스쿼드",
theater: "1",
time: "2021/07/21 10:00"
})
}
}
} catch (error) {
catchErrors(error, setError)
}
}
async function getUserInfo() {
try {
const response = await axios.post(`/api/auth/getuserinfo`, {
id: user.id
})
const response2 = await axios.post(`/api/reservation/findonereservation`, {
userType: "member",
user: user.id
})
if (response.data || response2.data) {
const responseEmail = await axios.post('/api/email/send', {
...response2.data,
...response.data,
})
}
} catch (error) {
catchErrors(error, setError)
}
}
return (
<div className="text-center">
<h3>예매가 정상적으로 완료되었습니다.</h3>
<button>홈으로</button>
{user.role === "member" ? <button>마이페이지</button> : <></>}
</div>
)
}
export default PaymentCompletePage
\ No newline at end of file
import axios from 'axios'
import { useState } from 'react'
import Kakaopay from '../components/Kakaopay'
const Payment = ({ location }) => {
const [ticketInfo, setTicketInfo] = useState({ ...location.state })
async function SendMail(e) {
try {
const response = await axios.post('/api/email/send',{
email:e.target.name
})
console.log(response.data)
} catch (error) {
console.log(error)
}
}
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">
<div className="col-sm-8 text-center">
<h5 className="mb-3">결제방법</h5>
<img src="/images/naverpay_button.png" />
<Kakaopay ticketInfo={ticketInfo} setTicketInfo={setTicketInfo} />
</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.time}</div>
<div className="mb-3">{ticketInfo.selectedCinemaNum} {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>
</div>
</div>
<div>
<button type="button" name="jiwon5393@naver.com" onClick={SendMail}>메일발송</button>
</div>
</div>
)
}
export default Payment
\ No newline at end of file
import axios from 'axios'
import { useEffect, useState } from 'react'
import { useAuth } from '../../context/auth_context'
import catchErrors from '../../utils/catchErrors'
import styles from './PaymentPage.module.scss'
const Payment = ({ location }) => {
const { user } = useAuth()
const [guestInfo, setGuestInfo] = useState({})
const [guestID, setGuestID] = useState()
const [userInfo, setUserInfo] = useState({
nickname: "",
email: "",
birth: "",
phoneNumber: ""
})
const [ticketInfo, setTicketInfo] = useState({ ...location.state })
const [element, setElement] = useState()
const [error, setError] = useState("")
useEffect(() => {
if (user.role === "member") {
getUserInfo()
}
}, [])
async function getUserInfo() {
try {
setError("")
const response = await axios.post(`/api/auth/getuserinfo`, {
id: user.id
})
setUserInfo(response.data)
} catch (error) {
catchErrors(error, setError)
}
}
function handleChangeGuest(e) {
setGuestInfo({ ...guestInfo, [e.target.name]: String(e.target.value) })
}
async function handleClickGuest() {
try {
setError("")
const response = await axios.post('/api/auth/guest/save', {
...guestInfo
})
setGuestID(response.data.id)
alert("비회원 정보가 저장되었습니다.")
} catch (error) {
catchErrors(error, setError)
}
}
function kakaoBtnClick() {
setElement(
<div className="text-center">
<p className=" font-weight-bold" style={{ display: 'inline', color: "#FEDC00" }}>'카카오페이'</p><p style={{ display: 'inline' }}>를 선택하셨습니다. </p>
<p>결제하기를 눌러 결제를 이어가주세요.</p>
</div>
)
setTicketInfo({ ...ticketInfo, payment: "카카오페이" })
}
async function reservationComplete() {
try {
setError("")
if (user.role === "member") {
const response = await axios.post(`/api/reservation/save`, {
userType: "member",
user: userInfo.id,
...ticketInfo,
timetable: 1
})
const responsekakao = await axios.post('/api/kakaopay/test/single', {
cid: 'TC0ONETIME',
partner_order_id: 'orderNum',
partner_user_id: userInfo.id || guestInfo.id,
item_name: ticketInfo.title,
quantity: ticketInfo.adult + ticketInfo.youth + ticketInfo.senior,
total_amount: ticketInfo.totalFee,
vat_amount: 0,
tax_free_amount: 0,
approval_url: 'http://localhost:3000/paymentcomplete',
fail_url: 'http://localhost:3000/ticket',
cancel_url: 'http://localhost:3000/ticket',
})
if (response && responsekakao) {
window.location.href = responsekakao.data.redirect_url
}
} else {
if (guestID) {
const response = await axios.post(`/api/reservation/save`, {
userType: "guest",
user: guestID,
...ticketInfo,
timetable: 1
})
const responsekakao = await axios.post('/api/kakaopay/test/single', {
cid: 'TC0ONETIME',
partner_order_id: 'orderNum',
partner_user_id: 'user',
item_name: ticketInfo.title,
quantity: ticketInfo.adult + ticketInfo.youth + ticketInfo.senior,
total_amount: ticketInfo.totalFee,
vat_amount: 0,
tax_free_amount: 0,
approval_url: 'http://localhost:3000/paymentcomplete',
fail_url: 'http://localhost:3000/ticket',
cancel_url: 'http://localhost:3000/ticket',
})
if (response && responsekakao) {
window.location.href = responsekakao.data.redirect_url
}
} else {
alert("비회원 정보를 모두 입력 후 비회원 정보 저장 버튼을 눌러주세요.")
}
}
} catch (error) {
catchErrors(error, setError)
}
}
return (
<div className="container" style={{ color: "white" }}>
<div className="row justify-content-center my-5">
<div className="col-sm-4 ">
<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">
<div className="col-sm-8 text-center">
{user.role === "member"
?
<div>
<h5 className="mb-4 p-2" style={{ backgroundColor: "white", color: "black" }}>회원정보</h5>
<div className="my-1">
<label className={styles.labelStyle}>이름</label>
<input type="text" name="name" placeholder="이름" value={userInfo.nickname} />
</div>
<div className="my-1">
<label className={styles.labelStyle}>이메일</label>
<input type="email" name="email" placeholder="이메일" value={userInfo.email} />
</div>
<div className="my-1">
<label className={styles.labelStyle}>생년월일</label>
<input type="number" name="birth" placeholder="생년월일" maxLength="6" value={userInfo.birth} />
</div>
<div className="my-1">
<label className={styles.labelStyle}>휴대폰 번호</label>
<input type="number" name="phoneNumber" placeholder="휴대폰 번호" maxLength="11" value={userInfo.phoneNumber} />
</div>
<div className="m-2">
<p className={`text-muted ${styles.warningText}`}>
회원정보 변경은 마이페이지에서 가능합니다.
</p>
</div>
</div>
:
<div>
<h5 className="mb-4 p-2" style={{ backgroundColor: "white", color: "black" }}>비회원예매 정보입력</h5>
<div className="my-1">
<label className={styles.labelStyle}>이름</label>
<input type="text" name="name" placeholder="이름" onChange={handleChangeGuest} required />
</div>
<div className="my-1">
<label className={styles.labelStyle}>이메일</label>
<input type="email" name="email" placeholder="이메일" onChange={handleChangeGuest} required />
</div>
<div className="my-1">
<label className={styles.labelStyle}>생년월일</label>
<input type="number" name="birth" placeholder="생년월일" onChange={handleChangeGuest} maxLength="6" required />
</div>
<div className="my-1">
<label className={styles.labelStyle}>휴대폰 번호</label>
<input type="number" name="phoneNumber" placeholder="휴대폰 번호" onChange={handleChangeGuest} maxLength="11" required />
</div>
<div className="my-1">
<label className={styles.labelStyle}>비밀번호</label>
<input type="password" name="guestPassword" placeholder="비밀번호" onChange={handleChangeGuest} required style={{ width: "178px" }} />
</div>
<div className="m-2">
<p className={`text-muted ${styles.warningText}`}>
비회원 정보 오기입 예매 내역 확인/취소 티켓 발권이 어려울 있으니 다시 한번 확인해 주시기 바랍니다.
</p>
</div>
<button className="btn btn-warning mb-3" type="button" style={{ width: "100%" }} onClick={handleClickGuest}>비회원 정보 저장</button>
</div>
}
<h5 className="my-4 p-2" style={{ backgroundColor: "white", color: "black" }}>결제방법</h5>
<img src="/images/naverpay_button.png" style={{ width: "150px" }} />
<button onClick={kakaoBtnClick} style={{ backgroundColor: "black", border: '0' }}>
<img src="/images/payment_icon_yellow_medium.png" style={{ width: "130px" }} />
</button>
{element}
<div className="my-5">
<button className="btn btn-warning" type="button" style={{ width: "100%" }} onClick={reservationComplete}>결제하기</button>
</div>
</div>
<div className="col-sm-4">
<div className="text-center rounded-3 p-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.cinema}</div>
<div>{ticketInfo.time}</div>
<div className="mb-3">{ticketInfo.selectedTheater} {ticketInfo.selectedSeats.map(el => String.fromCharCode(parseInt(el.split('-')[0]) + 65) + el.split('-')[1]) + ' '}</div>
<div className="rounded-3 p-3" style={{ backgroundColor: '#404040' }}>
<div>성인: {ticketInfo.adult}</div>
<div>청소년: {ticketInfo.youth}</div>
<div>경로우대: {ticketInfo.senior}</div>
<div className="mt-2"> 결제금액: {ticketInfo.totalFee}</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default Payment
\ No newline at end of file
.labelStyle {
display: inline-block;
width: 80px;
text-align: right;
margin-right: 1rem;
}
.warningText {
font-size: small;
}
\ No newline at end of file
export { default } from "./PaymentPage"
\ No newline at end of file
import {useState} from 'react'
import { useState } from 'react'
import TicketFeeTable from '../components/Admin/TicketFeeTable'
import TheaterInfo from '../components/TheaterInfo'
const TheaterPage = () => {
const [state, setState] = useState(0)
return (
<div>
<div className="">
<div>
<ul className="nav nav-tabs justify-content-center my-4 border-0" id="myTab" role="tablist">
<li className="nav-item" role="presentation">
<button className="nav-link active mx-auto" style={{ color: "white", borderColor: "black", backgroundColor: "black", borderBottom: state === 0 ? "3px solid" : "none", borderBottomColor: state === 0 ? "#FEDC00" : "black" }} id="overview-tab" data-bs-toggle="tab" data-bs-target="#overview" type="button" role="tab" aria-controls="overview" aria-selected="true" onClick={() => setState(0)}>극장정보</button>
......@@ -19,13 +22,17 @@ const TheaterPage = () => {
</div>
<div className="tab-content text-center" id="myTabContent" style={{ color: "white" }}>
<div className="tab-pane fade show active" id="overview" role="tabpanel" aria-labelledby="overview-tab">
<div>극장정보</div>
<TheaterInfo />
</div>
<div className="tab-pane fade" id="stillcut" role="tabpanel" aria-labelledby="stillcut-tab">
<div>상영시간표</div>
</div>
<div className="tab-pane fade" id="review" role="tabpanel" aria-labelledby="review-tab">
<div>관람료</div>
<div className="row justify-content-center">
<div className="col-sm-9 pb-5">
<TicketFeeTable />
</div>
</div>
</div>
</div>
</div>
......
import { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import movieApi from '../apis/movie.api.js'
import cinemaApi from "../apis/cinema.api.js"
import TicketingMovie from "../components/TicketingMovie/TicketingMovie.js"
import TicketingTheater from "../components/TicketingTheater/TicketingTheater.js"
import TicketingTimeTable from "../components/TicketingTimeTable/TicketingTimeTable.js"
import catchErrors from "../utils/catchErrors.js"
const TicketingPage = ({ location }) => {
const [ticketInfo, setTicketInfo] = useState({
...location.state,
theater:"",
selectedCinemaNum: 3,
cinema: "",
selectedTheater: "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()
const [error, setError] = useState("")
useEffect(() => {
getCinemaInfo()
}, [])
useEffect(() => {
getMovieInfo()
......@@ -27,30 +31,36 @@ const TicketingPage = ({ location }) => {
const data = await movieApi.getMovieInfofromTM(ticketInfo.movieId)
setMovieInfo(data)
} catch (error) {
console.log(error)
catchErrors(error, setError)
}
}
async function getCinemaInfo() {
try {
const response = await cinemaApi.getCinemaInfo()
setCinemaInfo(response.data)
} catch (error) {
catchErrors(error, setError)
}
}
return (
<div className="container" style={{ backgroundColor: "black" }}>
<div>
{console.log(ticketInfo)}
</div>
<div className="row justify-content-center my-5">
<div className="col-sm-4 mb-4 ">
<h3 className="py-2 text-white text-center" style={{ border: "3px solid #000000", borderBottom: "3px solid #FEDC00" }}>영화</h3>
<TicketingMovie ticketInfo={ticketInfo} setTicketInfo={setTicketInfo} />
</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={theaterInfo} ticketInfo={ticketInfo} setTicketInfo={setTicketInfo} />
<h3 className="py-2 text-white text-center" style={{ border: "3px solid #000000", borderBottom: "3px solid #FEDC00" }}>극장</h3>
<TicketingTheater cinemaInfo={cinemaInfo} 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={theaterInfo} />
<TicketingTimeTable ticketInfo={ticketInfo} cinemaInfo={cinemaInfo} />
</div>
</div>
<div className="row p-3" style={{ backgroundColor: "#252525"}}>
<div className="row p-3" style={{ backgroundColor: "#252525" }}>
<div className="col-sm-3 border-end text-center">
{movieInfo
? <img style={{ maxHeight: "10rem" }} src={`https://image.tmdb.org/t/p/original${movieInfo.poster_path}`} alt="영화포스터" />
......@@ -58,28 +68,26 @@ 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.selectedCinemaNum}</li>
<li>상영관: {ticketInfo.selectedTheater}</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`,
state: {...ticketInfo,...movieInfo}
state: { ...ticketInfo, ...movieInfo }
}}>
<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="예매하기" />
: <img className="border border-3 rounded-3" src="/images/icons8-arrow-white.png" alt="예매하기" />
}
</div>
</div>
......
import { Link } from 'react-router-dom'
import { useState } from 'react'
import { useState, useEffect, useRef } from 'react'
import { Link, useHistory } from 'react-router-dom'
import CountButton from '../components/CountButton'
import SeatTable from '../components/SeatTable/SeatTable'
import axios from 'axios'
import { useAuth } from '../context/auth_context.js'
import { Modal } from 'bootstrap'
import catchErrors from '../utils/catchErrors'
import styles from '../components/SeatTable/seatTable.module.scss'
const TicketingSeatPage = ({ location }) => {
const history = useHistory()
const modalRef = useRef(null)
const modal = useRef()
const { user } = useAuth()
const [error, setError] = useState()
const [ticketInfo, setTicketInfo] = useState({ ...location.state })
const [theaterInfo, setTheaterInfo] = useState({ theatertypeId: 0 })
const [selectedSeats, setSelectedSeats] = useState([])
const [reservedSeats, setReservedSeats] = useState([])
const [ticketFee, setTicketFee] = useState({
youth: 0,
adult: 0,
senior: 0
})
const [count, setCount] = useState({
youth: 0,
adult: 0,
teenager: 0,
elderly: 0
senior: 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()
}, [])
useEffect(() => {
getTicketFee()
}, [theaterInfo.theatertypeId])
<span className="">청소년</span>
<CountButton name="teenager" count={count} setCount={setCount} />
async function getInfo() {
try {
const response = await axios.post('/api/theater/getInfo', {
theaterName: ticketInfo.selectedTheater
})
setTheaterInfo(response.data)
const response2 = await axios.post('/api/reservation/findreservation', {
timetable: 1
})
const reserve = response2.data.map((el) =>
el.row + '-' + el.col
)
setReservedSeats(reserve)
} catch (error) {
catchErrors(error, setError)
}
}
<span className="">경로우대</span>
<CountButton name="elderly" count={count} setCount={setCount} /> */}
async function getTicketFee() {
try {
const response3 = await axios.get(`/api/info/ticketfee`, {
params: {
theaterTypeId: theaterInfo.theatertypeId
}
})
const basicFee = response3.data[0].day + response3.data[0].defaultPrice + response3.data[0].weekdays
setTicketFee({
adult: basicFee + response3.data[0].adult,
youth: basicFee + response3.data[0].youth,
senior: basicFee + response3.data[0].senior
})
} catch (error) {
catchErrors(error, setError)
}
}
</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>
function loginModal() {
if (user.role === "member") {
history.push("/payment", {
...ticketInfo, selectedSeats: selectedSeats, ...count, totalFee: count.adult * ticketFee.adult + count.youth * ticketFee.youth + count.senior * ticketFee.senior
});
} else {
modal.current = new Modal(modalRef.current)
modal.current?.show()
}
}
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, totalFee: count.adult * ticketFee.adult + count.youth * ticketFee.youth + count.senior * ticketFee.senior }
}}>
<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 mt-5">
<p>선택됨</p>
<p>선택불가</p>
<div className="mx-5 pb-5" style={{ color: "white" }}>
<div className="row justify-content-center my-5">
<div className="col-sm-4">
<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-4 mb-4">
<div className="row text-end justify-content-sm-end">
<div className="col-sm-6 me-5" >
<div>
<span className="my-1">일반</span>
<span>
<CountButton name="adult" count={count} setCount={setCount} />
</span>
</div>
<div>
<span className="my-1">청소년</span>
<span>
{ticketInfo.adult
?
<CountButton name="youth" count={count} setCount={setCount} disabled />
:
<CountButton name="youth" count={count} setCount={setCount} />
}
</span>
</div>
<div>
<span className="my-1">경로우대</span>
<span>
<CountButton name="senior" count={count} setCount={setCount} />
</span>
</div>
</div>
</div>
</div>
<div className="col-sm-5 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-2 mb-1 text-center">
{ticketInfo
? <img style={{ width: "6rem" }} 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-4 mb-1" style={{ color: "white" }}>
{ticketInfo
? <ul>
<li>영화: {ticketInfo.title}</li>
<li>극장: {ticketInfo.cinema}</li>
<li>일시: 2021/07/21 10:00 </li>
<li>상영관: {ticketInfo.selectedTheater}</li>
<li>좌석: {selectedSeats.map(el => String.fromCharCode(parseInt(el.split('-')[0]) + 64) + el.split('-')[1]) + ' '}</li>
</ul>
:
<div className="mb-2 text-center">극장선택</div>
}
</div>
<div className="col-sm-4 mb-1">
{selectedSeats
?
<ul>
<li>성인: {count.adult}</li>
<li>청소년: {count.youth}</li>
<li>경로: {count.senior}</li>
<li className="mt-3"> 결제금액: {count.adult * ticketFee.adult + count.youth * ticketFee.youth + count.senior * ticketFee.senior}</li>
</ul>
: <></>}
</div>
<div className="col-sm-2 text-center mb-1">
<div className="h5 mb-3">결제하기</div>
{selectedSeats.length > 0 && count.adult + count.youth + count.senior === selectedSeats.length
?
<button onClick={loginModal} style={{ backgroundColor: '#252525', border: 0 }} >
<img className="border border-3 rounded-3" src="/images/icons8-arrow-white.png" style={{ width: "70px" }} alt="결제하기" />
</button>
:
<button onClick={() => { alert("좌석을 선택해주세요.") }} style={{ backgroundColor: '#252525', border: 0 }}>
<img className="border border-3 rounded-3" src="/images/icons8-arrow-white.png" style={{ width: "70px" }} alt="결제하기" />
</button>
}
}
</div>
</div>
</div>
</div>
</>
)
}
......
import config from "./clientConfig";
import clientConfig from "./clientConfig";
export function handleLogin(user) {
if (user) {
localStorage.setItem(config.loginUser, JSON.stringify(user));
localStorage.setItem(clientConfig.loginUser, JSON.stringify(user));
}
}
export function getLocalUser() {
const userData = localStorage.getItem(config.loginUser);
const userData = localStorage.getItem(clientConfig.loginUser);
let user = null;
if (userData) {
user = JSON.parse(userData);
......
......@@ -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",
......@@ -458,17 +421,17 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"crypto-js": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
},
"crypto-random-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
"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",
......@@ -666,6 +629,11 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs": {
"version": "0.0.1-security",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
"integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ="
},
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
......@@ -673,21 +641,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 +693,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 +723,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 +1163,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 +1289,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 +1357,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 +1428,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 +1445,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 +1455,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",
......@@ -1668,6 +1544,11 @@
"requires": {
"lru-cache": "^6.0.0"
}
},
"validator": {
"version": "10.11.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz",
"integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw=="
}
}
},
......@@ -1692,16 +1573,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 +1731,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 +1809,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",
......@@ -2000,20 +1834,15 @@
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"validator": {
"version": "10.11.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz",
"integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw=="
"version": "13.6.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz",
"integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg=="
},
"vary": {
"version": "1.1.2",
"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 +1884,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",
......
......@@ -19,8 +19,10 @@
"axios": "^0.21.1",
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.5",
"crypto-js": "^4.1.1",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"fs": "0.0.1-security",
"jsonwebtoken": "^8.5.1",
"moment": "^2.29.1",
"multer": "^1.4.2",
......@@ -28,7 +30,7 @@
"pg": "^8.6.0",
"pg-hstore": "^2.3.4",
"sequelize": "^6.6.4",
"twilio": "^3.66.0"
"validator": "^13.6.0"
},
"devDependencies": {
"nodemon": "^2.0.12"
......
......@@ -7,8 +7,7 @@ const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(cookieParser())
app.use('/upload', express.static('upload'))
app.use('/api', mainRouter)
export default app
\ No newline at end of file
......@@ -4,6 +4,7 @@ const config = {
jwtSecret: 'dfkasf23i$efksdfks!',
jwtExpires: '7d',
cookieName: 'butterStudio',
cookieNameMb: 'confirmNum',
cookieMaxAge: 60 * 60 * 24 * 7 * 1000,
kakaoAdminKey: 'e3ce7106688a35e072e2630daa9d7250',
}
......
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 transporter = nodemailer.createTransport({
// service: "gmail",
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
type: "OAuth2",
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: {
rejectUnauthorized: false,
},
});
// 메일 옵션
const mailOptions = {
from: `윤지원 <angelayoon99@gmail.com>`,
to: "jiwon5393@naver.com",
subject: "사용자 계정 확인용 메일.",
text: "Test Mail from Test Server.",
};
// 메일 전송
try {
const mailResult = await transporter.sendMail(mailOptions);
console.log(`Mail sent - ID : ${mailResult.messageId}`);
} catch (err) {
console.log("Mail Sending Failuer.");
console.log(err);
}
}
sendMail(email);
}
const SendMail = async (req, res) => {
const { email, name, nickname } = req.body.userData
const { title, cinema, time, theater } = req.body
const selectedSeats = req.body.reservationData.map(el => String.fromCharCode(el.row + 64) + el.col)
const sendMail = async (email, title, cinema, theater, time, name, selectedSeats, nickname) => {
const transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
type: "OAuth2",
user: "angelayoon99@gmail.com",
clientId: process.env.GMAIL_CLIENTID,
clientSecret: process.env.GMAIL_CLIENTSECRET,
refreshToken: process.env.GMAIL_REFRESH_TOKEN,
},
tls: {
rejectUnauthorized: false,
},
});
// 메일 옵션
const mailOptions = {
from: `${cinema} <angelayoon99@gmail.com>`,
to: `${email}`,
subject: `${cinema} 예매확인내역: ${title}`,
html: `<div>
<h2>
${name || nickname}님의 예매
</h2>
<div>
영화: ${title}
</div>
<div>
장소: ${cinema} ${theater}
</div>
<div>
일시 및 좌석: ${time} / ${selectedSeats.map(el => el + ' ')}
</div>
</div>`
};
try {
const mailResult = await transporter.sendMail(mailOptions);
console.log(`Mail sent - ID : ${mailResult.messageId}`);
} catch (err) {
console.log("Mail Sending Failuer.");
console.log(err);
}
}
sendMail(email, title, cinema, theater, time, name, selectedSeats, nickname);
}
export default { SendMail }
\ No newline at end of file
......@@ -36,12 +36,10 @@ const singleTest = async (req, res) => {
},
})
const resp = response.data
console.log('resp', resp)
res.json({ redirect_url: resp.next_redirect_pc_url })
} catch (error) {
console.log(error)
}
}
export default { success, fail, cancel, singleTest }
\ No newline at end of file
......@@ -12,48 +12,6 @@ const getListfromDB = async (req, res) => {
}
}
const getMovieByCategory = async (req, res, next, category) => {
try {
const TMDBmovieIds = []
const movieIds = []
const response = await axios.get(`https://api.themoviedb.org/3/movie/${category}?api_key=${process.env.TMDB_APP_KEY}&language=ko-KR&page=1`)
const TMDBmovies = response.data.results
TMDBmovies.forEach(element => {
TMDBmovieIds.push(element.id)
})
const responseAfterCompare = await Movie.findAll({
where: {
movieId: {
[Op.or]: TMDBmovieIds
}
}
})
responseAfterCompare.forEach(el => {
movieIds.push(el.movieId)
})
req.movieIds = movieIds
next()
} catch (error) {
return res.status(500).send(error.message || "영화 가져오기 중 에러 발생");
}
}
const getMovieById = async (req, res) => {
try {
const movieIds = req.movieIds
const elements = await Promise.all(
movieIds.map(async (movieId) => {
const movie = await axios.get(`https://api.themoviedb.org/3/movie/${movieId}?api_key=${process.env.TMDB_APP_KEY}&language=ko-KR`)
return movie.data
})
)
res.json(elements)
} catch (error) {
return res.status(500).send(error.message || "영화 가져오기 중 에러 발생");
}
}
const movieforAdmin = async (req, res) => {
try {
const TMDBmovieIds = []
......@@ -111,6 +69,7 @@ const getAllMovie = async (req, res, next) => {
const getMovieList = async (req, res) => {
try {
const { category } = req.params
const movieList = await Movie.findAll()
const movieIds = []
movieList.forEach(el => {
......@@ -119,10 +78,45 @@ const getMovieList = async (req, res) => {
const elements = await Promise.all(
movieIds.map(async (movieId) => {
const movie = await axios.get(`https://api.themoviedb.org/3/movie/${movieId}?api_key=${process.env.TMDB_APP_KEY}&language=ko-KR`)
return movie.data
const cols = await Movie.findOne({
where: { "movieId": movieId },
attributes: ["ticket_sales", "vote_average"]
})
const totalReservationRate = await Movie.findAll({
attributes: [[sequelize.fn('SUM', sequelize.col('ticket_sales')), 'totalReservationRate']]
});
return { ...movie.data, ticket_sales: cols.ticket_sales, vote_average: cols.vote_average, totalReservationRate: totalReservationRate[0] }
})
)
res.json(elements)
if (category === "popular") {
for (let i = 0; i < elements.length; i++) {
if (new Date(elements[i].release_date) > new Date()) {
elements.splice(i, 1);
i--;
}
}
elements.sort(function (a, b) {
return b.popularity - a.popularity
})
res.json(elements)
} else if (category === "upcoming") {
for (let i = 0; i < elements.length; i++) {
if (new Date(elements[i].release_date) <= new Date()) {
elements.splice(i, 1);
i--;
}
}
elements.sort(function (a, b) {
return a.release_date - b.release_date
})
res.json(elements)
} else {
elements.sort(function (a, b) {
return a.title - b.title
})
res.json(elements)
}
} catch (error) {
return res.status(500).send(error.message || "영화 정보 가져오는 중 에러 발생")
}
......@@ -165,7 +159,14 @@ const findonlyTitle = async (req, res) => {
const elements = await Promise.all(
movieIds.map(async (movieId) => {
const movie = await axios.get(`https://api.themoviedb.org/3/movie/${movieId}?api_key=${process.env.TMDB_APP_KEY}&language=ko-KR`)
return movie.data
const cols = await Movie.findOne({
where: { "movieId": movieId },
attributes: ["ticket_sales", "vote_average"]
})
const totalReservationRate = await Movie.findAll({
attributes: [[sequelize.fn('SUM', sequelize.col('ticket_sales')), 'totalReservationRate']]
});
return { ...movie.data, ticket_sales: cols.ticket_sales, vote_average: cols.vote_average, totalReservationRate: totalReservationRate[0] }
})
)
return res.json({ count: movieIds.length, results: elements })
......@@ -189,8 +190,6 @@ const findaboutAll = async (req, res, next) => {
export default {
getListfromDB,
getMovieByCategory,
getMovieById,
getAllMovie,
getMovieList,
create,
......
import axios from 'axios'
import { Movie, Reservation, Theater } from '../db/index.js'
import sequelize from 'sequelize'
const { Op } = sequelize
const findReservedSeats = async (req, res) => {
const { timetable } = req.body
try {
const reservedSeats = await Reservation.findAll({
where: {
timetable: timetable
}
})
res.json(reservedSeats)
} catch (error) {
res.status(500).send(error.message || "이미 예매되어있는 좌석을 찾는 중 오류발생")
}
}
const findReservation = async (req, res) => {
const { user } = req.body
try {
const reservation = await Reservation.findAll({
where: {
user: user
}
})
res.json(reservation)
} catch (error) {
res.status(500).send(error.message || "예매 내역들을 찾는 중 오류발생")
}
}
const findOneReservation = async (req, res) => {
const { userType, user } = req.body
try {
const reservation = await Reservation.findAll({
where: {
userType: userType,
user: user
},
})
// console.log(reservation)
res.json(reservation)
} catch (error) {
res.status(500).send(error.message || "예매 내역을 찾는 중 오류 발생")
}
}
const saveReservation = async (req, res) => {
const { movieId, selectedTheater, timetable, payment, user, userType, totalFee } = req.body
const rows = req.body.selectedSeats.map(el => el.split('-')[0])
const cols = req.body.selectedSeats.map(el => el.split('-')[1])
try {
for (let index = 0; index < rows.length; index++) {
const reservation = await Reservation.create({
user: user,
userType: userType,
movieId: movieId,
theater: selectedTheater,
row: rows[index],
col: cols[index],
timetable: timetable,
payment: payment,
totalFee: totalFee
})
}
const movie = await Movie.findOne({
where: {
movieId: movieId
}
})
movie.ticket_sales++
await movie.save();
res.json({ message: '200 OK' })
} catch (error) {
console.log(error)
res.status(500).send(error.message || "예매DB에 저장 실패")
}
}
export default {
findReservedSeats,
findReservation,
findOneReservation,
saveReservation
}
\ No newline at end of file
import { Theater, TheaterType } from "../db/index.js";
const getTheaterInfo = async (req, res) => {
const { theaterName } = req.body
try {
const theaterInfo = await Theater.findOne({
where: { theaterName: String(theaterName) },
attributes: ['theaterName', 'rows', 'columns']
})
// console.log("theaterInfo====",theaterInfo)
return res.json(theaterInfo)
} catch (error){
console.log(error)
}
}
const getAll = async (req, res) => {
try {
const findList = await Theater.findAll({ attributes: { exclude: ['createdAt', 'updatedAt'] }, include: [TheaterType], order: [['theaterName']] })
......@@ -64,5 +77,6 @@ export default {
getOne,
getTypes,
submit,
remove
}
\ No newline at end of file
remove,
getTheaterInfo
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment