diff --git a/.gitignore b/.gitignore index 362797ac983d6ad6efb5b1650aba26966c43bbc6..f596774af503c5155320b3504911378ce5af499a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /node_modules .env.development -.env \ No newline at end of file +.env +upload/ \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index 38d0bb594c1204eb4ab3bcb30154d7ace84d1c85..046e20d9f3b9bf673c63cf4ecb7badfb580d3598 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -4419,9 +4419,9 @@ } }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" }, "cookie-signature": { "version": "1.0.6", @@ -6510,6 +6510,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/client/public/images/19.png b/client/public/images/19.png new file mode 100644 index 0000000000000000000000000000000000000000..55861dc24895bb5ed4272b4e05297a8be1e617d0 Binary files /dev/null and b/client/public/images/19.png differ diff --git a/client/public/images/icon-bus.png b/client/public/images/icon-bus.png new file mode 100644 index 0000000000000000000000000000000000000000..8bf2124942dbf240798f16210e91bf7005f49a7e Binary files /dev/null and b/client/public/images/icon-bus.png differ diff --git a/client/public/images/icon-car.png b/client/public/images/icon-car.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3d18315b6a01fa7b48cc35a74a634e8938d1f2 Binary files /dev/null and b/client/public/images/icon-car.png differ diff --git a/client/public/images/movieTheater.jpg b/client/public/images/movieTheater.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e8ce553dd18c6c9133da1075980d0b59addd7268 Binary files /dev/null and b/client/public/images/movieTheater.jpg differ diff --git a/client/src/App.js b/client/src/App.js index 1ce9d6f9b0fa73c68bf90571d8598683adb78590..b3f0c6057d18b08a33e0f586aeb3d6d7c0596bad 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -14,7 +14,8 @@ import AdminPage from "./pages/AdminPage/AdminPage"; import TicketingPage from "./pages/TicketingPage"; import TicketingSeatPage from './pages/TicketingSeatPage' import SearchPage from "./pages/SearchPage"; -import Payment from "./pages/PaymentPage"; +import Payment from "./pages/PaymentPage/PaymentPage"; +import PaymentCompletePage from "./pages/PaymentCompletePage"; function App() { @@ -46,4 +47,4 @@ function App() { ); } -export default App; +export default App; \ No newline at end of file diff --git a/client/src/apis/auth.api.js b/client/src/apis/auth.api.js index 48404159fc855bd94e87eaa3615fe16e2942ceed..27aa753da69560b99e9a5b02011be97ed6942f1f 100644 --- a/client/src/apis/auth.api.js +++ b/client/src/apis/auth.api.js @@ -1,6 +1,11 @@ import axios from "axios"; import { baseUrl } from "../utils/baseUrl.js"; -import config from "../utils/clientConfig.js"; + +const getUser = async () => { + const url = `${baseUrl}/api/auth/user` + const { data } = await axios.get(url) + return data +} const login = async (login) => { const payload = login; @@ -9,41 +14,61 @@ const login = async (login) => { }; const logout = async () => { - alert("로그아웃되었습니다."); - localStorage.removeItem(config.loginUser); - await axios.get(`${baseUrl}/api/auth/logout`); + const { data } = await axios.get(`${baseUrl}/api/auth/logout`); + return data }; const signup = async (user) => { - const url = `${baseUrl}/api/auth/signup` - await axios.post(url, user) + const url = `${baseUrl}/api/auth/signup`; + const { data } = await axios.post(url, user); + return data +} + +const confirmMbnum = async (phone) => { + const url = `${baseUrl}/api/auth/phone/${phone}` + const { data } = await axios.post(url); + return data +} + +const confirmNum = async (confirmNum) => { + const url = `${baseUrl}/api/auth/num` + const { data } = await axios.post(url, confirmNum); + return data } -const compareId = async (userId) => { - const url = `${baseUrl}/api/auth/${userId}` +const profile = async (formData) => { + const url = `${baseUrl}/api/auth/profile` + const { data } = await axios.post(url, formData) + return data +} +const getMember = async () => { + const url = `${baseUrl}/api/auth/member` const { data } = await axios.get(url) return data -} +} -const confirmMbnum = async (id,token) => { - const url = `${baseUrl}/api/auth/${id}/${token}` +const comparePw = async (pw) => { + const url = `${baseUrl}/api/auth/pw/${pw}` const { data } = await axios.get(url) return data } -const getNickName = async(id) =>{ - const url = `${baseUrl}/api/auth/${id}` - console.log("url : ", url); - const { nickName } = await axios.get(url) - return nickName +const modifyUser = async (user) => { + const url = `${baseUrl}/api/auth/modify` + const { data } = await axios.post(url, user) + return data } const authApi = { + getUser, login, logout, signup, - compareId, confirmMbnum, - getNickName, + confirmNum, + profile, + getMember, + comparePw, + modifyUser, }; export default authApi \ No newline at end of file diff --git a/client/src/apis/movie.api.js b/client/src/apis/movie.api.js index abe991afd154d0515e4fa80bdd329531385fd0a0..e6d218e2c7070d33a3a0a76dbf096777e37ac62b 100644 --- a/client/src/apis/movie.api.js +++ b/client/src/apis/movie.api.js @@ -11,11 +11,6 @@ const getAllfromTM = async (pageNum) => { return data } -const getMoviesfromTM = async (category) => { - const response = await axios.get(`${baseUrl}/api/movie/showmovies/${category}`) - return response.data -} - const getMovieInfofromTM = async (id) => { const movieId = id const response = await axios.get(`${TMDBUrl}/${movieId}?api_key=${process.env.REACT_APP_TMDB_API_KEY}&language=ko-KR`) @@ -28,13 +23,13 @@ const getImagesfromTM = async (id) => { return response.data } -const getCreditsfromTM = async (id) =>{ +const getCreditsfromTM = async (id) => { const movieId = id const response = await axios.get(`${TMDBUrl}/${movieId}/credits?api_key=${process.env.REACT_APP_TMDB_API_KEY}`) return response.data } -const getVideosfromTM = async (id) =>{ +const getVideosfromTM = async (id) => { const movieId = id const response = await axios.get(`${TMDBUrl}/${movieId}/videos?api_key=${process.env.REACT_APP_TMDB_API_KEY}`) return response.data.results @@ -45,6 +40,11 @@ const getListfromDB = async () => { return data } +const getListByCategoryfromDB = async (category) => { + const { data } = await axios.get(`${baseUrl}/api/movie/movielist/${category}`) + return data +} + const submit = async (movieId) => { const { data } = await axios.post(`${baseUrl}/api/movie/${movieId}`) return data @@ -68,7 +68,7 @@ const search = async ({ type, keyword }, pageNum) => { const movieApi = { getAllfromTM, - getMoviesfromTM, + getListByCategoryfromDB, getMovieInfofromTM, getImagesfromTM, getCreditsfromTM, diff --git a/client/src/components/Admin/TicketFeeTable.js b/client/src/components/Admin/TicketFeeTable.js index 184cdbdb4b206e0e747091174b819751ccce2aac..7f591a0ce3700ebc74a3510e2cebb16574db3ac2 100644 --- a/client/src/components/Admin/TicketFeeTable.js +++ b/client/src/components/Admin/TicketFeeTable.js @@ -1,11 +1,14 @@ 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 = ({ selectTheater, setEditFee, formRef }) => { const [ticketFee, setTicketFee] = useState([]) const [error, setError] = useState("") + const { user } = useAuth() + useEffect(() => { if (selectTheater !== 0) getOne(selectTheater) @@ -48,7 +51,7 @@ const TicketFeeTable = ({ selectTheater, setEditFee, formRef }) => { } return ( - +
@@ -57,7 +60,7 @@ const TicketFeeTable = ({ selectTheater, setEditFee, formRef }) => { - + {user.role === "admin" ? : <>} @@ -70,12 +73,15 @@ const TicketFeeTable = ({ selectTheater, setEditFee, formRef }) => { - + {user.role === "admin" + ? + + : <>} @@ -107,12 +113,15 @@ const TicketFeeTable = ({ selectTheater, setEditFee, formRef }) => { - + {user.role === "admin" + ? + + : <>} ) : diff --git a/client/src/components/BoxOffice/BoxOffice.js b/client/src/components/BoxOffice/BoxOffice.js index 1cabc69c8747b92ec082386f0918c648e808a45d..a7c3f776e7eca83deaed5d57d51318ad535e9d18 100644 --- a/client/src/components/BoxOffice/BoxOffice.js +++ b/client/src/components/BoxOffice/BoxOffice.js @@ -1,147 +1,186 @@ import { useState, useEffect } from "react" -import movieApi from '../../apis/movie.api.js' -import "./box-office.module.css" -const BoxOffice = () => { - 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) - } - } +const BoxOffice = ({TMDB_TopRated_Data}) => { return (
- {console.log(TMDB_TopRated_Data)} -
-

Bootstrap Multi Slide Carousel

-
-
-
-
-
-
-
- -
-
Slide 1
-
-
-
-
-
-
-
- -
-
Slide 2
-
-
-
-
-
-
-
- -
-
Slide 3
-
-
-
-
-
-
-
- -
-
Slide 4
-
-
-
-
-
-
-
- -
-
Slide 5
-
-
-
-
-
-
-
- -
-
Slide 6
-
-
+ {/*
+
+ {TMDB_TopRated_Data.length>0 + ? + TMDB_TopRated_Data.map((movie, index) => { +
+ {console.log(movie.poster_path)} + Movie Poster
+ }) + : +
+ {console.log("스틸컷 불러오기 오류")} + 등록된 스틸컷이 없습니다.
- - - - - - -
-
-
advances one slide at a time
-
-
-
-
- {TMDB_TopRated_Data ? - TMDB_TopRated_Data.map((moviePoster, index) => ( -
-
-
-
- -
-
-
-
- )) - : (
영화를 불러올 수 없습니다:(
)} -
- - - - - - + }
-
+ + +
*/} +
) } -export default BoxOffice \ No newline at end of file +export default BoxOffice + +// import { useState, useEffect } from "react" +// import movieApi from '../../apis/movie.api.js' +// import "./box-office.module.css" + +// const BoxOffice = () => { +// 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 ( +//
+// {console.log(TMDB_TopRated_Data)} +//
+//

Bootstrap Multi Slide Carousel

+//
+//
+//
+//
+//
+//
+//
+// +//
+//
Slide 1
+//
+//
+//
+//
+//
+//
+//
+// +//
+//
Slide 2
+//
+//
+//
+//
+//
+//
+//
+// +//
+//
Slide 3
+//
+//
+//
+//
+//
+//
+//
+// +//
+//
Slide 4
+//
+//
+//
+//
+//
+//
+//
+// +//
+//
Slide 5
+//
+//
+//
+//
+//
+//
+//
+// +//
+//
Slide 6
+//
+//
+//
+//
+// +// +// +// +// +// +//
+//
+//
advances one slide at a time
+//
+//
+//
+//
+// {TMDB_TopRated_Data ? +// TMDB_TopRated_Data.map((moviePoster, index) => ( +//
+//
+//
+//
+// +//
+//
+//
+//
+// )) +// : (
영화를 불러올 수 없습니다:(
)} +//
+// +// +// +// +// +// +//
+//
+//
+// ) +// } + +// export default BoxOffice \ No newline at end of file diff --git a/client/src/components/BoxOffice/box-office.module.css b/client/src/components/BoxOffice/box-office.module.css deleted file mode 100644 index 6e44ad3882525d170ea5e8f3217c99b8c6c69d44..0000000000000000000000000000000000000000 --- a/client/src/components/BoxOffice/box-office.module.css +++ /dev/null @@ -1,34 +0,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); -} - diff --git a/client/src/components/BoxOffice/mystyle.css b/client/src/components/BoxOffice/mystyle.css deleted file mode 100644 index b4c221b29fe5ba4478cd6a426d5c4d2787a03c25..0000000000000000000000000000000000000000 --- a/client/src/components/BoxOffice/mystyle.css +++ /dev/null @@ -1,34 +0,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); -} diff --git a/client/src/components/Collection.js b/client/src/components/Collection.js index 56bba0220c9f16179f8d36760cd25c177f020343..65a21359f7b9c47f6b2bb133fa29499d84378e27 100644 --- a/client/src/components/Collection.js +++ b/client/src/components/Collection.js @@ -1,10 +1,46 @@ -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) { + 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) + } + } return ( <>

Movie Collection

-
-
- +
+
+ {videoUrls.length > 0 + ? +
+
+ +
+
+ + :
예고편 정보가 존재하지 않습니다.
} +
+ {TMDB_TopRated_Data.length > 0 + ? + + : +
+ }
) diff --git a/client/src/components/CountButton.js b/client/src/components/CountButton.js index 2a3e11b30fb70f609d1b8a372f819ba33c7cfa03..ca00a3d2a25e7bb89dc8f3a029cef94c7a8c18ef 100644 --- a/client/src/components/CountButton.js +++ b/client/src/components/CountButton.js @@ -1,26 +1,25 @@ -import {useState} from 'react' -const CountButton = (props) => { - const name = props.name +const CountButton = ({name, count, setCount}) => { function handleCount(event) { if (event.target.name === "backbutton") { - props.setCount({...props.count, [name] :props.count[name] - 1}) + setCount({...count, [name] :count[name] - 1}) } else if (event.target.name === "forwardbutton") { - props.setCount({...props.count, [name] :props.count[name] + 1}) + setCount({...count, [name] :count[name] + 1}) } else { - props.setCount({...props.count, [name] :event.target.value}) + setCount({...count, [name] :event.target.value}) } } + return ( -
+ <> - + -
+ ) } diff --git a/client/src/components/Kakaopay.js b/client/src/components/Kakaopay.js deleted file mode 100644 index f0a3e1d90574bb0b1e00cad7a0d0c87c48dd59ad..0000000000000000000000000000000000000000 --- a/client/src/components/Kakaopay.js +++ /dev/null @@ -1,37 +0,0 @@ -import axios from 'axios' - -const Kakaopay = (props) => { - async function handleClick() { - try { - const response = await axios.post('/api/kakaopay/test/single', { - cid: 'TC0ONETIME', - partner_order_id: 'orderNum', - partner_user_id: 'userName', - item_name: props.ticketInfo.title, - quantity: props.ticketInfo.teenager+props.ticketInfo.adult+props.ticketInfo.elderly, - total_amount: props.ticketInfo.teenager * 7000 + props.ticketInfo.adult * 8000 + props.ticketInfo.elderly * 6000, - vat_amount: 0, - tax_free_amount: 0, - approval_url: 'http://localhost:3000/', - fail_url: 'http://localhost:3000/', - cancel_url: 'http://localhost:3000/', - }) - console.log(response.data) - if (response.data) { - window.location.href = response.data.redirect_url - } - } catch (error) { - console.log(error) - } - } - - return ( - <> - - - ) -} - -export default Kakaopay \ No newline at end of file diff --git a/client/src/components/Login/Login.js b/client/src/components/Login/Login.js index e152f6f62330055336e3a8b4794371bb5956843b..da31480d857a9422900eefe0a2316283ea104367 100644 --- a/client/src/components/Login/Login.js +++ b/client/src/components/Login/Login.js @@ -1,21 +1,18 @@ import { useState } from "react"; -import styles from "./login.module.scss"; import { Redirect } from "react-router-dom"; +import { useAuth } from "../../context/auth_context.js"; import catchErrors from "../../utils/catchErrors"; -import {useAuth} from "../../context/auth_context.js"; +import styles from "./login.module.scss"; const Login = () => { - const {login, loading} = useAuth(); - //useState를 이용해서 각 state 생성 및 초기값 저장 - const [state, setState] = useState(true); // 이 줄은 css에 해당하는 state - //state변수 지정 하지만 이 변수는 react에 의해 없어지지 않음, 그리고 그 다음 변수는 state변수를 갱신해주는 함수 + const { login, loading } = useAuth(); + const [state, setState] = useState(true); const [user, setUser] = useState({ id: '', password: '' }); const [error, setError] = useState(""); const [success, setSuccess] = useState(false); - const [guest, setGuset] = useState({ guestName: '', gusetBirthday: '', @@ -23,10 +20,7 @@ const Login = () => { guestPassword: '' }) - //input태그에 걸려있는 onchange에서 실행할 함수설정 const handleLoginOnChange = (e) => { - // ... 전개 연산자 - // 현재 state에 방금 변화한 값을 다시 저장함 setUser({ ...user, [e.target.name]: e.target.value @@ -41,9 +35,12 @@ const Login = () => { } const requestServer = async (data) => { - if(data === user){ - await login(data); - }else{ + if (data === user) { + const success = await login(data); + if (success) { + setSuccess(true); + alert('로그인이 완료되었습니다.') + } } } @@ -51,11 +48,8 @@ const Login = () => { e.preventDefault(); try { setError(""); - console.log(e.target.name); if (e.target.name === "login") { requestServer(user); - alert('로그인이 완료되었습니다.') - setSuccess(true); } else { requestServer(guest); @@ -86,7 +80,6 @@ const Login = () => {
- {/* 로그인 */}
@@ -95,7 +88,6 @@ const Login = () => { 회원이 아니십니까?
- {/* 비회원예매 학인 */}
@@ -103,7 +95,6 @@ const Login = () => { -

※ 비회원 정보 오 입력 시 예매 내역 확인/취소 및 티켓 발권이 어려울 수 있으니 다시 한번 확인해 주시기 바랍니다.

diff --git a/client/src/components/MovieCard/MovieCard.js b/client/src/components/MovieCard/MovieCard.js index 83d558ce0d133a13bb89bc8d891de7ac1e527222..05b50cc34ef9abb3612e2b8d889e943822e1ba5f 100644 --- a/client/src/components/MovieCard/MovieCard.js +++ b/client/src/components/MovieCard/MovieCard.js @@ -23,8 +23,9 @@ const MovieCard = ({ list }) => {
{movie.overview}
- {movie.title} -

예매율: {movie.ticket_sales}0% | {movie.runtime}분

+ {movie.adult? :<>} +
{movie.title}
+

예매율: {Math.round((movie.ticket_sales/(movie.totalReservationRate.totalReservationRate||1))*100)}% | {movie.runtime}분

{movie.release_date} 개봉

{ const [TMDB_TopRated_Data, setTMDB_TopRated_Data] = useState([]) const [error, setError] = useState("") @@ -16,8 +15,7 @@ const MovieChart = () => { async function getTMDB_TopRated() { try { setError("") - const data = await movieApi.getMoviesfromTM(category) - console.log("sdad==", data) + const data = await movieApi.getListByCategoryfromDB(category) setTMDB_TopRated_Data([...data]) } catch (error) { catchErrors(error, setError) @@ -30,7 +28,7 @@ const MovieChart = () => {
- :

영화정보를 로딩할 수 없습니다.

+ :

} ) diff --git a/client/src/components/MovieComing.js b/client/src/components/MovieComing.js index 21bf7165c5f1ca84141fc38b19ca68f82bc68959..dd4d3537809120c5141575b38acf4240eb8b3472 100644 --- a/client/src/components/MovieComing.js +++ b/client/src/components/MovieComing.js @@ -1,9 +1,8 @@ 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 movieApi from "../apis/movie.api.js" import catchErrors from '../utils/catchErrors.js' +import styles from './MovieCard/movie-card.module.scss' const MovieComing = () => { const [TMDB_UpComing_Data, setTMDB_UpComing_Data] = useState([]) @@ -17,7 +16,7 @@ const MovieComing = () => { async function getTMDB_UpComing() { try { setError("") - const response = await movieApi.getMoviesfromTM(category) + const response = await movieApi.getListByCategoryfromDB(category) setTMDB_UpComing_Data([...response]) } catch (error) { catchErrors(error, setError) @@ -28,7 +27,6 @@ const MovieComing = () => { <> {TMDB_UpComing_Data.length !== 0 ?
- {/* */} {TMDB_UpComing_Data.map(movie => (
{
{movie.overview}
- {movie.title} -

예매율: {movie.ticket_sales}0% | {movie.runtime}분

+ {movie.adult ? : <>} +
{movie.title}
+

{movie.runtime}분

{movie.release_date} 개봉

{
))}
- :

영화정보를 로딩할 수 없습니다.

+ :

} ) diff --git a/client/src/components/MyInfo/MyInfo.js b/client/src/components/MyInfo/MyInfo.js index 6d2df936d6fa7b6e29f576c099773e4e718424b7..d5216783610b746348fb51ea3c37a2695b5c892b 100644 --- a/client/src/components/MyInfo/MyInfo.js +++ b/client/src/components/MyInfo/MyInfo.js @@ -1,35 +1,317 @@ -import styles from "./my-info.module.scss"; -import { useAuth } from "../../context/auth_context"; import { useState, useEffect } from "react"; import authApi from "../../apis/auth.api"; +import catchErrors from "../../utils/catchErrors.js"; +import styles from "./my-info.module.scss"; const MyInfo = () => { - const { user } = useAuth(); - const [userNickName, setUserNickName] = useState(""); - - const getNickName = async (id) => { - console.log(id); - const nickname = await authApi.getNickName(id); - console.log(nickname); - return nickname - } + const [userNickName, setUserNickName] = useState("사용자"); + const [img, setImg] = useState(""); + const [profile, setProfile] = useState(""); + const [startTime, setStartTime] = useState(""); + const [page, setPage] = useState(true); + const [presentPw, setPresentPw] = useState(""); + const [loading, setLoading] = useState(false); + const [userRe, setUserRe] = useState({ + userName: "", + userEmail: "", + userNickName: "", + userMbnum: "", + userPassword: "", + userRePassword: "" + }) + const [confirmMb, setConfirmMb] = useState(false); + const [number, setNumber] = useState(null); + const [mbError, setMbError] = useState(false); + const [error, setError] = useState(""); + const [errorMsg, setErrorMsg] = useState({ + errorName: false, + errorEmail: false, + errorNickName: false, + errorMbnum: false, + errorPassword: false, + }) useEffect(() => { - let name = getNickName(user.id); - setUserNickName(name); + getMember(); }, []) + const getMember = async () => { + const member = await authApi.getMember(); + setUserNickName(member.nickname); + setProfile(member.img); + } + + const handlePwOnChange = (e) => { + setPresentPw(e.target.value) + } + + const handleUserOnChange = (e) => { + setUserRe({ + ...userRe, + [e.target.name]: e.target.value + }) + if (e.target.name === "userMbnum") { + setUserRe({ + ...userRe, + [e.target.name]: String(e.target.value) + }) + } + } + const enterKey = (e) => { + if (e.key === "Enter") { + handleOnSummitVerify(e); + } + } + + const handleOnChange = (e) => { + setImg(e.target.files[0]); + } + + const handleOnSummitForm = async (e) => { + e.preventDefault(); + try { + setError("") + const formData = new FormData(); + formData.append("image", img); + const image = await authApi.profile(formData); + setProfile(image.img); + } catch (error) { + catchErrors(error, setError); + } + } + + const handleOnSummitVerify = async (e) => { + e.preventDefault(); + try { + setError(""); + setLoading(true); + const pw = presentPw; + const confirmPw = await authApi.comparePw(pw); + if (confirmPw) { + setPage(false); + setPresentPw(""); + } else { + alert("비밀번호가 일치하지 않습니다."); + } + } catch (error) { + catchErrors(error, setError); + } finally { + setLoading(false); + } + } + + const handleOnClickMbnum = async (e) => { + e.preventDefault(); + try { + setStartTime(""); + setError(""); + setLoading(true); + const phone = userRe.userMbnum; + const message = await authApi.confirmMbnum(phone); + if (message.isSuccess) { + setMbError("보냄"); + setStartTime(message.startTime); + } + } catch (error) { + catchErrors(error, setError); + } finally { + setLoading(false); + } + } + + const handleOnChangeMb = (e) => { + setNumber(String(e.target.value)); + } + + const handleOnClickMbConfirm = async (e) => { + e.preventDefault(); + try { + setError(""); + setLoading(true); + const confirmNum = { userMbnum: userRe.userMbnum, number: number, startTime: startTime }; + const message = await authApi.confirmNum(confirmNum); + setMbError(message); + if (message === "성공") { + setConfirmMb(true); + console.log("인증완료"); + } + } catch (error) { + catchErrors(error, setError); + } finally { + setLoading(false); + } + } + + const validationPw = () => { + if (userRe.userPassword !== userRe.userRePassword) return false; + else return true; + } + + const handleOnSummit = async (e) => { + e.preventDefault(); + try { + setError(""); + setLoading(true); + let validPw = validationPw(); + if (confirmMb) { + if (validPw) { + const userData = userRe; + const error = await authApi.modifyUser(userData); + if (error === "성공") { + alert("회원정보수정에 성공하였습니다.") + } else { + setErrorMsg(error); + alert("형식에 맞게 다시 작성해주세요"); + } + } else { + throw new Error("비밀번호가 일치하지 않습니다."); + } + } else { + throw new Error("핸드폰 번호를 인증해주세요."); + } + } catch (error) { + catchErrors(error, setError); + } finally { + setLoading(false); + } + } + + const handleOnclickOut = (e) => { + setConfirmMb(false); + } + + const handleOnClick = (e) => { + e.preventDefault(); + handleOnclickOut(e); + setPage(true); + } + return ( -
- 마이페이지 -
- -
- {`${userNickName}`}님 반갑습니다! - + <> +
+ 마이페이지 +
+
+

프로필 변경

+ +
+
+ {`${userNickName}`}님 반갑습니다! + +
+
+
+ + -
+ ) } diff --git a/client/src/components/MyInfo/my-info.module.scss b/client/src/components/MyInfo/my-info.module.scss index 6cf65ac8ad7f8da76d65fee8509f83bc72981002..f80cf6c6888319eced88322f14ae16c4afa55898 100644 --- a/client/src/components/MyInfo/my-info.module.scss +++ b/client/src/components/MyInfo/my-info.module.scss @@ -1,7 +1,180 @@ -.title{ +.main { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; +} + +.title { + display: flex; + justify-content: center; + color: #FEDC00; + font-size: 2.5rem; + margin: 2rem 0; +} + +.confirm { + color: black; + padding-right: 8px; + text-align: center; + display: flex; + align-items: center; +} + +.input2 { + width: 9.01rem; +} + +.userName { + color: white; + font-size: 1.5rem; +} + +.contents { + display: flex; + width: 100%; + justify-content: spa; + align-items: center; + padding-top: 5px; +} + +.signupLabel { + color: black; + padding-right: 8px; + text-align: left; +} + +.input_file_button { + padding: 6px 25px; + background-color: #FF6600; + border-radius: 4px; + color: white; + cursor: pointer; +} + +.inputContent { + display: flex; + justify-content: space-around; + align-items: center; + margin: 1rem 0; +} + +.box { + width: 12rem; + margin: 0px 3rem; + position: relative; + display: flex; + align-items: center; + + &:hover { + display: block; + } +} + +.hoverTxt { + display: none; + position: absolute; + top: 4rem; + left: 1.6rem; + color: #FEDC00; + font-size: 1.5rem; +} + +.box:hover .hoverTxt { + display: block; +} + +.profile { + width: 10rem; + height: 10rem; + + &:hover { + opacity: 0.5; + } +} + +.input { + margin: 0.5rem 0 0 0; + padding: 0.5rem 0 0.5rem 0; + border-radius: 3px; + text-align: center; +} + +input[type=password] { + font-family: 'Courier New', Courier, monospace; +} + +input::placeholder { + font-family: 'HangeulNuriB' +} + +.inputSize { + width: 15.3rem; +} + +input[type="number"]::-webkit-outer-spin-button, +input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; +} + +.butterYellowAndBtn { + color: black; + font-size: 1rem; + background-color: #FEDC00; + border: 1px solid black; + text-align: center; +} + +.btnHover:hover { + background-color: black; + color: #FEDC00; + transition: ease-out; + border: 1px solid #FEDC00; + text-align: center; +} + +.passwordConfirmError { + margin-bottom: 0; + margin-top: 0.5rem; + margin-right: 3rem; + text-align: end; + font-size: 13px; + font-weight: bold; + color: black; +} + +@media (max-width: 576px) { + .title { display: flex; justify-content: center; color: #FEDC00; - font-size: 25px; - margin: 1rem 0; + font-size: 2rem; + margin: 2rem 0; + } + + .box { + width: 8rem; + margin: 0px 1rem; + position: relative; + } + + .profile { + width: 8rem; + height: 8rem; + } + + .userName { + color: white; + font-size: 1.1rem; + } + + .hoverTxt { + display: none; + position: absolute; + top: 3.2rem; + left: 1.7rem; + color : #FEDC00; + font-size: 1rem; + } } \ No newline at end of file diff --git a/client/src/components/Navs/MainNav.js b/client/src/components/Navs/MainNav.js index 237847698fc2a47aa6d2d42d12c0b161d49cf70b..f3980193d5171f9df71a64072f3d47835f274fb1 100644 --- a/client/src/components/Navs/MainNav.js +++ b/client/src/components/Navs/MainNav.js @@ -1,5 +1,6 @@ import { useState } from "react"; -import { useHistory } from "react-router"; +import { Link, useHistory } from "react-router-dom"; + import Search from "../Search"; const MainNav = () => { @@ -12,9 +13,9 @@ const MainNav = () => { return ( ) diff --git a/client/src/components/Navs/SubNav.js b/client/src/components/Navs/SubNav.js index e3bf48067b3ed96f7c2b50a3498f35b42e676328..e0d278ed82afc18d3631cab62e9ffb672257a033 100644 --- a/client/src/components/Navs/SubNav.js +++ b/client/src/components/Navs/SubNav.js @@ -1,22 +1,23 @@ import { Link } from "react-router-dom"; import { useAuth } from "../../context/auth_context.js" + const SubNav = () => { const { user, logout } = useAuth(); return ( - <> {(user) ? - : - ) } + export default SubNav \ No newline at end of file diff --git a/client/src/components/ReservationDetails/ReservationDetails.js b/client/src/components/ReservationDetails/ReservationDetails.js new file mode 100644 index 0000000000000000000000000000000000000000..a0610485b368f8cfe7c8a9861192bcdaa01b573e --- /dev/null +++ b/client/src/components/ReservationDetails/ReservationDetails.js @@ -0,0 +1,28 @@ +import styles from "./reservation-details.module.scss"; + +const ReservationDetails = () => { + return ( +
+
나의 예매 내역
+
+
+
+ 영화 포스터 +
+
+ 영화제목 + 예매확인번호 + 예매날짜 + 상영관 + 좌석정보 + 결제금액 + 결제수단 +
+
+
+
나의 리뷰
+
+ ) +} + +export default ReservationDetails \ No newline at end of file diff --git a/client/src/components/ReservationDetails/index.js b/client/src/components/ReservationDetails/index.js new file mode 100644 index 0000000000000000000000000000000000000000..287aac2478c4f9887d75aa04f3a258c34c6345e3 --- /dev/null +++ b/client/src/components/ReservationDetails/index.js @@ -0,0 +1 @@ +export { default } from "./ReservationDetails" \ No newline at end of file diff --git a/client/src/components/ReservationDetails/reservation-details.module.scss b/client/src/components/ReservationDetails/reservation-details.module.scss new file mode 100644 index 0000000000000000000000000000000000000000..4dafcf0da8a3998a53eb4264b7135b5ac99a0dfd --- /dev/null +++ b/client/src/components/ReservationDetails/reservation-details.module.scss @@ -0,0 +1,39 @@ +.width{ + width : 100%; + display: flex; + justify-content: center; +} + +.header{ + display: flex; + justify-content: center; + background-color: #FEDC00; + width: 80%; + text-align: center; + font-size: 2.5rem; + margin: 5rem; +} +.body{ + width: 80%; + border-top: 1px solid #FEDC00; + border-bottom: 1px solid #FEDC00; +} + +.span .layout{ + color:white; + font-size: 1.5rem; +} + +@media (max-width: 403px) { + + .header{ + display: flex; + justify-content: center; + background-color: #FEDC00; + width: 80%; + text-align: center; + font-size: 1.5rem; + margin: 2rem; + } + +} \ No newline at end of file diff --git a/client/src/components/SearchResult.js b/client/src/components/SearchResult.js index 0868a11df612e206a10d2b4fc1ddb6c68fe0ab69..7c815c44781fce2dfb4d8e87969d1061be8b4a51 100644 --- a/client/src/components/SearchResult.js +++ b/client/src/components/SearchResult.js @@ -26,7 +26,7 @@ const SearchResult = () => { } return ( - <> +
{result.length !== 0 ? ( <>

'{title}' 에 관한 검색 결과입니다.

@@ -36,7 +36,7 @@ const SearchResult = () => { ) :

'{title}' 에 관한 검색 결과가 존재하지 않습니다.

} - +
) } diff --git a/client/src/components/SeatTable/SeatTable.js b/client/src/components/SeatTable/SeatTable.js index d9ec81ba6996cbd6a7c0dad9da1057babe360318..d803e29b60ef044dc4d8da0fd0263eb00b4abb35 100644 --- a/client/src/components/SeatTable/SeatTable.js +++ b/client/src/components/SeatTable/SeatTable.js @@ -1,40 +1,38 @@ -import { useState } from 'react' import styles from './seatTable.module.scss' -const SeatTable = (props) => { +const SeatTable = ({ theaterInfo, count, setSelectedSeats, selectedSeats, reservedSeats }) => { const table = [] - for (let rowIndex = 0; rowIndex < props.allSeat.row; rowIndex++) { - table.push({String.fromCharCode(rowIndex + 65)}) - // console.log(String.fromCharCode(rowIndex+65)) - for (let colIndex = 0; colIndex < props.allSeat.col; colIndex++) { - table.push( - - - - ) + + if (theaterInfo) { + for (let rowIndex = 0; rowIndex < theaterInfo.rows; rowIndex++) { + table.push({String.fromCharCode(rowIndex + 65)}) + for (let colIndex = 0; colIndex < theaterInfo.columns; colIndex++) { + table.push( + {reservedSeats.find(el => el === String(rowIndex + 1) + '-' + String(colIndex + 1)) + ? + + : + + } + ) + } + table.push(
) } - table.push(
) } function handleClick(event) { - const num = Object.values(props.count).reduce((a, b) => (a + b)) - if (props.selectedSeats.find(el => el === event.target.name)) { - //제거 - const deleted = props.selectedSeats.filter((element) => element !== event.target.name); - props.setSelectedSeats(deleted) + const num = Object.values(count).reduce((a, b) => (a + b)) + if (selectedSeats.find(el => el === event.target.name + '-' + event.target.id)) { + const deleted = selectedSeats.filter((element) => element !== event.target.name + '-' + event.target.id); + setSelectedSeats(deleted) } else { - if (props.selectedSeats.length > num - 1) { - alert("선택한 좌석이 예매인원보다 많습니다.") - } else { - //추가 - props.setSelectedSeats([...props.selectedSeats, event.target.name]) - } + if (selectedSeats.length > num - 1) alert("선택한 좌석이 예매인원보다 많습니다.") + else setSelectedSeats([...selectedSeats, event.target.name + '-' + event.target.id]) } - } + return (
- {console.log(props.selectedSeats)}
Screen
{table}
diff --git a/client/src/components/SeatTable/seatTable.module.scss b/client/src/components/SeatTable/seatTable.module.scss index 10907c73b361ed0fc211ae1970d54459fbd049a1..9b49038fa1abe6dcad16372f76b99092f0e643e1 100644 --- a/client/src/components/SeatTable/seatTable.module.scss +++ b/client/src/components/SeatTable/seatTable.module.scss @@ -1,15 +1,23 @@ .btn { - border:0; + border: 0; background: black; color: white; - &:hover{ - border:0; - background: red ; - color:white + + &:hover { + border: 0; + background: red; + color: white; } } + .on { - border:0; - background: red ; - color:white + border: 0; + background: red; + color: white; +} + +.btnBlock { + background: gray; + border: 0; + color: white; } \ No newline at end of file diff --git a/client/src/components/Signup/Signup.js b/client/src/components/Signup/Signup.js index 381fb31f89af91b642fea75b9808be7976f6e365..db82ccd2e65ef0e049e49614701c8cc67a830efe 100644 --- a/client/src/components/Signup/Signup.js +++ b/client/src/components/Signup/Signup.js @@ -1,13 +1,13 @@ -import styles from "./signup.module.scss"; import { useState } from "react"; +import { Redirect } from "react-router-dom"; import authApi from "../../apis/auth.api.js"; -import { Redirect } from "react-router"; import catchErrors from "../../utils/catchErrors.js"; -import Twilio from "twilio"; +import styles from "./signup.module.scss"; const Signup = () => { const [user, setUser] = useState({ userId: "", + userName: "", userEmail: "", userNickName: "", userBirthday: "", @@ -15,25 +15,24 @@ const Signup = () => { userPassword: "", userRePassword: "" }) - + const [startTime, setStartTime] = useState(""); + const [number, setNumber] = useState(null); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(false); - //각 타입별 error 유무 state + + const [mbError, setMbError] = useState(false); const [error, setError] = useState(""); const [errorMsg, setErrorMsg] = useState({ - errorId: null, + errorId: false, + errorName: false, errorEmail: false, errorNickName: false, errorBirthday: false, errorMbnum: false, errorPassword: false, - errorRePassword: false }) - // id중복확인 여부 state와 가입하기 누르면 id 임시 저장 - const [overlapId, setOverlapId] = useState(false); - const [preId, setPreId] = useState(""); + const [confirmMb, setConfirmMb] = useState(false); - //입력할때마다 state에 저장 const handleUserOnChange = (e) => { setUser({ ...user, @@ -47,116 +46,73 @@ const Signup = () => { } } - //id(중복확인 체크, 형식 에러) - const handleOnClickId = async (e) => { + const handleOnClickMbnum = async (e) => { e.preventDefault(); try { + setStartTime(""); setError(""); - if (user.userId.length < 5) { - setErrorMsg(errorMsg => ({ - ...errorMsg, - [e.target.name]: true - })); - if (overlapId === true) { - setOverlapId(() => (false)); - }; - } else { - const userId = user.userId; - await authApi.compareId(userId); - if (!await authApi.compareId(userId)) { - alert("이 아이디는 사용가능합니다.") - setErrorMsg(errorMsg => ({ - ...errorMsg, - [e.target.name]: false - })); - setOverlapId(() => (true)); - } else { - alert("이미 사용중인 아이디입니다.") - setOverlapId(() => (false)); - } + setLoading(true) + const phone = user.userMbnum; + const message = await authApi.confirmMbnum(phone); + if (message.isSuccess) { + setMbError("보냄"); + setStartTime(message.startTime); } } catch (error) { - catchErrors(error, setError) + catchErrors(error, setError); } finally { setLoading(false); } } - const handleOnClickMbnum = async (e) => { - try { - const id = "AC01ecdbffb36dc0766cfea487a54a4c6e"; - const token = "1d86d5d43760b5dce5582badf7b0a775"; - await authApi.confirmMbnum(id,token); - } catch (error) { - console.log('twilio error'+ error) - } + const handleOnChangeMb = (e) => { + setNumber(String(e.target.value)); } - const handleOnSummit = async (e) => { + const handleOnClickMbConfirm = async (e) => { e.preventDefault(); try { - setError(() => ("")); - //처리가 될때까지 버튼(가입하기)이 안눌리게 지정 - setLoading(() => (true)); - //유효성 검사 - validation(); - const userData = user; - //서버로 전송 - await authApi.signup(userData) - alert("가입이 완료되었습니다. 로그인 해주세요."); - setSuccess(true); + setError(""); + setLoading(true); + const confirmNum = { userMbnum: user.userMbnum, number: number, startTime: startTime }; + const message = await authApi.confirmNum(confirmNum); + setMbError(message); + if (message === "성공") { + setConfirmMb(true); + } } catch (error) { - //에러전송 catchErrors(error, setError); } finally { setLoading(false); } } - //비교하여 error메세지 반환 - const vaildationData = (text, compareValue, error) => { - if (text !== compareValue) { - setErrorMsg(errorMsg => ({ ...errorMsg, [error]: true })); - } else { - setErrorMsg(errorMsg => ({ ...errorMsg, [error]: false })); - } - } - //아이디 비번 유효성 검사 - const vaildationIdPw = (text, minValue, error) => { - if ((text < minValue)) { - setErrorMsg(errorMsg => ({ ...errorMsg, [error]: true })); - } else if (text >= minValue) { - setErrorMsg(errorMsg => ({ ...errorMsg, [error]: false })); - if (overlapId === true) { - if (preId !== user.userId) { - setOverlapId(false); - } - } - } + const validationPw = () => { + if (user.userPassword !== user.userRePassword) return false; + else return true; } - //유효성 검사 - const validation = () => { - setPreId(user.userId); - //아이디 유효성 검사 - vaildationIdPw(user.userId.length, 5, "errorId"); - //별명 유효성 검사 - vaildationData((user.userNickName.length === 0), false, "errorNickName"); - // 생일 유효성 검사 - vaildationData(user.userBirthday.length, 6, "errorBirthday"); - // 휴대폰 유효성 검사 - vaildationData(user.userMbnum.length, 11, "errorMbnum"); - // 비밀번호 유효성 검사 - vaildationIdPw(user.userPassword.length, 8, "errorPassword"); - // 비밀번호 확인 유효성 검사 - vaildationData(user.userRePassword, user.userPassword, "errorRePassword"); - // 최종 유효성 검사 - if (overlapId && (Object.values(errorMsg).some((element) => (element)) === false)) { - } else if (!overlapId && (Object.values(errorMsg).some((element) => (element)) === false)) { - setErrorMsg(errorMsg => ({ ...errorMsg, errorId: false })); - throw new Error("먼저 아이디 중복확인을 해주세요"); - } else { - throw new Error("유효하지 않은 데이터입니다."); + const handleOnSummit = async (e) => { + e.preventDefault(); + try { + setError(""); + setLoading(true); + let validPw = validationPw(); + if (confirmMb) { + if (validPw) { + const userData = user; + const error = await authApi.signup(userData); + if (error === "성공") setSuccess(true); + else { + setErrorMsg(error); + alert("형식에 맞게 다시 작성해주세요"); + } + } else throw new Error("비밀번호가 일치하지 않습니다."); + } else throw new Error("핸드폰 번호를 인증해주세요."); + } catch (error) { + catchErrors(error, setError); + } finally { + setLoading(false); } } @@ -164,73 +120,80 @@ const Signup = () => { return ; } - return ( - // 데이터 입력과 유효성 검사 후 보이는 경고창
회원가입
-
- - -
+ +
+ {errorMsg.errorId &&

5~10자리 사이로 입력해주세요.

} +
+
+
+ +
- {(overlapId === false) && errorMsg.errorId &&

5~10자리 사이로 입력해주세요.

} - {overlapId && (errorMsg.errorId === false) &&

아이디 중복이 확인되었습니다.

} - {(errorMsg.errorId === false) && (overlapId === false) &&

아이디 중복확인을 해주세요.

} + {errorMsg.errorName &&

이름을 입력해주세요

}
- +
- {errorMsg.errorEmail &&

이메일을 입력해주세요

} + {errorMsg.errorEmail &&

이메일을 입력해주세요

}
- +
- {errorMsg.errorNickName &&

10자 이내로 입력해주세요.

} + {errorMsg.errorNickName &&

10자 이내로 입력해주세요.

}
-
- +
- {errorMsg.errorBirthday &&

숫자 6자리를 입력해주세요.

} + {errorMsg.errorBirthday &&

숫자 6자리를 입력해주세요.

}
-
- - + + +
+
+ {errorMsg.errorMbnum &&

-없이 숫자 11자리를 입력해주세요.

} +
+
+ +
+ + + +
+ {(mbError === "재전송") &&

유효시간이 만료되었습니다. 재전송해주세요.

} + {(mbError === "보냄") &&

5분이내에 입력해주세요.

} + {(mbError === "성공") &&

인증되었습니다.

} + {(mbError === "실패") &&

인증번호를 다시 입력해주세요.

}
- {errorMsg.errorMbnum &&

-없이 숫자 11자리를 입력해주세요.

}
- +
- {errorMsg.errorPassword &&

8~11자리 사이로 입력해주세요.

} + {errorMsg.errorPassword &&

8~11자리 사이로 입력해주세요.

}
- -
-
- - -
- {errorMsg.errorRePassword &&

비밀번호가 일치하지 않습니다.

} +
+ +
-
diff --git a/client/src/components/Signup/signup.module.scss b/client/src/components/Signup/signup.module.scss index cfd428e1b4ca03a97dd63d1f3b84d0d553bb2d73..c4715f589009cf0545596e3b9b85f929a0ea2990 100644 --- a/client/src/components/Signup/signup.module.scss +++ b/client/src/components/Signup/signup.module.scss @@ -5,7 +5,13 @@ font-size: 1.7rem; margin-top: 2rem; } - +.confirm{ + color: white; + padding-right: 8px; + text-align: center; + display: flex; + align-items: center; +} .contents{ display: flex; width: 100%; @@ -31,7 +37,9 @@ border-radius: 3px; text-align: center; } - +.input2 { + width: 9.01rem; +} input[type=password]{ font-family: 'Courier New', Courier, monospace; } @@ -65,7 +73,7 @@ border: 1px solid white ; text-align: center; } -.passwordConfirmError{ +.errorMsg{ margin-bottom: 0; margin-top: 0.5rem; text-align: end; diff --git a/client/src/components/TheaterInfo.js b/client/src/components/TheaterInfo.js new file mode 100644 index 0000000000000000000000000000000000000000..c18678794e9f4ba9d6313606230aa1cf4f5d0022 --- /dev/null +++ b/client/src/components/TheaterInfo.js @@ -0,0 +1,122 @@ +import { useRef, useState, useEffect } from 'react' +import cinemaApi from "../apis/cinema.api,js" +import theaterApi from "../apis/theater.api.js" +import catchErrors from "../utils/catchErrors" + +const { kakao } = window; +const options = { + center: new kakao.maps.LatLng(37.365264512305174, 127.10676860117488), + level: 3 +}; + +const TheaterInfo = () => { + const container = useRef(null) + const [cinemaInfo, setCinemaInfo] = 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 === "address") { + const container = document.getElementById("map"); + 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: '
Butter Studio
' + }); + infowindow.open(map, marker); + map.setCenter(coords); + } + }); + } + }, [currentInfo]); + + async function getTheaterInfo() { + try { + const response = await cinemaApi.getCinemaInfo() + const response2 = await theaterApi.getAll() + setCinemaInfo({ ...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 ( + <> + {cinemaInfo ? +
+ {console.log(cinemaInfo)} +

{cinemaInfo.cinemaName}

+
+ +
+
총 상영관 수: {cinemaInfo.theaterNum}개
+
{cinemaInfo.address}
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
{currentInfo.information}
+
+
{currentInfo.information}
+
+
+
+
+
+ : +
+ 극장정보를 불러올 수 없습니다. +
} + + ) +} + +export default TheaterInfo \ No newline at end of file diff --git a/client/src/components/TicketingMovie/TicketingMovie.js b/client/src/components/TicketingMovie/TicketingMovie.js index 612fe1e0267f50dfcd31a5b5e35ad367453baa49..96e0718c8098649fe50e32a04c2278223a7524be 100644 --- a/client/src/components/TicketingMovie/TicketingMovie.js +++ b/client/src/components/TicketingMovie/TicketingMovie.js @@ -1,34 +1,35 @@ -import React, { useState, useEffect } from 'react' -import axios from 'axios' +import { useState, useEffect } from 'react' +import movieApi from '../../apis/movie.api' +import catchErrors from '../../utils/catchErrors' import styles from "./ticketingMovie.module.scss" -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() + 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 (
- {console.log(props.ticketInfo.movieId)}
{movieList.length > 0 ? movieList.map(movie => ( - )) diff --git a/client/src/components/TicketingTheater/TicketingTheater.js b/client/src/components/TicketingTheater/TicketingTheater.js index fc1071ae908b04fdb2ca672f571614082deba756..4c76ee16497c03016190e8884e610ef2db04acdc 100644 --- a/client/src/components/TicketingTheater/TicketingTheater.js +++ b/client/src/components/TicketingTheater/TicketingTheater.js @@ -1,20 +1,15 @@ 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, theater:event.target.name}) + setTicketInfo({ ...ticketInfo, cinema: event.target.name }) } return (
- {props.theaterInfo.theater.length > 0 - ? props.theaterInfo.theater.map(name => ( - - )) - :
영화관 정보가 존재하지 않습니다.
} +
) diff --git a/client/src/components/TicketingTimeTable/TicketingTimeTable.js b/client/src/components/TicketingTimeTable/TicketingTimeTable.js index e17e0ad840df244332365c86268e24f83cc8b031..8b26dc9963e982071088dfaf566e06f63bf66d1c 100644 --- a/client/src/components/TicketingTimeTable/TicketingTimeTable.js +++ b/client/src/components/TicketingTimeTable/TicketingTimeTable.js @@ -1,10 +1,10 @@ -const TicketingTimeTable = (props) => { +const TicketingTimeTable = ({ ticketInfo }) => { + return (
-
- {console.log(props.ticketInfo.movieId, props.ticketInfo.theater)} - {props.ticketInfo.movieId && props.ticketInfo.theater - ?
{props.ticketInfo.movieId} {props.ticketInfo.theater}
+
+ {ticketInfo.movieId && ticketInfo.cinema + ?
{ticketInfo.movieId} {ticketInfo.cinema}
:
영화와 극장을 모두 선택해주세요.
}
diff --git a/client/src/components/Video.js b/client/src/components/Video.js index ac36712e1c7c8d461bc94f94ba6a83291c8b2557..a29b645fa69d9da5bcdf2de59f30898932fd5719 100644 --- a/client/src/components/Video.js +++ b/client/src/components/Video.js @@ -1,19 +1,24 @@ import { useEffect, useState } from 'react' import movieApi from '../apis/movie.api.js' -const Video = (props) => { +import catchErrors from "../utils/catchErrors.js" + +const Video = ({ movieId }) => { const [videoUrls, setVideoUrls] = useState([]) + const [error, setError] = useState("") + useEffect(() => { getVideos() }, []) async function getVideos() { try { - const data = await movieApi.getVideosfromTM(props.movieId) + const data = await movieApi.getVideosfromTM(movieId) setVideoUrls(data) } catch (error) { - console.log(error) + catchErrors(error, setError) } } + return (
{videoUrls.length > 0 diff --git a/client/src/context/auth_context.js b/client/src/context/auth_context.js index 4132158bfc1dd65310d2a5fc29ba1cf1e8a53f2c..f0341b4ea5767fc6e7c7ac5955fe522676e5b6f9 100644 --- a/client/src/context/auth_context.js +++ b/client/src/context/auth_context.js @@ -1,15 +1,11 @@ -import axios from "axios"; -import { createContext, useCallback, useContext, useState } from "react"; +import { createContext, useCallback, useContext, useEffect, useState } from "react"; import authApi from "../apis/auth.api"; -import { getLocalUser } from "../utils/auth"; -import {baseUrl} from "../utils/baseUrl"; import catchErrors from "../utils/catchErrors"; -import config from "../utils/clientConfig"; const AuthContext = createContext({ error: "", loading: false, - user: {id:0, role:"user"}, + user: { id: 0, role: "user" }, setUser: () => { }, login: () => Promise.resolve(false), logout: () => { }, @@ -19,16 +15,24 @@ const AuthContext = createContext({ const AuthProvider = ({ children }) => { const [error, setError] = useState(""); const [loading, setLoading] = useState(false); - const [user, setUser] = useState(getLocalUser()); + const [user, setUser] = useState({ id: 0, role: "user" }); + + const getUser = async () => { + const { id, role } = await authApi.getUser(); + const user = { "id": id, "role": role }; + setUser(user); + }; + + useEffect(() => { + getUser(); + }, []); const login = useCallback(async (id, password) => { try { setError(""); setLoading(true); const user = await authApi.login(id, password); - localStorage.setItem(config.loginUser, JSON.stringify(user)); setUser(user); - return true; } catch (error) { catchErrors(error, setError); @@ -41,11 +45,10 @@ const AuthProvider = ({ children }) => { const logout = useCallback(async () => { try { setError(""); - setUser(null); - alert("로그아웃되었습니다."); - localStorage.removeItem(config.loginUser); setLoading(true); - await axios.get(`${baseUrl}/api/auth/logout`); + const user = await authApi.logout(); + setUser(user); + alert("로그아웃되었습니다."); } catch (error) { catchErrors(error, setError); } finally { @@ -64,7 +67,6 @@ const AuthProvider = ({ children }) => { if (data.redirectUrl) { errorMsg = data.message; console.log("Error response with redirected message:", errorMsg); - console.log("redirect url", data.redirectUrl); return await logout(); } } @@ -75,7 +77,6 @@ const AuthProvider = ({ children }) => { errorMsg = error.message; console.log("Error message:", errorMsg); } - displayError(errorMsg); }, []); diff --git a/client/src/pages/HomePage.js b/client/src/pages/HomePage.js index 4fd44cc94f3ee73f4f83501f8458745f41cb565d..4efc9b8a6289b6f6b7255e580a35c843218b2650 100644 --- a/client/src/pages/HomePage.js +++ b/client/src/pages/HomePage.js @@ -1,13 +1,36 @@ - +import { useState, useEffect } from "react" import BoxOffice from "../components/BoxOffice"; import Collection from "../components/Collection"; import Footer from "../components/Footer"; +import movieApi from '../apis/movie.api' +import catchErrors from '../utils/catchErrors.js' 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) + data.sort(function (a, b) { + return b.popularity - a.popularity + }) + setTMDB_TopRated_Data([...data]) + } catch (error) { + catchErrors(error, setError) + } + } + return ( <> - - + +
상영관 종류청소년 일반 경로
{priceToString(info.weekdays + info.morning + info.youth + info.defaultPrice)}원 {priceToString(info.weekdays + info.morning + info.adult + info.defaultPrice)}원 {priceToString(info.weekdays + info.morning + info.senior + info.defaultPrice)}원 -
- - -
-
+
+ + +
+
일반 (11:00 ~ ){priceToString(info.weekend + info.night + info.youth + info.defaultPrice)}원 {priceToString(info.weekend + info.night + info.adult + info.defaultPrice)}원 {priceToString(info.weekend + info.night + info.senior + info.defaultPrice)}원 -
- - -
-
+
+ + +
+