Commit 7e4f390c authored by 한규민's avatar 한규민
Browse files

Merge branch 'master' into gyumin

parents 6d08d71f 73dd813f
import axios from "axios"; import axios from "axios";
import { baseUrl } from "../utils/baseUrl.js"; import { baseUrl } from "../utils/baseUrl.js";
const getAll = async (selectDate) => {
const { data } = await axios.get(`${baseUrl}/api/timetable?when=${selectDate}`)
return data
}
const submit = async (sendData) => { const submit = async (sendData) => {
const { data } = await axios.post(`${baseUrl}/api/timetable`, sendData) const { data } = await axios.post(`${baseUrl}/api/timetable`, sendData)
return data return data
} }
const remove = async (timeId) => {
const { data } = await axios.delete(`${baseUrl}/api/timetable/${timeId}`)
return data
}
const timetableApi = { const timetableApi = {
submit getAll,
submit,
remove
} }
export default timetableApi export default timetableApi
\ No newline at end of file
import { useState, useEffect } from "react";
import moment from 'moment';
import HorizontalCalender from "../Calender/HorizontalCalender.js";
import timetableApi from "../../apis/timetable.api.js";
import catchErrors from "../../utils/catchErrors.js";
import styles from "./admin.module.scss";
const TimeTable = () => { const TimeTable = () => {
const [selectDate, setSelectDate] = useState(moment().format('YYYY-MM-DD'))
const [timeList, setTimeList] = useState([])
const [error, setError] = useState("")
useEffect(() => {
getTimeTable(selectDate)
}, [selectDate])
async function getTimeTable() {
try {
setError("")
const res = await timetableApi.getAll(selectDate)
setTimeList(res)
} catch (error) {
catchErrors(error, setError)
}
}
async function deleteTime(timeId) {
try {
setError("")
await timetableApi.remove(timeId)
alert('해당 상영시간표 정보를 성공적으로 삭제하였습니다.')
getTimeTable(selectDate)
} catch (error) {
catchErrors(error, setError)
}
}
return ( return (
<div className="col-6"> <div className="col-12 col-lg-6 ms-lg-1 mb-5">
<HorizontalCalender selectDate={selectDate} setSelectDate={setSelectDate} />
{timeList.length !== 0 ?
timeList.map(el => <div className="mt-4">
<h5 className="mb-0">{el.theaterName} / <p className="d-inline fs-6 mb-0">{el.theatertype.theaterTypeName}</p></h5>
{el.timetable.map(time => <div className="d-inline-flex flex-column m-2">
<div className="d-flex justify-content-end">
<button type="button" className={`btn btn-dark btn-sm ${styles.customBtn}`} onClick={() => deleteTime(time.id)}>X</button>
</div>
<div className="card">
<div className="card-body py-1">{moment(time.start_time).format('HH:mm')} ~ {moment(time.end_time).format('HH:mm')}</div>
<div className="card-footer text-center py-1">{time.title}</div>
</div>
</div>)}
</div>)
: <p className="text-center mt-5 mb-0">서버에 저장되어 있는 상영시간표가 존재하지 않습니다.<br />아래의 양식을 작성해 새로운 상영시간표를 등록해주세요.</p>}
</div> </div>
) )
} }
......
...@@ -2,12 +2,13 @@ import TimeTableEditForm from "./TimeTableEditForm"; ...@@ -2,12 +2,13 @@ import TimeTableEditForm from "./TimeTableEditForm";
import TimeTable from "./TimeTable"; import TimeTable from "./TimeTable";
const TimeTableEdit = () => { const TimeTableEdit = () => {
return ( return (
<> <>
<h2 className="border-bottom border-2 text-center pb-2 me-2">현재 상영시간표 정보</h2> <h2 className="border-bottom border-2 text-center pb-2 me-2">현재 상영시간표 정보</h2>
<div className="d-flex"> <div className="d-flex flex-column flex-lg-row-reverse">
<TimeTableEditForm />
<TimeTable /> <TimeTable />
<TimeTableEditForm />
</div> </div>
</> </>
) )
......
...@@ -75,7 +75,7 @@ const TimeTableEditForm = () => { ...@@ -75,7 +75,7 @@ const TimeTableEditForm = () => {
const { list } = showTimes const { list } = showTimes
const isSelect = Object.values(selectInfo).every((el) => Boolean(el)) const isSelect = Object.values(selectInfo).every((el) => Boolean(el))
if (isSelect) { if (isSelect) {
const isTime = list.find(el => el.theaterTypeId === selectInfo.theater && (getDate(el.start) <= getDate(selectInfo.end) && getDate(el.end) >= getDate(selectInfo.start))) const isTime = list.find(el => (el.theaterTypeId === selectInfo.theater) && ((getDate(el.start) <= getDate(selectInfo.start) && getDate(selectInfo.start) <= getDate(el.end)) || (getDate(el.start) > getDate(selectInfo.start) && getDate(el.start) <= getDate(selectInfo.end))))
if (isTime) alert('이미 추가한 상영시간대입니다. 다른 시간대를 골라주시기 바랍니다.') if (isTime) alert('이미 추가한 상영시간대입니다. 다른 시간대를 골라주시기 바랍니다.')
else { else {
const theater = theaterList.find(theater => theater.theatertypeId === selectInfo.theater) const theater = theaterList.find(theater => theater.theatertypeId === selectInfo.theater)
...@@ -141,11 +141,13 @@ const TimeTableEditForm = () => { ...@@ -141,11 +141,13 @@ const TimeTableEditForm = () => {
window.location.reload() window.location.reload()
} catch (error) { } catch (error) {
catchErrors(error, setError) catchErrors(error, setError)
setShowTimes({ list: [] })
} }
} }
return ( return (
<form className="col-6" onSubmit={handleSubmit}> <form className="col-12 col-lg-6 me-lg-1" onSubmit={handleSubmit}>
<h5 className={`border-top border-dark border-2 pt-3 mb-3 ${styles.borderLg}`}>상영시간표 등록</h5>
<select className={`form-select mb-3 ${styles.shadowNone} ${styles.selectInput}`} id="movieId" name="movieId" value={selectId} onChange={handleChange} aria-label="select movie" defaultValue="0"> <select className={`form-select mb-3 ${styles.shadowNone} ${styles.selectInput}`} id="movieId" name="movieId" value={selectId} onChange={handleChange} aria-label="select movie" defaultValue="0">
{movieList.length !== 0 ? {movieList.length !== 0 ?
movieList.map((movie, index) => { movieList.map((movie, index) => {
...@@ -157,13 +159,15 @@ const TimeTableEditForm = () => { ...@@ -157,13 +159,15 @@ const TimeTableEditForm = () => {
}) })
: <option value="0" disabled>서버에 등록된 영화가 없습니다.</option>} : <option value="0" disabled>서버에 등록된 영화가 없습니다.</option>}
</select> </select>
<div className="col-md-6 mb-3"> <div className="d-flex justify-content-between">
<label htmlFor="release_date" className="form-label">상영시작일</label> <div className="col-md-5 mb-3">
<input type="text" className={`form-control ${styles.shadowNone}`} id="release_date" name="release_date" value={selectMovie?.release_date || ''} disabled /> <label htmlFor="release_date" className="form-label">상영시작일</label>
</div> <input type="text" className={`form-control ${styles.shadowNone}`} id="release_date" name="release_date" value={selectMovie?.release_date || ''} disabled />
<div className="col-md-6 mb-3"> </div>
<label htmlFor="end_date" className="form-label">상영종료일</label> <div className="col-md-5 mb-3">
<input type="date" className={`form-control ${styles.shadowNone}`} id="end_date" name="end_date" value={info.end_date} min={selectMovie.release_date} onChange={handleChange} /> <label htmlFor="end_date" className="form-label">상영종료일</label>
<input type="date" className={`form-control ${styles.shadowNone}`} id="end_date" name="end_date" value={info.end_date} min={selectMovie.release_date} onChange={handleChange} />
</div>
</div> </div>
<p>시간대 설정</p> <p>시간대 설정</p>
<ul className="list-group list-group-flush"> <ul className="list-group list-group-flush">
...@@ -171,10 +175,10 @@ const TimeTableEditForm = () => { ...@@ -171,10 +175,10 @@ const TimeTableEditForm = () => {
showTimes.list.map((timeInfo, index) => <li className="list-group-item d-flex justify-content-between align-items-center"> showTimes.list.map((timeInfo, index) => <li className="list-group-item d-flex justify-content-between align-items-center">
{timeInfo.theaterName}&nbsp;&nbsp;&nbsp;{timeInfo.start} ~ {timeInfo.end} {timeInfo.theaterName}&nbsp;&nbsp;&nbsp;{timeInfo.start} ~ {timeInfo.end}
<button type="button" className="btn btn-danger" onClick={() => delData(index)}>삭제</button> <button type="button" className="btn btn-danger" onClick={() => delData(index)}>삭제</button>
</li>) : <li className="list-group-item text-center">추가된 시간대가 없습니다. 을 작성해 시간대를 추가해 주세요.</li>} </li>) : <li className="list-group-item text-center">추가된 시간대가 없습니다. 아래 양식을 작성해 시간대를 추가해 주세요.</li>}
</ul> </ul>
<div> <div className="d-sm-flex flex-lg-column">
<div> <div className="col-sm-5 col-lg-12">
<select className={`form-select mb-3 ${styles.shadowNone} ${styles.selectInput}`} id="theater" name="theater" value={selectInfo.theater} onChange={handleChange} aria-label="select theater" defaultValue="0"> <select className={`form-select mb-3 ${styles.shadowNone} ${styles.selectInput}`} id="theater" name="theater" value={selectInfo.theater} onChange={handleChange} aria-label="select theater" defaultValue="0">
{theaterList.length !== 0 ? {theaterList.length !== 0 ?
theaterList.map((theater, index) => { theaterList.map((theater, index) => {
...@@ -187,16 +191,18 @@ const TimeTableEditForm = () => { ...@@ -187,16 +191,18 @@ const TimeTableEditForm = () => {
: <option value="0" disabled>서버에 등록된 상영관이 없습니다.</option>} : <option value="0" disabled>서버에 등록된 상영관이 없습니다.</option>}
</select> </select>
</div> </div>
<div> <div className="d-flex justify-content-between col-sm-7 col-lg-auto mb-3">
<input type="time" id="start" name="start" value={selectInfo.start} onChange={handleChange} disabled={!selectId || !selectInfo.theater} /> <div className="d-flex col-auto">
<p>{(selectId && selectInfo.start !== "") ? "~ " + selectInfo.end : ""}</p> <div className="col-auto ms-sm-2 ms-lg-0">
</div> <input type="time" className={`form-control ${styles.shadowNone}`} id="start" name="start" value={selectInfo.start} onChange={handleChange} disabled={!selectId || !selectInfo.theater} />
<div> </div>
<button type="button" className={`btn btn-dark ${styles.customBtn}`} onClick={addData}>추가</button> <p className="align-self-center ms-2 mb-0">{(selectId && selectInfo.start !== "") ? "~ " + selectInfo.end : ""}</p>
</div>
<button type="button" className={`btn btn-dark col-auto ${styles.customBtn}`} onClick={addData}>추가</button>
</div> </div>
</div> </div>
<div> <div className="d-grid gap-2">
<button type="submit" className={`btn btn-dark ${styles.customBtn}`}>등록</button> <button type="submit" className={`btn btn-dark ${styles.customBtn}`} disabled={showTimes.list.length === 0 ? true : false}>등록</button>
</div> </div>
</form> </form>
) )
......
...@@ -44,6 +44,12 @@ ...@@ -44,6 +44,12 @@
} }
} }
@media screen and (min-width: 992px) {
.borderLg {
border: 0 !important;
}
}
.selectInput { .selectInput {
& option[disabled] { & option[disabled] {
color: #000; color: #000;
......
import { useState, useEffect } from "react" import { useState, useEffect } from "react"
import movieApi from '../../apis/movie.api.js'
import "./box-office.module.css"
const BoxOffice = () => { const BoxOffice = ({TMDB_TopRated_Data}) => {
const [TMDB_TopRated_Data, setTMDB_TopRated_Data] = useState()
useEffect(() => {
// getTMDB_TopRated()
let items = document.querySelectorAll('.carousel .carousel-item')
// console.log("item", items)
items.forEach((el) => {
const minPerSlide = 4
let next = el.nextElementSibling
for (let i = 1; i < minPerSlide; i++) {
if (!next) {
// wrap carousel by using first child
next = items[0]
}
let cloneChild = next.cloneNode(true)
el.appendChild(cloneChild.children[0])
next = next.nextElementSibling
}
})
}, [])
async function getTMDB_TopRated() {
const category = "popular"
try {
const data = await movieApi.getMoviesfromTM(category)
console.log(data)
setTMDB_TopRated_Data(data)
} catch (error) {
console.log(error)
}
}
return ( return (
<div className="container text-center my-3"> <div className="container text-center my-3">
<div className="container text-center my-3"> {/* <div id="carouselExampleControls" className="carousel slide" data-bs-ride="carousel">
<h2 className="font-weight-light">Bootstrap Multi Slide Carousel</h2> <div className="carousel-inner">
<div className="row mx-auto my-auto justify-content-center"> {TMDB_TopRated_Data.length>0
<div id="recipeCarousel" className="carousel slide" data-bs-ride="carousel"> ?
<div className="carousel-inner" role="listbox"> TMDB_TopRated_Data.map((movie, index) => {
<div className="carousel-item active"> <div className={`carousel-item ${index === 0 ? "active" : ""}`}>
<div className="col-md-3"> {console.log(movie.poster_path)}
<div className="card"> <img src={`https://image.tmdb.org/t/p/original${movie.poster_path}`} className="d-block w-100" alt="Movie Poster"/>
<div className="card-img">
<img src="//via.placeholder.com/500x400/31f?text=1" className="img-fluid" />
</div>
<div className="card-img-overlay">Slide 1</div>
</div>
</div>
</div>
<div className="carousel-item">
<div className="col-md-3">
<div className="card">
<div className="card-img">
<img src="//via.placeholder.com/500x400/e66?text=2" className="img-fluid" />
</div>
<div className="card-img-overlay">Slide 2</div>
</div>
</div>
</div>
<div className="carousel-item">
<div className="col-md-3">
<div className="card">
<div className="card-img">
<img src="//via.placeholder.com/500x400/7d2?text=3" className="img-fluid" />
</div>
<div className="card-img-overlay">Slide 3</div>
</div>
</div>
</div>
<div className="carousel-item">
<div className="col-md-3">
<div className="card">
<div className="card-img">
<img src="//via.placeholder.com/500x400?text=4" className="img-fluid" />
</div>
<div className="card-img-overlay">Slide 4</div>
</div>
</div>
</div>
<div className="carousel-item">
<div className="col-md-3">
<div className="card">
<div className="card-img">
<img src="//via.placeholder.com/500x400/aba?text=5" className="img-fluid" />
</div>
<div className="card-img-overlay">Slide 5</div>
</div>
</div>
</div>
<div className="carousel-item">
<div className="col-md-3">
<div className="card">
<div className="card-img">
<img src="//via.placeholder.com/500x400/fc0?text=6" className="img-fluid" />
</div>
<div className="card-img-overlay">Slide 6</div>
</div>
</div>
</div> </div>
})
:
<div className="carousel-item">
{console.log("스틸컷 불러오기 오류")}
<img src="/images/none.jpg" className="d-block w-100" alt="등록된 스틸컷이 없습니다." />
</div> </div>
<a className="carousel-control-prev bg-transparent w-aut" href="#recipeCarousel" role="button" data-bs-slide="prev"> }
<span className="carousel-control-prev-icon" aria-hidden="true"></span>
</a>
<a className="carousel-control-next bg-transparent w-aut" href="#recipeCarousel" role="button" data-bs-slide="next">
<span className="carousel-control-next-icon" aria-hidden="true"></span>
</a>
</div>
</div> </div>
<h5 className="mt-2 fw-light">advances one slide at a time</h5> <button className="carousel-control-prev" type="button" data-bs-target="#carouselExampleControls" data-bs-slide="prev">
</div> <span className="carousel-control-prev-icon" aria-hidden="true"></span>
<div className="row my-auto justify-content-center"> <span className="visually-hidden">Previous</span>
<div id="recipeCarousel" className="carousel slide" data-bs-ride="carousel" data-bs-interval="999999999"> </button>
<div className={`carousel-inner`} role="listbox"> <button className="carousel-control-next" type="button" data-bs-target="#carouselExampleControls" data-bs-slide="next">
{TMDB_TopRated_Data ? <span className="carousel-control-next-icon" aria-hidden="true"></span>
TMDB_TopRated_Data.map((moviePoster, index) => ( <span className="visually-hidden">Next</span>
<div className={`carousel-item ${index === 0 ? "active" : ""}`}> </button>
<div className="col-sm-3"> </div> */}
<div className="card">
<div className="card-img">
<img src={`https://image.tmdb.org/t/p/original${moviePoster.poster_path}`} className="img-fluid" />
</div>
</div>
</div>
</div>
))
: (<div>영화를 불러올 없습니다:(</div>)}
</div>
<a className="carousel-control-prev bg-transparent w-aut" href="#recipeCarousel" role="button"
data-bs-slide="prev">
<span className="carousel-control-prev-icon" aria-hidden="true"></span>
</a>
<a className="carousel-control-next bg-transparent w-aut" href="#recipeCarousel" role="button"
data-bs-slide="next">
<span className="carousel-control-next-icon" aria-hidden="true"></span>
</a>
</div>
</div>
</div> </div>
) )
} }
......
@media (max-width: 767px) {
.carousel-inner .carousel-item > div {
display: none;
}
.carousel-inner .carousel-item > div:first-child {
display: block;
}
}
.carousel-inner .carousel-item.active,
.carousel-inner .carousel-item-next,
.carousel-inner .carousel-item-prev {
display: flex;
}
/* medium and up screens */
@media (min-width: 768px) {
.carousel-inner .carousel-item-end.active,
.carousel-inner .carousel-item-next {
transform: translateX(25%);
}
.carousel-inner .carousel-item-start.active,
.carousel-inner .carousel-item-prev {
transform: translateX(-25%);
}
}
.carousel-inner .carousel-item-end,
.carousel-inner .carousel-item-start {
transform: translateX(0);
}
@media (max-width: 767px) {
.carousel-inner .carousel-item > div {
display: none;
}
.carousel-inner .carousel-item > div:first-child {
display: block;
}
}
.carousel-inner .carousel-item.active,
.carousel-inner .carousel-item-next,
.carousel-inner .carousel-item-prev {
display: flex;
}
/* medium and up screens */
@media (min-width: 768px) {
.carousel-inner .carousel-item-end.active,
.carousel-inner .carousel-item-next {
transform: translateX(25%);
}
.carousel-inner .carousel-item-start.active,
.carousel-inner .carousel-item-prev {
transform: translateX(-25%);
}
}
.carousel-inner .carousel-item-end,
.carousel-inner .carousel-item-start {
transform: translateX(0);
}
import { useState, useEffect } from "react";
import moment from "moment";
import styles from "./calender.module.scss";
const Calender = ({ selectDate, setSelectDate }) => {
const [dateList, setDateList] = useState([])
const [week, setWeek] = useState(["", "", "", "", "", "", ""])
useEffect(() => {
getDate(selectDate)
}, [])
function getDate(oneDay) {
let dateArr = []
let lastWeek = moment(oneDay).subtract(7, 'days')
const nextWeek = moment(oneDay).add(7, 'days')
while (lastWeek.isBefore(nextWeek)) {
dateArr.push({ date: lastWeek.format('YYYY-MM-DD'), day: lastWeek.format('d') })
lastWeek.add(1, 'days')
}
const resultArr = dateArr.map(el => <div className="col-2 align-self-end text-center" onClick={() => setSelectDate(el.date)}>
{moment(el.date).isSame(oneDay) || el.date.split('-')[2] === "01" ? <strong className={styles.yearmonth}>{moment(el.date).format('YYYY.MM')}</strong> : ""}
<div className={"d-flex flex-column " + ((Number(el.day) === 0 || Number(el.day) === 6) ? ((Number(el.day) === 0) ? "text-danger" : "text-primary") : "")}>
<strong className={moment(el.date).isSame(oneDay) ? styles.selectDate : ""}>{moment(el.date).format('DD')}</strong>
<strong>{moment(el.date).isSame(oneDay) ? "오늘" : week[el.day]}</strong>
</div>
</div>)
setDateList(resultArr)
}
return (
<>
{console.log("date==", selectDate)}
<div className="d-flex position-relative border-bottom border-dark border-2 p-3">
<i className={`bi bi-calendar2 position-absolute top-0 ${styles.calender}`}></i>
<i className="col-1 bi bi-chevron-left align-self-center text-center"></i>
<div className={`d-flex col-10 ${styles.box}`}>{dateList.map(el => el)}</div>
<i className="col-1 bi bi-chevron-right align-self-center text-center"></i>
</div>
</>
)
}
export default Calender
\ No newline at end of file
.box {
overflow: hidden;
& .yearmonth {
position: relative;
top: 0;
width: 100%;
font-size: 10px;
}
& .selectDate {
background-color: #000;
color: #fff;
border-radius: 50%;
}
}
.calender {
right: 13px;
font-size: 1.5em;
}
\ No newline at end of file
const Collection = () => { import { useEffect, useState } from 'react'
import movieApi from '../apis/movie.api.js'
import catchErrors from '../utils/catchErrors.js'
const Collection = ({ TMDB_TopRated_Data }) => {
const [videoUrls, setVideoUrls] = useState([])
const [error, setError] = useState("")
useEffect(() => {
if (TMDB_TopRated_Data.length > 0) {
console.log("야이쒸===", TMDB_TopRated_Data)
getVideos()
}
}, [TMDB_TopRated_Data])
async function getVideos() {
try {
const data = await movieApi.getVideosfromTM(TMDB_TopRated_Data[0].id)
setVideoUrls(data)
} catch (error) {
// catchErrors(error, setError)
console.log(error)
}
}
return ( return (
<> <>
<h2 className="fw-bold text-white text-center my-5">Movie Collection</h2> <h2 className="fw-bold text-white text-center my-5">Movie Collection</h2>
<div className="d-flex container justify-content-between" style={{ marginBottom: "8em" }}> <div className="row justify-content-sm-center" style={{ marginBottom: "8rem" }}>
<div className="col-md-8 col-12 bg-white" style={{ height: "20em" }}></div> <div className="col-md-8">
<img className="col-md-3 bg-white" style={{ height: "20em" }} /> {videoUrls.length > 0
?
<div className="">
<div className="ratio ratio-16x9">
<iframe src={`https://www.youtube.com/embed/${videoUrls[0].key}`} title="YouTube video" allowfullscreen></iframe>
</div>
</div>
: <div className="text-center">예고편 정보가 존재하지 않습니다.</div>}
</div>
{TMDB_TopRated_Data.length > 0
?
<img src={`https://image.tmdb.org/t/p/original${TMDB_TopRated_Data[0].poster_path}`} className="col-md-3 bg-black" />
:
<div className="col-md-3"></div>
}
</div> </div>
</> </>
) )
......
...@@ -25,7 +25,7 @@ const MovieCard = ({ list }) => { ...@@ -25,7 +25,7 @@ const MovieCard = ({ list }) => {
<div className="card-body text-light"> <div className="card-body text-light">
{movie.adult? <image src="/images/19.png" /> :<></>} {movie.adult? <image src="/images/19.png" /> :<></>}
<div className={`h4 card-title text-center ${styles.title}`}>{movie.title}</div> <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 ${styles.txt}`}>예매율: {Math.round((movie.ticket_sales/(movie.totalReservationRate.totalReservationRate||1))*100)}% | {movie.runtime}</p>
<p className="card-text text-center"><small className="text-muted">{movie.release_date} 개봉</small></p> <p className="card-text text-center"><small className="text-muted">{movie.release_date} 개봉</small></p>
</div> </div>
<Link to={{ <Link to={{
......
...@@ -30,7 +30,7 @@ const MovieChart = () => { ...@@ -30,7 +30,7 @@ const MovieChart = () => {
<div className="row row-cols-1 row-cols-md-4 g-4"> <div className="row row-cols-1 row-cols-md-4 g-4">
<MovieCard list={TMDB_TopRated_Data} /> <MovieCard list={TMDB_TopRated_Data} />
</div> </div>
: <h2 className="text-white text-center p-5">영화정보를 로딩중입니다!</h2> : <h2 className="text-white text-center p-5"> </h2>
} }
</> </>
) )
......
...@@ -44,7 +44,7 @@ const MovieComing = () => { ...@@ -44,7 +44,7 @@ const MovieComing = () => {
<div className="card-body text-light"> <div className="card-body text-light">
{movie.adult ? <image src="/images/19.png" /> : <></>} {movie.adult ? <image src="/images/19.png" /> : <></>}
<div className={`h4 card-title text-center ${styles.title}`}>{movie.title}</div> <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 ${styles.txt}`}>{movie.runtime}</p>
<p className="card-text text-center"><small className="text-muted">{movie.release_date} 개봉</small></p> <p className="card-text text-center"><small className="text-muted">{movie.release_date} 개봉</small></p>
</div> </div>
<Link to={{ <Link to={{
...@@ -56,7 +56,7 @@ const MovieComing = () => { ...@@ -56,7 +56,7 @@ const MovieComing = () => {
</div> </div>
))} ))}
</div> </div>
: <h2 className="text-white text-center p-5">영화정보를 로딩중입니다!</h2> : <h2 className="text-white text-center p-5"> </h2>
} }
</> </>
) )
......
...@@ -26,7 +26,7 @@ const SearchResult = () => { ...@@ -26,7 +26,7 @@ const SearchResult = () => {
} }
return ( return (
<> <div className="container">
{result.length !== 0 ? ( {result.length !== 0 ? (
<> <>
<h3 className="text-white text-center my-5">'{title}' 관한 검색 결과입니다.</h3> <h3 className="text-white text-center my-5">'{title}' 관한 검색 결과입니다.</h3>
...@@ -36,7 +36,7 @@ const SearchResult = () => { ...@@ -36,7 +36,7 @@ const SearchResult = () => {
</> </>
) : <h3 className="text-white text-center my-5 vh-100" style={{ wordBreak: "keep-all" }}>'{title}' 관한 검색 결과가 존재하지 않습니다.</h3> ) : <h3 className="text-white text-center my-5 vh-100" style={{ wordBreak: "keep-all" }}>'{title}' 관한 검색 결과가 존재하지 않습니다.</h3>
} }
</> </div>
) )
} }
......
import { useState, useEffect } from 'react' import { useRef, useState, useEffect } from 'react'
import axios from "axios" import axios from "axios"
import catchErrors from "../utils/catchErrors" import catchErrors from "../utils/catchErrors"
// import InfoModal from "./InfoModal" // import InfoModal from "./InfoModal"
// const { kakao } = window; const { kakao } = window;
const options = {
center: new kakao.maps.LatLng(37.365264512305174, 127.10676860117488),
level: 3
};
const TheaterInfo = () => { const TheaterInfo = () => {
// if (kakao) { const container = useRef(null)
// console.log("kakao") const [cinemaInfo, setCinemaInfo] = useState()
// 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({ const [currentInfo, setCurrentInfo] = useState({
name: "init", name: "init",
title: "init", title: "init",
...@@ -49,23 +22,48 @@ const TheaterInfo = () => { ...@@ -49,23 +22,48 @@ const TheaterInfo = () => {
}, []) }, [])
useEffect(() => { useEffect(() => {
if (currentInfo.title === "parking") { if (currentInfo.title === "address") {
setTabContent(<div>{currentInfo.information}</div>) // 지도를 담을 영역의 DOM 레퍼런스
} else if (currentInfo.title === "address") { const container = document.getElementById("map");
setTabContent(<div id="map">{currentInfo.information}</div>) // center옵션은 지도를 생성하는데 반드시 필요하며 파라미터는 위경도좌표이다. (위도,경도 순서)
} else { // level옵션은 지도의 확대, 축소 정도이다.
setTabContent(<div>{currentInfo.information}</div>) const options = {
center: new kakao.maps.LatLng(33.450701, 126.570667),
level: 3,
};
// 지도 생성 및 객체 리턴
const map = new kakao.maps.Map(container, options);
const geocoder = new kakao.maps.services.Geocoder();
// 주소로 좌표를 검색합니다
geocoder.addressSearch(`${cinemaInfo.address}`, 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="color:black; width:150px;text-align:center;padding:6px 0;">Butter Studio</div>'
});
infowindow.open(map, marker);
// 지도의 중심을 결과값으로 받은 위치로 이동시킵니다
map.setCenter(coords);
}
});
} }
}, [currentInfo]) }, [currentInfo]);
async function getTheaterInfo() { async function getTheaterInfo() {
try { try {
const response = await axios.get('/api/info/cinema') const response = await axios.get('/api/info/cinema')
const response2 = await axios.get('/api/theater') const response2 = await axios.get('/api/theater')
setTheaterInfo({...response.data, theaterNum:response2.data.length}) setCinemaInfo({ ...response.data, theaterNum: response2.data.length })
setCurrentInfo({ setCurrentInfo({
name:"대중교통 안내", name: "대중교통 안내",
title:"transportation", title: "transportation",
information: response.data.transportation information: response.data.transportation
}) })
} catch (error) { } catch (error) {
...@@ -84,37 +82,39 @@ const TheaterInfo = () => { ...@@ -84,37 +82,39 @@ const TheaterInfo = () => {
return ( return (
<> <>
{theaterInfo ? {cinemaInfo ?
<div> <div>
{/* {console.log(currentInfo)} */} {/* {console.log(currentInfo)} */}
{console.log(theaterInfo)} {console.log(cinemaInfo)}
<h2 className="m-5">{theaterInfo.cinemaName}</h2> <h2 className="m-5">{cinemaInfo.cinemaName}</h2>
<div className="my-3 text-center"> <div className="my-3 text-center">
<img src="/images/movieTheater.jpg" style={{ width: "80%" }} /> <img src="/images/movieTheater.jpg" style={{ width: "80%" }} />
</div> </div>
<div className="m-3"> 상영관 : {theaterInfo.theaterNum}</div> <div className="m-3"> 상영관 : {cinemaInfo.theaterNum}</div>
<div className="m-3">{theaterInfo.address}</div> <div className="m-3">{cinemaInfo.address}</div>
<div className="row justify-content-sm-center py-5"> <div className="row justify-content-sm-center py-5">
<div className="col-sm-4 text-end"> <div className="col-sm-4 text-end">
<div className="m-2"> <div className="m-2">
<img src="/images/icon-bus.png" style={{ width: "35px" }} /> <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 className="px-3" name="대중교통 안내" id="transportation" value={cinemaInfo.transportation} type="button" onClick={handleClick} style={{ background: "black", borderLeftColor: "black", borderTopColor: "black", borderBottomColor: "black", color: "white", borderRightColor: currentInfo.title === "transportation" ? "white" : "black" }}>대중교통 안내
</button> </button>
</div> </div>
<div className="m-2"> <div className="m-2">
<img src="/images/icon-car.png" style={{ width: "35px" }} /> <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 className="px-3" name="자가용/주차 안내" id="parking" value={cinemaInfo.parking} type="button" onClick={handleClick} style={{ background: "black", borderLeftColor: "black", borderTopColor: "black", borderBottomColor: "black", color: "white", borderRightColor: currentInfo.title === "parking" ? "white" : "black" }}>자가용/주차 안내
</button> </button>
</div> </div>
<div className="m-2"> <div className="m-2">
<img src="/images/icon-map.png" style={{ width: "35px" }} /> <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 className="px-3" name="지도보기" id="address" value={cinemaInfo.address} type="button" onClick={handleClick} style={{ background: "black", borderLeftColor: "black", borderTopColor: "black", borderBottomColor: "black", color: "white", borderRightColor: currentInfo.title === "address" ? "white" : "black" }}>지도보기
</button> </button>
</div> </div>
</div> </div>
<div className="col-sm-6"> <div className="col-sm-6">
<div className="m-2"> <div className="m-2">
{tabContent} <div id="parking" style={{ display: currentInfo.title === "parking" ? 'block' : 'none' }}>{currentInfo.information}</div>
<div id="map" ref={container} style={{ width: "400px", height: "300px", display: currentInfo.title === "address" ? 'block' : 'none' }}></div>
<div id="transportaion" style={{ display: currentInfo.title === "transportation" ? 'block' : 'none' }} >{currentInfo.information}</div>
</div> </div>
</div> </div>
</div> </div>
......
import { useState, useEffect } from "react"
import BoxOffice from "../components/BoxOffice"; import BoxOffice from "../components/BoxOffice";
import Collection from "../components/Collection"; import Collection from "../components/Collection";
import Footer from "../components/Footer"; import Footer from "../components/Footer";
import movieApi from '../apis/movie.api'
import catchErrors from '../utils/catchErrors.js'
const HomePage = () => { const HomePage = () => {
const [TMDB_TopRated_Data, setTMDB_TopRated_Data] = useState([])
const [error, setError] = useState("")
const category = "popular"
useEffect(() => {
getTMDB_TopRated()
}, [])
async function getTMDB_TopRated() {
try {
setError("")
const data = await movieApi.getListByCategoryfromDB(category)
console.log("sdad==", data)
data.sort(function (a, b) {
return b.popularity - a.popularity
})
setTMDB_TopRated_Data([...data])
} catch (error) {
catchErrors(error, setError)
}
}
return ( return (
<> <>
<BoxOffice /> <BoxOffice TMDB_TopRated_Data={TMDB_TopRated_Data} />
<Collection /> <Collection TMDB_TopRated_Data={TMDB_TopRated_Data} />
<Footer /> <Footer />
</> </>
) )
......
...@@ -7,10 +7,9 @@ const MoviePage = ({ location }) => { ...@@ -7,10 +7,9 @@ const MoviePage = ({ location }) => {
const [movieInfo, setMovieInfo] = useState({ const [movieInfo, setMovieInfo] = useState({
...location.state, ...location.state,
stillCuts: [], stillCuts: [],
cast: "", cast: [],
director: "", director: [],
// genres: [], // attendance: ""
attendance: ""
}) })
const [state, setState] = useState(0) const [state, setState] = useState(0)
...@@ -24,23 +23,14 @@ const MoviePage = ({ location }) => { ...@@ -24,23 +23,14 @@ const MoviePage = ({ location }) => {
const still = images.backdrops.map(el => el.file_path) const still = images.backdrops.map(el => el.file_path)
const credits = await movieApi.getCreditsfromTM(movieInfo.id) const credits = await movieApi.getCreditsfromTM(movieInfo.id)
const castsInfo = credits.cast.map(el => el.name) 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) console.log(castsInfo)
const directorsInfo = await credits.crew.filter(element => element.job === "Director") const directorsInfo = await credits.crew.filter(element => element.job === "Director").map(el=>el.name)
const directors = directorsInfo.reduce((acc, cur, idx) => {
if (idx !== 0) return acc + ', ' + cur.name
else return acc + cur.name
}, "")
console.log("directorInfo=", directorsInfo) console.log("directorInfo=", directorsInfo)
setMovieInfo({ setMovieInfo({
...movieInfo, ...movieInfo,
stillCuts: still, stillCuts: still,
cast: casts, cast: castsInfo,
director: directors director: directorsInfo
}) })
} catch (error) { } catch (error) {
console.log(error) console.log(error)
...@@ -76,11 +66,18 @@ const MoviePage = ({ location }) => { ...@@ -76,11 +66,18 @@ const MoviePage = ({ location }) => {
<div className="col-sm-3 mb-5"> <div className="col-sm-3 mb-5">
<img className="img-thumbnail" src={`https://image.tmdb.org/t/p/original${movieInfo.poster_path}`} alt="영화포스터" /> <img className="img-thumbnail" src={`https://image.tmdb.org/t/p/original${movieInfo.poster_path}`} alt="영화포스터" />
</div> </div>
<div className="col-sm-6 " style={{ color: "white" }}> <div className="col-sm-6" style={{ color: "white" }}>
<h1 className="pb-3">{movieInfo.title}</h1> <h1 className="pb-3">{movieInfo.title}</h1>
<p>예매율: 0% 누적관객수: {movieInfo.attendance}</p> <p>예매율:{Math.round((movieInfo.ticket_sales / (movieInfo.totalReservationRate.totalReservationRate||1)) * 100)}% 누적관객수: {movieInfo.ticket_sales}</p>
<p>감독: {movieInfo.director}</p> {movieInfo.director || movieInfo.cast
<p>출연: {movieInfo.cast}</p> ?
<>
<p>감독: {movieInfo.director.map(el => el)+' '}</p>
<p>출연: {movieInfo.cast.slice(0, 5).map(el => el)+' '}</p>
</>
:
<></>
}
<p>장르: {movieInfo.genres.reduce((acc, cur, idx) => { <p>장르: {movieInfo.genres.reduce((acc, cur, idx) => {
if (idx !== 0) return acc + ', ' + cur.name if (idx !== 0) return acc + ', ' + cur.name
else return acc + cur.name else return acc + cur.name
......
...@@ -71,7 +71,7 @@ const Payment = ({ location }) => { ...@@ -71,7 +71,7 @@ const Payment = ({ location }) => {
if (user.role === "member") { if (user.role === "member") {
const response = await reservationApi.save({ const response = await reservationApi.save({
userType: "member", userType: "member",
payment: "카카오페이", // payment: "카카오페이",
user: userInfo.id, user: userInfo.id,
...ticketInfo, ...ticketInfo,
timetable: 1 timetable: 1
...@@ -98,7 +98,7 @@ const Payment = ({ location }) => { ...@@ -98,7 +98,7 @@ const Payment = ({ location }) => {
userType: "guest", userType: "guest",
user: guestID, user: guestID,
...ticketInfo, ...ticketInfo,
payment: "카카오페이", // payment: "카카오페이",
timetable: 1 timetable: 1
}) })
const responsekakao = await axios.post('/api/kakaopay/test/single', { const responsekakao = await axios.post('/api/kakaopay/test/single', {
......
...@@ -119,9 +119,9 @@ const TicketingSeatPage = ({ location }) => { ...@@ -119,9 +119,9 @@ const TicketingSeatPage = ({ location }) => {
</div> </div>
</div> </div>
<div className="row justify-content-center my-3"> <div className="row justify-content-center my-3">
<div className="col-sm-6 mb-4 text-center"> <div className="col-sm-4 mb-4">
<div className="row text-end justify-content-sm-end"> <div className="row text-end justify-content-sm-end">
<div className="col-sm-6 me-5"> <div className="col-sm-6 me-5" >
<div> <div>
<span className="my-1">일반</span> <span className="my-1">일반</span>
<span> <span>
...@@ -148,7 +148,7 @@ const TicketingSeatPage = ({ location }) => { ...@@ -148,7 +148,7 @@ const TicketingSeatPage = ({ location }) => {
</div> </div>
</div> </div>
</div> </div>
<div className="col-sm-6 mb-4 p-2 text-center" style={{ backgroundColor: '#252525' }}> <div className="col-sm-5 mb-4 p-2 text-center" style={{ backgroundColor: '#252525' }}>
<div>{ticketInfo.cinema} | {ticketInfo.selectedTheater}</div> <div>{ticketInfo.cinema} | {ticketInfo.selectedTheater}</div>
<div>{ticketInfo.title}</div> <div>{ticketInfo.title}</div>
<div>{ticketInfo.time}</div> <div>{ticketInfo.time}</div>
......
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