Commit eacc9ce9 authored by 한규민's avatar 한규민
Browse files

Merge branch 'master' into gyumin

parents 19251ba0 c6fcbcbe
......@@ -23,7 +23,8 @@ const MovieCard = ({ list }) => {
<div className={`${styles.description}`}>{movie.overview}</div>
</Link>
<div className="card-body text-light">
<marquee className={`h2 card-title text-center ${styles.title}`}>{movie.title}</marquee>
{movie.adult? <image src="/images/19.png" /> :<></>}
<div className={`h4 card-title text-center ${styles.title}`}>{movie.title}</div>
<p className={`card-text text-center ${styles.txt}`}>예매율: {movie.ticket_sales}0% | {movie.runtime}</p>
<p className="card-text text-center"><small className="text-muted">{movie.release_date} 개봉</small></p>
</div>
......
......@@ -16,7 +16,7 @@ const MovieChart = () => {
async function getTMDB_TopRated() {
try {
setError("")
const data = await movieApi.getMoviesfromTM(category)
const data = await movieApi.getListByCategoryfromDB(category)
console.log("sdad==", data)
setTMDB_TopRated_Data([...data])
} catch (error) {
......@@ -30,7 +30,7 @@ const MovieChart = () => {
<div className="row row-cols-1 row-cols-md-4 g-4">
<MovieCard list={TMDB_TopRated_Data} />
</div>
: <h2 className="text-white text-center my-5">영화정보를 로딩 없습니다.</h2>
: <h2 className="text-white text-center p-5">영화정보를 로딩중입니다!</h2>
}
</>
)
......
......@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'
import movieApi from "../apis/movie.api.js"
// import MovieCard from "./MovieCard/index.js"
import { Link } from 'react-router-dom'
import styles from './MovieCard/MovieCard.js'
import styles from './MovieCard/movie-card.module.scss'
import catchErrors from '../utils/catchErrors.js'
const MovieComing = () => {
......@@ -17,8 +17,9 @@ const MovieComing = () => {
async function getTMDB_UpComing() {
try {
setError("")
const response = await movieApi.getMoviesfromTM(category)
const response = await movieApi.getListByCategoryfromDB(category)
setTMDB_UpComing_Data([...response])
console.log(response)
} catch (error) {
catchErrors(error, setError)
}
......@@ -41,7 +42,8 @@ const MovieComing = () => {
<div className={`${styles.description}`}>{movie.overview}</div>
</Link>
<div className="card-body text-light">
<marquee className={`h2 card-title text-center ${styles.title}`}>{movie.title}</marquee>
{movie.adult ? <image src="/images/19.png" /> : <></>}
<div className={`h4 card-title text-center ${styles.title}`}>{movie.title}</div>
<p className={`card-text text-center ${styles.txt}`}>예매율: {movie.ticket_sales}0% | {movie.runtime}</p>
<p className="card-text text-center"><small className="text-muted">{movie.release_date} 개봉</small></p>
</div>
......@@ -54,7 +56,7 @@ const MovieComing = () => {
</div>
))}
</div>
: <h2 className="text-white text-center my-5">영화정보를 로딩 없습니다.</h2>
: <h2 className="text-white text-center p-5">영화정보를 로딩중입니다!</h2>
}
</>
)
......
import { useState } from 'react'
// import { useState } from 'react'
import styles from './seatTable.module.scss'
const SeatTable = (props) => {
const SeatTable = ({ theaterInfo, count, setSelectedSeats, selectedSeats, reservedSeats }) => {
const table = []
if (props.theaterInfo) {
for (let rowIndex = 0; rowIndex < props.theaterInfo.rows; rowIndex++) {
if (theaterInfo) {
for (let rowIndex = 0; rowIndex < 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++) {
for (let colIndex = 0; colIndex < theaterInfo.columns; colIndex++) {
table.push(
<span>
{props.reservedSeats.find(el => el === String(rowIndex + 1) + '-' + String(colIndex + 1))
{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>
<button className={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>
)
......@@ -24,25 +24,23 @@ const SeatTable = (props) => {
function handleClick(event) {
const num = Object.values(props.count).reduce((a, b) => (a + b))
if (props.selectedSeats.find(el => el === event.target.name + '-' + event.target.id)) {
const num = Object.values(count).reduce((a, b) => (a + b))
if (selectedSeats.find(el => el === event.target.name + '-' + event.target.id)) {
//제거
const deleted = props.selectedSeats.filter((element) => element !== event.target.name + '-' + event.target.id);
props.setSelectedSeats(deleted)
const deleted = selectedSeats.filter((element) => element !== event.target.name + '-' + event.target.id);
setSelectedSeats(deleted)
} else {
if (props.selectedSeats.length > num - 1) {
if (selectedSeats.length > num - 1) {
alert("선택한 좌석이 예매인원보다 많습니다.")
} else {
//추가
props.setSelectedSeats([...props.selectedSeats, event.target.name + '-' + event.target.id])
setSelectedSeats([...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}
</div>
......
import { useState, useEffect } from 'react'
import axios from "axios"
import catchErrors from "../utils/catchErrors"
// import InfoModal from "./InfoModal"
// const { kakao } = window;
const TheaterInfo = () => {
// if (kakao) {
// console.log("kakao")
// const mapContainer = document.getElementById('map'), // 지도를 표시할 div
// mapOption = {
// center: new kakao.maps.LatLng(33.450701, 126.570667), // 지도의 중심좌표
// level: 3 // 지도의 확대 레벨
// };
// // 지도를 생성합니다
// const map = new kakao.maps.Map(mapContainer, mapOption);
// // 주소-좌표 변환 객체를 생성합니다
// const geocoder = new kakao.maps.services.Geocoder();
// // 주소로 좌표를 검색합니다
// geocoder.addressSearch('제주특별자치도 제주시 첨단로 242', function (result, status) {
// // 정상적으로 검색이 완료됐으면
// if (status === kakao.maps.services.Status.OK) {
// const coords = new kakao.maps.LatLng(result[0].y, result[0].x);
// // 결과값으로 받은 위치를 마커로 표시합니다
// const marker = new kakao.maps.Marker({
// map: map,
// position: coords
// });
// // 인포윈도우로 장소에 대한 설명을 표시합니다
// const infowindow = new kakao.maps.InfoWindow({
// content: '<div style="width:150px;text-align:center;padding:6px 0;">우리회사</div>'
// });
// infowindow.open(map, marker);
// // 지도의 중심을 결과값으로 받은 위치로 이동시킵니다
// map.setCenter(coords);
// }
// });
// }
const [theaterInfo, setTheaterInfo] = useState()
const [currentInfo, setCurrentInfo] = useState({
name: "init",
title: "init",
information: "init"
})
const [error, setError] = useState()
const [tabContent, setTabContent] = useState([])
useEffect(() => {
getTheaterInfo()
}, [])
useEffect(() => {
if (currentInfo.title === "parking") {
setTabContent(<div>{currentInfo.information}</div>)
} else if (currentInfo.title === "address") {
setTabContent(<div id="map">{currentInfo.information}</div>)
} else {
setTabContent(<div>{currentInfo.information}</div>)
}
}, [currentInfo])
async function getTheaterInfo() {
try {
const response = await axios.get('/api/info/cinema')
const response2 = await axios.get('/api/theater')
setTheaterInfo({...response.data, theaterNum:response2.data.length})
setCurrentInfo({
name:"대중교통 안내",
title:"transportation",
information: response.data.transportation
})
} catch (error) {
catchErrors(error, setError)
}
}
function handleClick(e) {
setCurrentInfo({
name: e.target.name,
title: e.target.id,
information: e.target.value
})
}
return (
<>
{theaterInfo ?
<div>
{/* {console.log(currentInfo)} */}
{console.log(theaterInfo)}
<h2 className="m-5">{theaterInfo.cinemaName}</h2>
<div className="my-3 text-center">
<img src="/images/movieTheater.jpg" style={{ width: "80%" }} />
</div>
<div className="m-3"> 상영관 : {theaterInfo.theaterNum}</div>
<div className="m-3">{theaterInfo.address}</div>
<div className="row justify-content-sm-center py-5">
<div className="col-sm-4 text-end">
<div className="m-2">
<img src="/images/icon-bus.png" style={{ width: "35px" }} />
<button className="px-3" name="대중교통 안내" id="transportation" value={theaterInfo.transportation} type="button" onClick={handleClick} style={{ background: "black", borderLeftColor: "black", borderTopColor: "black", borderBottomColor: "black", color: "white", borderRightColor: currentInfo.title === "transportation" ? "white" : "black" }}>대중교통 안내
</button>
</div>
<div className="m-2">
<img src="/images/icon-car.png" style={{ width: "35px" }} />
<button className="px-3" name="자가용/주차 안내" id="parking" value={theaterInfo.parking} type="button" onClick={handleClick} style={{ background: "black", borderLeftColor: "black", borderTopColor: "black", borderBottomColor: "black", color: "white", borderRightColor: currentInfo.title === "parking" ? "white" : "black" }}>자가용/주차 안내
</button>
</div>
<div className="m-2">
<img src="/images/icon-map.png" style={{ width: "35px" }} />
<button className="px-3" name="지도보기" id="address" value={theaterInfo.address} type="button" onClick={handleClick} style={{ background: "black", borderLeftColor: "black", borderTopColor: "black", borderBottomColor: "black", color: "white", borderRightColor: currentInfo.title === "address" ? "white" : "black" }}>지도보기
</button>
</div>
</div>
<div className="col-sm-6">
<div className="m-2">
{tabContent}
</div>
</div>
</div>
<div id="map"></div>
</div>
:
<div>
극장정보를 불러올 없습니다.
</div>}
</>
)
}
export default TheaterInfo
\ No newline at end of file
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import styles from "./ticketingMovie.module.scss"
import movieApi from '../../apis/movie.api'
import catchErrors from '../../utils/catchErrors'
const TicketingMovie = (props) => {
const TicketingMovie = ({ticketInfo, setTicketInfo}) => {
const [movieList, setMovieList] = useState([])
const [error, setError] = useState()
useEffect(() => {
getMovieList()
}, [])
async function getMovieList() {
try {
const response = await axios.get(`/api/movie/movielist`)
setMovieList(response.data)
const response = await movieApi.getListByCategoryfromDB()
console.log(response)
setMovieList(response)
} catch (error) {
catchErrors(error, setError)
}
}
function handleClick(event) {
console.log(event.target.name)
props.setTicketInfo({...props.ticketInfo, movieId: event.target.name })
setTicketInfo({...ticketInfo, movieId: event.target.name })
}
return (
<div >
{console.log(props.ticketInfo.movieId)}
{console.log(ticketInfo.movieId)}
<div className="d-grid gap-2">
{movieList.length > 0
? movieList.map(movie => (
<button name={movie.id} className={`${props.ticketInfo.movieId == movie.id ? styles.on : styles.btn}`} onClick={handleClick}>
<button name={movie.id} className={`${ticketInfo.movieId == movie.id ? styles.on : styles.btn}`} onClick={handleClick}>
{movie.title}
</button>
))
......
import styles from "./ticketingTheater.module.scss"
const TicketingTheater = (props) => {
const TicketingTheater = ({ticketInfo, cinemaInfo, setTicketInfo}) => {
function handleClick(event) {
// event.preventDefault()
console.log(event.target.name)
props.setTicketInfo({ ...props.ticketInfo, cinema: event.target.name })
setTicketInfo({ ...ticketInfo, cinema: event.target.name })
}
return (
<div >
<div className="d-grid gap-2">
<button name={props.cinemaInfo.cinemaName} className={`${props.ticketInfo.cinema === props.cinemaInfo.cinemaName ? styles.on : styles.btn}`} onClick={handleClick}>{props.cinemaInfo.cinemaName}</button>
<button name={cinemaInfo.cinemaName} className={`${ticketInfo.cinema === cinemaInfo.cinemaName ? styles.on : styles.btn}`} onClick={handleClick}>{cinemaInfo.cinemaName}</button>
</div>
</div>
)
......
const TicketingTimeTable = (props) => {
const TicketingTimeTable = ({ticketInfo}) => {
return (
<div>
<div className="text-center" style={{color:"white"}}>
{console.log(props.ticketInfo.movieId, props.ticketInfo.theater)}
{props.ticketInfo.movieId && props.ticketInfo.theater
? <div>{props.ticketInfo.movieId} {props.ticketInfo.theater}</div>
{console.log(ticketInfo.movieId, ticketInfo.cinema)}
{ticketInfo.movieId && ticketInfo.cinema
? <div>{ticketInfo.movieId} {ticketInfo.cinema}</div>
: <div>영화와 극장을 모두 선택해주세요.</div>}
</div>
</div>
......
import { useEffect, useState } from 'react'
import movieApi from '../apis/movie.api.js'
const Video = (props) => {
const Video = ({movieId}) => {
const [videoUrls, setVideoUrls] = useState([])
useEffect(() => {
getVideos()
......@@ -8,7 +8,7 @@ const Video = (props) => {
async function getVideos() {
try {
const data = await movieApi.getVideosfromTM(props.movieId)
const data = await movieApi.getVideosfromTM(movieId)
setVideoUrls(data)
} catch (error) {
console.log(error)
......
......@@ -3,27 +3,23 @@ import MovieChart from '../components/MovieChart.js'
import MovieComing from '../components/MovieComing.js'
const MovieListPage = () => {
const [state, setState] = useState(true)
const [state, setState] = useState(0)
return (
<div className="container">
<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? "3px solid":"none" ,borderBottomColor:state?"#FEDC00":"black"}} id="moviechart-tab" data-bs-toggle="tab" data-bs-target="#moviechart" type="button" role="tab" aria-controls="moviechart" aria-selected="true" onClick={() => setState(true)}>무비차트</button>
</li>
<li className="nav-item" role="presentation">
<button className="nav-link mx-auto" style={{color:"white", borderColor: "black",backgroundColor:"black", borderBottom: state?"none" :"3px solid", borderBottomColor:state?"black": "#FEDC00"}} id="moviecomming-tab" data-bs-toggle="tab" data-bs-target="#moviecomming" type="button" role="tab" aria-controls="moviecomming" aria-selected="false" onClick={() => setState(false)}>상영예정작</button>
</li>
</ul>
<div className="text-center my-5">
<button className="mx-auto" style={{ color: "white", borderColor: "black", backgroundColor: "black", borderBottom: !state ? "3px solid" : "none", borderBottomColor: !state ? "#FEDC00" : "black" }} type="button" onClick={() => setState(0)}>무비차트</button>
<button className="mx-auto" style={{ color: "white", borderColor: "black", backgroundColor: "black", borderBottom: !state ? "none" : "3px solid", borderBottomColor: !state ? "black" : "#FEDC00" }} type="button" onClick={() => setState(1)}>상영예정작</button>
</div>
<div className="tab-content" id="myTabContent">
<div className="tab-pane fade show active" id="moviechart" role="tabpanel" aria-labelledby="moviechart-tab">
<div>
{state === 0
?
<MovieChart />
</div>
<div className="tab-pane fade" id="moviecomming" role="tabpanel" aria-labelledby="moviecomming-tab">
:
<MovieComing />
</div>
}
</div>
</div>
)
......
......@@ -113,13 +113,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 axios from 'axios'
import { useAuth } from '../context/auth_context'
import { useEffect, useState } from 'react'
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
})
console.log({
reservationData: [...response2.data],
userData: { ...response.data },
})
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"
})
console.log(responseEmail.data)
}
console.log(response.data)
}
} 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
})
console.log(response2.data)
if (response.data || response2.data) {
const responseEmail = await axios.post('/api/email/send', {
...response2.data,
...response.data,
})
console.log(responseEmail.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 { 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', {
...ticketInfo,
...userInfo
})
console.log(response.data)
} catch (error) {
console.log(error)
}
}
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>
</div>
</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" />
<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.cinema}</div>
<div>{ticketInfo.time}</div>
<div className="mb-3">{ticketInfo.selectedTheater} {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>
)
}
export default Payment
\ No newline at end of file
import axios from 'axios'
import { useEffect, useState } from 'react'
import { useHistory } from 'react-router-dom'
import { useAuth } from '../../context/auth_context'
import catchErrors from '../../utils/catchErrors'
import styles from './PaymentPage.module.scss'
const Payment = ({ location }) => {
const history = useHistory();
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(() => {
console.log(user.id)
if (user.role === "member") {
getUserInfo()
}
}, [])
async function getUserInfo() {
try {
const response = await axios.post(`/api/auth/getuserinfo`, {
id: user.id
})
console.log(response.data)
setUserInfo(response.data)
} catch (error) {
catchErrors(error, setError)
}
}
function handleChangeGuest(e) {
setGuestInfo({ ...guestInfo, [e.target.name]: String(e.target.value) })
}
async function handleClickGuest() {
try {
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 {
if (user.role === "member") {
const response = await axios.post(`/api/reservation/save`, {
userType: "member",
payment: "카카오페이",
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,
payment: "카카오페이",
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" }}>
{console.log(ticketInfo)}
{/* {console.log(userInfo)} */}
{/* {console.log(guestInfo)} */}
<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>
......
......@@ -10,7 +10,7 @@ const TicketingPage = ({ location }) => {
const [ticketInfo, setTicketInfo] = useState({
...location.state,
cinema:"",
selectedTheater: 1,
selectedTheater: "1",
time: "2021/07/21 10:00"
})
const [cinemaInfo, setCinemaInfo] = useState({})
......@@ -52,7 +52,7 @@ const TicketingPage = ({ location }) => {
<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>
<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 ">
......
......@@ -6,50 +6,76 @@ 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'
import catchErrors from '../utils/catchErrors'
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()
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
})
useEffect(() => {
getInfo()
}, [])
useEffect(() => {
getTicketFee()
}, [theaterInfo.theatertypeId])
async function getInfo() {
try {
const response = await axios.post('/api/theater/getInfo', {
theaterNum: ticketInfo.selectedTheater
theaterName: 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)
catchErrors(error, setError)
}
}
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)
}
}
function loginModal() {
if (user) {
if (user.role === "member") {
history.push("/payment", {
...ticketInfo, selectedSeats: selectedSeats, ...count
...ticketInfo, selectedSeats: selectedSeats, ...count, totalFee: count.adult * ticketFee.adult + count.youth * ticketFee.youth + count.senior * ticketFee.senior
});
} else {
modal.current = new Modal(modalRef.current)
......@@ -62,7 +88,6 @@ const TicketingSeatPage = ({ location }) => {
<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>
......@@ -78,7 +103,7 @@ const TicketingSeatPage = ({ location }) => {
</Link>
<Link to={{
pathname: `/payment`,
state: { ...ticketInfo, selectedSeats: selectedSeats, ...count }
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>
......@@ -86,27 +111,39 @@ const TicketingSeatPage = ({ location }) => {
</div>
</div>
</div>
<div className="container" style={{ color: "white" }}>
{console.log(ticketInfo)}
{console.log(reservedSeats)}
<div className="mx-5 pb-5" style={{ color: "white" }}>
<div className="row justify-content-center my-5">
<div className="col-sm-4 mb-3 ">
<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 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 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>
......@@ -132,33 +169,45 @@ const TicketingSeatPage = ({ location }) => {
</div>
</div>
<div className="row p-3 mt-5" style={{ backgroundColor: "#252525" }}>
<div className="col-sm-3 border-end text-center">
<div className="col-sm-2 mb-1 text-center">
{ticketInfo
? <img style={{ maxHeight: "10rem" }} src={`https://image.tmdb.org/t/p/original${ticketInfo.poster_path}`} alt="영화포스터" />
? <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-6 border-end" style={{ color: "white" }}>
<div className="mb-2 text-center">극장선택</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>상영관: 3</li>
<li>좌석: {selectedSeats}</li>
<li>상영관: {ticketInfo.selectedTheater}</li>
<li>좌석: {selectedSeats.map(el => String.fromCharCode(parseInt(el.split('-')[0]) + 64) + el.split('-')[1]) + ' '}</li>
</ul>
: <div></div>}
:
<div className="mb-2 text-center">극장선택</div>
}
</div>
<div className="col-sm-3 text-center">
<div className="mb-2" style={{ color: "white" }}>결제하기</div>
{ticketInfo
<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" alt="결제하기" />
<img className="border border-3 rounded-3" src="/images/icons8-arrow-white.png" style={{ width: "70px" }} alt="결제하기" />
</button>
:
<button disabled>
<img className="border border-3 rounded-3" src="/images/icons8-arrow-white.png" alt="결제하기" />
<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>
}
......
import nodemailer from "nodemailer"
const SendMail = async (req,res) => {
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({
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}`,
text: `${nickname}님의 예매: ${title} / ${cinema} / ${selectedTheater}관 / 일시: ${time} / ${selectedSeats} /`,
};
// 메일 전송
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,selectedTheater, time, nickname, selectedSeats);
const SendMail = async (req, res) => {
// const { email, title, cinema, theater, time, name, nickname } = req.body.userData
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 + 65) + 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);
}
......
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