Commit 1abc13d9 authored by Jiwon Yoon's avatar Jiwon Yoon
Browse files

극장정보 및 이메일 api 및 예매완료

parent e3674d69
import { useState, useEffect } from "react";
import cinemaApi from "../../apis/cinema.api.js";
import catchErrors from "../../utils/catchErrors.js";
import { useAuth } from '../../context/auth_context'
import styles from "./admin.module.scss";
const TicketFeeTable = ({ setEditFee, formRef }) => {
const [ticketFee, setTicketFee] = useState([])
const [error, setError] = useState("")
const { user } = useAuth()
useEffect(() => {
getInfo()
......@@ -47,7 +51,7 @@ const TicketFeeTable = ({ setEditFee, formRef }) => {
}
return (
<table className={`table caption-top text-center align-middle ${styles.tableForm}`}>
<table style={{ color: user.role==="admin"?"":"white" }} className={`table caption-top text-center align-middle ${styles.tableForm}`}>
<caption className="text-dark">영화관람료 안내</caption>
<thead className={`table-dark align-middle ${styles.dNone}`}>
<tr>
......@@ -57,7 +61,10 @@ const TicketFeeTable = ({ setEditFee, formRef }) => {
<th>청소년</th>
<th>일반</th>
<th>경로</th>
<th style={{ width: "14%" }}></th>
{user.role === "admin"
?
<th style={{ width: "14%" }}></th>
: <></>}
</tr>
</thead>
<tbody>
......@@ -70,12 +77,15 @@ const TicketFeeTable = ({ setEditFee, formRef }) => {
<td className="d-inline-block d-md-table-cell">{priceToString(info.weekdays + info.morning + info.youth + info.defaultPrice)}</td>
<td className="d-inline-block d-md-table-cell">{priceToString(info.weekdays + info.morning + info.adult + info.defaultPrice)}</td>
<td className="d-inline-block d-md-table-cell">{priceToString(info.weekdays + info.morning + info.senior + info.defaultPrice)}</td>
<td rowSpan="6" className="d-none d-md-table-cell">
<div className="d-flex flex-column">
<button type="button" className="btn btn-primary my-1" onClick={() => editRow(info.theatertypeId)}>수정</button>
<button type="button" className="btn btn-danger my-1" onClick={() => deleteData(info.theatertypeId)}>삭제</button>
</div>
</td>
{user.role === "admin"
?
<td rowSpan="6" className="d-none d-md-table-cell">
<div className="d-flex flex-column">
<button type="button" className="btn btn-primary my-1" onClick={() => editRow(info.theatertypeId)}>수정</button>
<button type="button" className="btn btn-danger my-1" onClick={() => deleteData(info.theatertypeId)}>삭제</button>
</div>
</td>
: <></>}
</tr>
<tr>
<td className="d-inline-block d-md-table-cell">일반 (11:00 ~ )</td>
......@@ -107,12 +117,15 @@ const TicketFeeTable = ({ setEditFee, formRef }) => {
<td className="d-inline-block d-md-table-cell">{priceToString(info.weekend + info.night + info.youth + info.defaultPrice)}</td>
<td className="d-inline-block d-md-table-cell">{priceToString(info.weekend + info.night + info.adult + info.defaultPrice)}</td>
<td className="d-inline-block d-md-table-cell">{priceToString(info.weekend + info.night + info.senior + info.defaultPrice)}</td>
<td className={`d-block d-md-none ${styles.borderTop}`}>
<div className="d-flex justify-content-end">
<button type="button" className="btn btn-primary" onClick={() => editRow(info.theatertypeId)}>수정</button>
<button type="button" className="btn btn-danger ms-2" onClick={() => deleteData(info.theatertypeId)}>삭제</button>
</div>
</td>
{user.role === "admin"
?
<td className={`d-block d-md-none ${styles.borderTop}`}>
<div className="d-flex justify-content-end">
<button type="button" className="btn btn-primary" onClick={() => editRow(info.theatertypeId)}>수정</button>
<button type="button" className="btn btn-danger ms-2" onClick={() => deleteData(info.theatertypeId)}>삭제</button>
</div>
</td>
: <></>}
</tr>
</>)
: <tr>
......
......@@ -28,7 +28,7 @@ const Kakaopay = ({ticketInfo}) => {
return (
<>
<button onClick={handleClick} style={{ backgroundColor: "black", border: '0' }}>
<img src="/images/payment_icon_yellow_medium.png" />
<img src="/images/payment_icon_yellow_medium.png" style={{width:"130px"}} />
</button>
</>
)
......
import { useState, useEffect } from 'react'
import axios from "axios"
import {useState, useEffect} from 'react'
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')
console.log(response.data)
setTheaterInfo(response.data)
const response2 = await axios.get('/api/theater')
setTheaterInfo({...response.data, theaterNum:response2.data.length})
} catch (error) {
catchErrors(error,setError)
catchErrors(error, setError)
}
}
function handleClick(e) {
setCurrentInfo({
name: e.target.name,
title: e.target.id,
information: e.target.value
})
}
return (
<>
{/* <h3>{theaterInfo.cinemaName}</h3> */}
<div> 상영관 : </div>
{/* <div>{theaterInfo.address}</div> */}
{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>}
</>
)
}
......
import axios from 'axios'
import { useEffect, useState } from 'react'
import { useHistory } from 'react-router-dom'
import Kakaopay from '../../components/Kakaopay'
import { useAuth } from '../../context/auth_context'
import catchErrors from '../../utils/catchErrors'
import styles from './PaymentPage.module.scss'
const Payment = ({ location }) => {
const history = useHistory();
const [ticketInfo, setTicketInfo] = useState({ ...location.state })
const [error, setError] = useState("")
const [userInfo, setUserInfo] = useState()
const [userInfo, setUserInfo] = useState({
nickname: "",
email: "",
birth: "",
phoneNumber: ""
})
const [guestInfo, setGuestInfo] = useState({})
const [guestID, setGuestID] = useState()
const { user } = useAuth()
useEffect(() => {
console.log(user.id)
if (user.id > 0) {
if (user.role === "member") {
getUserInfo()
}
}, [])
......@@ -25,6 +32,7 @@ const Payment = ({ location }) => {
const response = await axios.post(`/api/auth/getuserinfo`, {
id: user.id
})
console.log(response.data)
setUserInfo(response.data)
} catch (error) {
catchErrors(error, setError)
......@@ -41,7 +49,7 @@ const Payment = ({ location }) => {
...guestInfo
})
setGuestID(response.data.id)
// console.log(response.data)
alert("비회원 정보가 저장되었습니다.")
} catch (error) {
catchErrors(error, setError)
}
......@@ -49,7 +57,7 @@ const Payment = ({ location }) => {
async function reservationComplete() {
try {
if (userInfo) {
if (user.id > 0) {
const response = await axios.post(`/api/reservation/save`, {
userType: "member",
user: userInfo.id,
......@@ -57,7 +65,16 @@ const Payment = ({ location }) => {
payment: "카카오페이",
timetable: 1
})
console.log("회원예매완료===", response.data)
if (response.data) {
const responseEmail = await axios.post('/api/email/send', {
...ticketInfo,
...userInfo,
...guestInfo,
})
console.log("이메일전송완료===", responseEmail.data)
alert("예매가 완료되었습니다.")
history.push('/')
}
} else {
if (guestID) {
const response = await axios.post(`/api/reservation/save`, {
......@@ -67,17 +84,22 @@ const Payment = ({ location }) => {
payment: "카카오페이",
timetable: 1
})
if (response.data) {
const responseEmail = await axios.post('/api/email/send', {
...ticketInfo,
...userInfo,
...guestInfo,
})
console.log("이메일전송완료===", responseEmail.data)
}
alert("예매가 완료되었습니다.")
console.log("비회원예매완료===", response.data)
history.push('/')
} else {
alert("비회원 정보를 모두 입력 후 저장버튼을 눌러주세요.")
alert("비회원 정보를 모두 입력 후 비회원 정보 저장 버튼을 눌러주세요.")
}
}
const responseEmail = await axios.post('/api/email/send', {
...ticketInfo,
...userInfo,
...guestInfo,
})
console.log("이메일전송완료===", responseEmail.data)
} catch (error) {
catchErrors(error, setError)
}
......@@ -88,7 +110,7 @@ const Payment = ({ location }) => {
<div className="container" style={{ color: "white" }}>
{console.log(ticketInfo)}
{console.log(userInfo)}
{console.log(guestInfo)}
{/* {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>
......@@ -96,11 +118,31 @@ const Payment = ({ location }) => {
</div>
<div className="row justify-content-center">
<div className="col-sm-8 text-center">
{user?.id > 0
{user.role === "member"
?
<div>
<h5 className="mb-3">회원정보</h5>
<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>
......@@ -134,7 +176,7 @@ const Payment = ({ location }) => {
</div>
}
<h5 className="my-4 p-2" style={{ backgroundColor: "white", color: "black" }}>결제방법</h5>
<img src="/images/naverpay_button.png" />
<img src="/images/naverpay_button.png" style={{width:"150px"}} />
<Kakaopay ticketInfo={ticketInfo} setTicketInfo={setTicketInfo} />
<div className="my-5">
<button className="btn btn-warning" type="button" style={{ width: "100%" }} onClick={reservationComplete}>결제완료</button>
......
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>
......@@ -20,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">
<TheaterInfo/>
<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">
<TicketFeeTable />
</div>
</div>
</div>
</div>
</div>
......
......@@ -48,7 +48,7 @@ const TicketingSeatPage = ({ location }) => {
}
function loginModal() {
if (user) {
if (user.role==="member") {
history.push("/payment", {
...ticketInfo, selectedSeats: selectedSeats, ...count
});
......@@ -155,7 +155,7 @@ const TicketingSeatPage = ({ location }) => {
{ticketInfo
?
<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:"90px"}} alt="결제하기" />
</button>
:
<button disabled>
......
import nodemailer from "nodemailer"
const SendMail = async (req,res) => {
const {email, title, cinema,selectedTheater, time, name} = req.body
const selectedSeats = req.body.selectedSeats
const sendMail = async (email,title, cinema,selectedTheater, time, name, 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: `${name}님의 예매: ${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, name, selectedSeats);
const SendMail = async (req, res) => {
const { email, title, cinema, selectedTheater, time, name, nickname } = req.body
const selectedSeats = req.body.selectedSeats
console.log(selectedSeats)
const sendMail = async (email, title, cinema, selectedTheater, 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} ${selectedTheater}
</div>
<div>
일시 및 좌석: ${time} / ${selectedSeats.map(el => String.fromCharCode(parseInt(el.split('-')[0]) + 65) + el.split('-')[1]) + ' '}
</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, selectedTheater, time, name, selectedSeats, nickname);
}
......
......@@ -205,6 +205,7 @@ const getUserInfo = async (req, res) => {
where: { id: id },
attributes: ["id","userId", "email", "nickname", "birth", "phoneNumber"]
})
console.log(userInfo)
res.json(userInfo)
} catch (error) {
res.status(500).send("회원정보 불러오기 실패");
......
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