Commit 31cef7c3 authored by Jiwon Yoon's avatar Jiwon Yoon
Browse files

Merge branch 'kimpen'

parents 53792c65 ba5429cf
......@@ -24,35 +24,31 @@ function App() {
<AuthProvider>
<Router>
<Switch>
<>
<Route path="/admin" component={AdminPage} />
<div style={{ backgroundColor: "black" }}>
<Router>
<SubNav />
<Header />
<MainNav />
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/login" component={LoginPage} />
<Route path="/signup" component={SignupPage} />
<Route path="/movielist" component={MovieListPage} />
<Route path="/movie/:movieId" component={MoviePage} />
<Route path="/mypage" component={MyPage} />
<Route path="/guest" component={GuestPage} />
<Route path="/ticket/seat" component={TicketingSeatPage} />
<Route path="/ticket" component={TicketingPage} />
<Route path="/payment" component={Payment} />
<Route path="/paymentcomplete" component={PaymentCompletePage} />
<Route path="/theater" component={TheaterPage}/>
<Route path="/search" component={SearchPage} />
</Switch>
</Router>
<SubNav />
<Header />
<MainNav />
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/login" component={LoginPage} />
<Route path="/signup" component={SignupPage} />
<Route path="/movielist" component={MovieListPage} />
<Route path="/movie/:movieId" component={MoviePage} />
<Route path="/mypage" component={MyPage} />
<Route path="/guest" component={GuestPage}/>
<Route path="/ticket/seat" component={TicketingSeatPage}/>
<Route path="/ticket" component={TicketingPage} />
<Route path="/payment" component={Payment} />
<Route path="/paymentcomplete" component={PaymentCompletePage} />
<Route path="/theater" component={TheaterPage}/>
<Route path="/search" component={SearchPage} />
</Switch>
</div>
</>
</Switch>
</Router>
</AuthProvider>
);
}
export default App;
export default App;
\ No newline at end of file
import axios from "axios";
import { baseUrl, TMDBUrl } from "../utils/baseUrl.js";
const getAllfromTM = async () => {
const getAllfromTM = async (pageNum) => {
const payload = {
params: {
pageNum: 1
pageNum
}
}
const { data } = await axios.get(`${baseUrl}/api/movie/all`, payload)
return data
}
const getMovieIdfromTM = async (movieId) => {
const { data } = await axios.get(`${baseUrl}/api/movie/${movieId}`)
return 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`)
......@@ -42,10 +39,12 @@ const getListfromDB = async () => {
const { data } = await axios.get(`${baseUrl}/api/movie`)
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
......@@ -56,10 +55,11 @@ const remove = async (movieId) => {
return data
}
const search = async ({ type, keyword }) => {
const search = async ({ type, keyword }, pageNum) => {
const payload = {
params: {
keyword
keyword,
pageNum
}
}
const { data } = await axios.get(`${baseUrl}/api/movie/search/${type}`, payload)
......@@ -74,7 +74,6 @@ const movieApi = {
getCreditsfromTM,
getVideosfromTM,
getListfromDB,
getMovieIdfromTM,
submit,
remove,
search,
......
......@@ -2,6 +2,7 @@ import { useState, useEffect, useRef } from "react";
import TicketEditForm from "./TicketEditForm.js";
import TicketFeeTable from "./TicketFeeTable.js";
import cinemaApi from "../../apis/cinema.api.js";
import theaterApi from "../../apis/theater.api.js";
import catchErrors from "../../utils/catchErrors.js";
import styles from "./admin.module.scss";
......@@ -15,12 +16,15 @@ const INIT_CINEMAINFO = {
const CinemaEdit = () => {
const [cinemaInfo, setCinemaInfo] = useState(INIT_CINEMAINFO)
const [theaterTypeList, setTheaterTypeList] = useState([])
const [selectTheater, setSelectTheater] = useState(0)
const [ticketFee, setTicketFee] = useState({})
const [error, setError] = useState("")
const formRef = useRef(null)
useEffect(() => {
getInfo()
getTicketFeeInfo()
}, [])
function handleChange(e) {
......@@ -49,6 +53,15 @@ const CinemaEdit = () => {
}
}
async function getTicketFeeInfo() {
try {
const res = await theaterApi.getTheaterType()
setTheaterTypeList(res)
} catch (error) {
catchErrors(error, setError)
}
}
return (
<>
<h2 className="border-bottom border-2 text-center pb-2 me-2">현재 영화관 정보</h2>
......@@ -73,7 +86,14 @@ const CinemaEdit = () => {
<p className="mb-0">영화관람료 설정</p>
<p className="text-danger">*추가금액 정보를 입력바랍니다. 필요에 따라 기본가격 또한 변경 가능합니다.</p>
<TicketEditForm editFee={ticketFee} formRef={formRef} />
<TicketFeeTable setEditFee={setTicketFee} formRef={formRef} />
<label className="form-label">영화관람료 안내</label>
<nav aria-label="breadcrumb">
<ol className={"breadcrumb" + (theaterTypeList.length === 0 ? " d-flex justify-content-center" : "" )}>
{theaterTypeList.length !== 0 ? theaterTypeList.map(theater => <li className={`breadcrumb-item ${styles.cursor}`} key={theater.id} onClick={() => setSelectTheater(theater.id)}>{theater.theaterTypeName}</li>)
: <li>등록된 관람료 관련 정보가 없습니다.</li>}
</ol>
</nav>
<TicketFeeTable selectTheater={selectTheater} setEditFee={setTicketFee} formRef={formRef} />
<div className="mb-3">
<label htmlfor="moreFeeInfo" className="form-label">관람료 추가정보</label>
<textarea className={`form-control ${styles.shadowNone} ${styles.textarea}`} rows="7" id="moreFeeInfo" name="moreFeeInfo" value={cinemaInfo.moreFeeInfo} onChange={handleChange}></textarea>
......
......@@ -8,39 +8,53 @@ import catchErrors from "../../utils/catchErrors.js";
const MovieEdit = () => {
const [search, setSearch] = useState({ type: "admin", keyword: "" })
const [movieList, setMovieList] = useState([])
const [totalPages, setTotalPages] = useState(0)
const [activePage, setActivePage] = useState(1)
const [error, setError] = useState("")
useEffect(() => {
getMovieList()
paginate(activePage)
}, [])
async function getMovieList() {
async function paginate(pageNum) {
try {
setError("")
const getMovieList = await movieApi.getAllfromTM()
setMovieList(getMovieList)
const { TMDBmovies, totalPage } = (search.keyword !== '') ? await movieApi.search(search, pageNum) : await movieApi.getAllfromTM(pageNum)
setActivePage(pageNum)
setTotalPages(totalPage)
setMovieList(TMDBmovies)
} catch (error) {
catchErrors(error, setError)
catchErrors(error, setError);
}
}
async function searchMovie() {
try {
setError("")
const findMovie = await movieApi.search(search)
setMovieList(findMovie)
} catch (error) {
catchErrors(error, setError)
const prevPage = () => {
if (activePage > 1) {
paginate(activePage - 1)
} else {
paginate(1);
}
}
};
const nextPage = () => {
if (activePage < totalPages) {
paginate(activePage + 1)
} else {
paginate(totalPages);
}
};
return (
<>
<div className="d-flex justify-content-md-end justify-content-center mb-3">
<Search search={search} setSearch={setSearch} handleClick={searchMovie} />
<Search search={search} setSearch={setSearch} handleClick={paginate} />
</div>
<MovieTable movieList={movieList} />
<Pagination />
<Pagination
totalPages={totalPages}
activePage={activePage}
prevPage={prevPage}
nextPage={nextPage}
paginate={paginate} />
</>
)
}
......
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 { useAuth } from '../../context/auth_context';
import styles from "./admin.module.scss";
const TicketFeeTable = ({ setEditFee, formRef }) => {
const TicketFeeTable = ({ selectTheater, setEditFee, formRef }) => {
const [ticketFee, setTicketFee] = useState([])
const [error, setError] = useState("")
const { user } = useAuth()
useEffect(() => {
getInfo()
}, [])
if (selectTheater !== 0) getOne(selectTheater)
}, [selectTheater])
async function getInfo() {
async function getOne(theatertypeId) {
try {
const res = await cinemaApi.getTicketFee()
setTicketFee(res)
setError("")
const res = await cinemaApi.getTicketFeeOne(theatertypeId)
setTicketFee([res])
} catch (error) {
catchErrors(error, setError)
}
......@@ -40,7 +40,7 @@ const TicketFeeTable = ({ setEditFee, formRef }) => {
setError("")
await cinemaApi.removeTicketFee(theatertypeId)
alert("해당 관람료 정보를 성공적으로 삭제했습니다.")
getInfo()
window.location.reload()
} catch (error) {
catchErrors(error, setError)
}
......@@ -51,8 +51,7 @@ const TicketFeeTable = ({ setEditFee, formRef }) => {
}
return (
<table style={{ color: user.role==="admin"?"":"white" }} className={`table caption-top text-center align-middle ${styles.tableForm}`}>
<caption className="text-dark">영화관람료 안내</caption>
<table className={`table text-center align-middle ${styles.tableForm}`} style={{ color: user.role === "admin" ? "" : "white" }}>
<thead className={`table-dark align-middle ${styles.dNone}`}>
<tr>
<th className={styles.word}>상영관 종류</th>
......@@ -61,10 +60,7 @@ const TicketFeeTable = ({ setEditFee, formRef }) => {
<th>청소년</th>
<th>일반</th>
<th>경로</th>
{user.role === "admin"
?
<th style={{ width: "14%" }}></th>
: <></>}
{user.role === "admin" ? <th style={{ width: "14%" }}></th> : <></>}
</tr>
</thead>
<tbody>
......@@ -129,7 +125,7 @@ const TicketFeeTable = ({ setEditFee, formRef }) => {
</tr>
</>)
: <tr>
<td colSpan="7">등록된 관람료 관련 정보가 없습니다.</td>
<td colSpan="7">상단의 상영관을 선택해주십시오.</td>
</tr>}
</tbody>
</table>
......
......@@ -43,7 +43,7 @@ const TimeTable = () => {
<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>
<button type="button" className={`btn btn-dark btn-sm shadow-none ${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>
......
......@@ -146,7 +146,7 @@ const TimeTableEditForm = () => {
}
return (
<form className="col-12 col-lg-6 me-lg-1" onSubmit={handleSubmit}>
<form className="col-12 col-lg-6 me-lg-1 mb-5 mb-lg-0" 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">
{movieList.length !== 0 ?
......
......@@ -68,6 +68,10 @@
}
}
.cursor {
cursor: pointer;
}
.textarea {
resize: none;
}
......
......@@ -35,4 +35,152 @@ const BoxOffice = ({TMDB_TopRated_Data}) => {
)
}
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 (
// <div className="container text-center my-3">
// {console.log(TMDB_TopRated_Data)}
// <div className="container text-center my-3">
// <h2 className="font-weight-light">Bootstrap Multi Slide Carousel</h2>
// <div className="row mx-auto my-auto justify-content-center">
// <div id="recipeCarousel" className="carousel slide" data-bs-ride="carousel">
// <div className="carousel-inner" role="listbox">
// <div className="carousel-item active">
// <div className="col-md-3">
// <div className="card">
// <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>
// <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>
// <h5 className="mt-2 fw-light">advances one slide at a time</h5>
// </div>
// <div className="row my-auto justify-content-center">
// <div id="recipeCarousel" className="carousel slide" data-bs-ride="carousel" data-bs-interval="999999999">
// <div className={`carousel-inner`} role="listbox">
// {TMDB_TopRated_Data ?
// TMDB_TopRated_Data.map((moviePoster, index) => (
// <div className={`carousel-item ${index === 0 ? "active" : ""}`}>
// <div className="col-sm-3">
// <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>
// )
// }
// export default BoxOffice
\ No newline at end of file
import { useState, useEffect } from "react";
import moment from "moment";
import styles from "./calender.module.scss";
const DatePicker = ({ selectDate, setSelectDate, month }) => {
const [week, setWeek] = useState([])
useEffect(() => {
generate()
}, [month])
function generate() {
const weekly = []
const startWeek = moment(month.cur).startOf('month').week()
const endWeek = moment(month.cur).endOf('month').week() === 1 ? 53 : moment(month.cur).endOf('month').week()
for (let week = startWeek; week <= endWeek; week++) {
weekly.push(<tr key={week}>{
Array(7).fill(0).map((n, i) => {
let current = moment(month.cur).clone().week(week).startOf('week').add(n + i, 'day')
let isSelected = moment(selectDate).format('YYYYMMDD') === current.format('YYYYMMDD') ? `${styles.selectDate}` : ''
let isColor = current.format('MM') !== moment(month.cur).format('MM') ? 'text-secondary ' : ((i === 0) ? "text-danger" : (i === 6) ? "text-primary" : "")
return <td className={`text-center p-1 ${styles.cursor}`} key={i} data-bs-dismiss="modal" onClick={() => setSelectDate(current.format('YYYY-MM-DD'))}>
<span className={`d-block ${isColor} ${isSelected}`}>{current.format('D')}</span>
</td>
})}</tr>)
}
setWeek(weekly)
}
return (
<tbody>{week.length !== 0 ? week.map(row => row) : ''}</tbody>
)
}
export default DatePicker
\ No newline at end of file
import { useState, useEffect } from "react";
import moment from "moment";
import DatePicker from "./DatePicker.js";
import styles from "./calender.module.scss";
const Calender = ({ selectDate, setSelectDate }) => {
const [dateList, setDateList] = useState([])
const [dateArr, setDateArr] = useState([])
const [weekly, setWeekly] = useState([])
const [week, setWeek] = useState(["", "", "", "", "", "", ""])
const [month, setMonth] = useState({ pre: moment(selectDate).subtract(1, 'months').format('YYYY-MM'), cur: moment(selectDate).format('YYYY-MM'), next: moment(selectDate).add(1, 'months').format('YYYY-MM') })
useEffect(() => {
setMonth({ ...month, pre: moment(selectDate).subtract(1, 'months').format('YYYY-MM'), cur: moment(selectDate).format('YYYY-MM'), next: moment(selectDate).add(1, 'months').format('YYYY-MM') })
getDate(selectDate)
}, [])
getWeek(selectDate)
}, [selectDate])
function getWeek(oneDay) {
let dateArr = []
dateArr = Array(7).fill(0).map((n, i) => {
let current = moment(oneDay).add((n + i), 'days')
return <div className="col-auto align-self-end text-center" onClick={() => setSelectDate(current)}>
{current.isSame(oneDay) || current.format("DD") === "01" ? <strong className={styles.yearmonth}>{current.format('YYYY.MM')}</strong> : ""}
<div className={`d-flex flex-column ${styles.cursor} ` + ((current.format("d") === "0" || current.format("d") === "6") ? ((current.format("d") === "0") ? "text-danger" : "text-primary") : "")}>
<strong className={current.isSame(oneDay) ? styles.selectDate : ""}>{current.format('DD')}</strong>
<strong>{current.isSame(oneDay) ? "오늘" : week[Number(current.format("d"))]}</strong>
</div>
</div>
})
console.log("Dadsa--===", dateArr)
setWeekly(dateArr)
}
function getDate(oneDay) {
let dateArr = []
......@@ -20,7 +42,7 @@ const Calender = ({ selectDate, setSelectDate }) => {
}
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") : "")}>
<div className={`d-flex flex-column ${styles.cursor} ` + ((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>
......@@ -28,14 +50,58 @@ const Calender = ({ selectDate, setSelectDate }) => {
setDateList(resultArr)
}
function preWeek() {
// let dateArr = []
// dateArr = Array(7).fill(0).map((n, i) => {
// let current = moment(oneDay).add((n + i), 'days')
// return <div className="col-auto align-self-end text-center" onClick={() => setSelectDate(current)}>
// {current.isSame(oneDay) || current.format("DD") === "01" ? <strong className={styles.yearmonth}>{current.format('YYYY.MM')}</strong> : ""}
// <div className={`d-flex flex-column ${styles.cursor} ` + ((current.format("d") === "0" || current.format("d") === "6") ? ((current.format("d") === "0") ? "text-danger" : "text-primary") : "")}>
// <strong className={current.isSame(oneDay) ? styles.selectDate : ""}>{current.format('DD')}</strong>
// <strong>{current.isSame(oneDay) ? "오늘" : week[Number(current.format("d"))]}</strong>
// </div>
// </div>
// })
// console.log("Dadsa--===", dateArr)
// setWeekly(dateArr)
}
function nextWeek() {
}
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>
<i className={`bi bi-calendar2 position-absolute top-0 ${styles.calender} ${styles.cursor}`} data-bs-toggle="modal" data-bs-target="#calenderModal"></i>
<div className="modal" id="calenderModal" tabindex="-1" aria-labelledby="calenderModal" aria-hidden="true">
<div className={`modal-dialog position-absolute bg-white ${styles.datepicker}`}>
<div className="modal-content">
<div className="modal-body px-1 pt-1 pb-0">
<div className="d-flex justify-content-between bg-dark rounded py-1">
<i className={`bi bi-chevron-left align-self-center text-center text-white ${styles.cursor}`} onClick={() => setMonth({ ...month, pre: moment(month.pre).subtract(1, 'months').format('YYYY-MM'), cur: month.pre, next: month.cur })}></i>
<div className="text-white">{moment(month.cur).format('YYYY년 MM월')}</div>
<i className={`bi bi-chevron-right align-self-center text-center text-white ${styles.cursor}`} onClick={() => setMonth({ ...month, pre: month.cur, cur: month.next, next: moment(month.next).add(1, 'months').format('YYYY-MM') })}></i>
</div>
<table className="table mb-0">
<thead>
<tr>{week.map(day => <th>{day}</th>)}</tr>
</thead>
<DatePicker selectDate={selectDate} setSelectDate={setSelectDate} month={month} />
<tfoot>
<tr>
<td colSpan="7" align="center"><button type="button" className={`btn btn-dark btn-sm shadow-none ${styles.customBtn}`} data-bs-dismiss="modal" onClick={() => setSelectDate(moment().format('YYYY-MM-DD'))}>오늘</button></td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
<i className={`col-1 bi bi-chevron-left align-self-center text-center ${styles.cursor}`} onClick={preWeek}></i>
<div className={`d-flex justify-content-between col-10 ${styles.box}`}>{weekly.map(el => el)}</div>
<i className={`col-1 bi bi-chevron-right align-self-center text-center ${styles.cursor}`} onClick={nextWeek}></i>
</div>
</>
)
......
......@@ -7,15 +7,32 @@
width: 100%;
font-size: 10px;
}
& .selectDate {
background-color: #000;
color: #fff;
border-radius: 50%;
}
}
.calender {
right: 13px;
font-size: 1.5em;
}
.datepicker {
top: 92px;
right: 12px;
& .customBtn {
&:hover {
border-color: #FEDC00;
background-color: #FEDC00;
color: #000;
}
}
}
.cursor {
cursor: pointer;
}
.selectDate {
background-color: #000;
color: #fff;
border-radius: 50%;
}
\ No newline at end of file
......@@ -8,7 +8,6 @@ const Collection = ({ TMDB_TopRated_Data }) => {
useEffect(() => {
if (TMDB_TopRated_Data.length > 0) {
console.log("야이쒸===", TMDB_TopRated_Data)
getVideos()
}
}, [TMDB_TopRated_Data])
......@@ -18,8 +17,7 @@ const Collection = ({ TMDB_TopRated_Data }) => {
const data = await movieApi.getVideosfromTM(TMDB_TopRated_Data[0].id)
setVideoUrls(data)
} catch (error) {
// catchErrors(error, setError)
console.log(error)
catchErrors(error, setError)
}
}
return (
......
......@@ -9,6 +9,7 @@ const CountButton = ({name, count, setCount}) => {
}
}
return (
<>
<button type="button" name="backbutton" style={{ backgroundColor: "black", border: "0" }} onClick={handleCount}>
......
import { useState } from "react";
import styles from "./login.module.scss";
import { Redirect } from "react-router-dom";
import catchErrors from "../../utils/catchErrors";
import { useAuth } from "../../context/auth_context.js";
import catchErrors from "../../utils/catchErrors";
import styles from "./login.module.scss";
const Login = () => {
const { login, guestLogin, loading } = useAuth();
......@@ -15,7 +15,6 @@ const Login = () => {
});
const [error, setError] = useState("");
const [success, setSuccess] = useState(false);
const [guest, setGuset] = useState({
guestName: "",
guestEmail: "",
......@@ -24,10 +23,7 @@ const Login = () => {
guestPassword: ""
})
//input태그에 걸려있는 onchange에서 실행할 함수설정
const handleLoginOnChange = (e) => {
// ... 전개 연산자
// 현재 state에 방금 변화한 값을 다시 저장함
setUser({
...user,
[e.target.name]: e.target.value
......@@ -55,7 +51,6 @@ const Login = () => {
setSuccess("guest");
alert('로그인이 완료되었습니다.')
}
}
} catch (error) {
catchErrors(error, setError);
......@@ -99,7 +94,6 @@ const Login = () => {
</li>
</ul>
<div className="tab-content w-100" id="myTabContent">
{/* 로그인 */}
<div className="tab-pane fade show active" id="login" role="tabpanel" aria-labelledby="login-tab">
<form className="d-flex flex-column" name="login" onSubmit={handleOnSummit}>
<input className={styles.input} type="text" name="id" placeholder="ID" onChange={handleLoginOnChange} maxLength="10"/>
......@@ -108,7 +102,6 @@ const Login = () => {
<span><a href="./signup" className={styles.intoSignupPage}>회원이 아니십니까?</a></span>
</form>
</div>
{/* 비회원예매 학인 */}
<div className="tab-pane fade" id="guest" role="tabpanel" aria-labelledby="guest-tab">
<form className="d-flex flex-column" onSubmit={handleOnSummit}>
<input className={styles.input} type="text" name="guestName" id="guestName" placeholder="이름" onChange={handleGuestOnChange} maxLength="10"/>
......
......@@ -3,7 +3,6 @@ import MovieCard from './MovieCard/index.js'
import movieApi from '../apis/movie.api.js'
import catchErrors from '../utils/catchErrors.js'
const MovieChart = () => {
const [TMDB_TopRated_Data, setTMDB_TopRated_Data] = useState([])
const [error, setError] = useState("")
......@@ -17,7 +16,6 @@ const MovieChart = () => {
try {
setError("")
const data = await movieApi.getListByCategoryfromDB(category)
console.log("sdad==", data)
setTMDB_TopRated_Data([...data])
} catch (error) {
catchErrors(error, setError)
......
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/movie-card.module.scss'
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([])
......@@ -29,7 +28,6 @@ const MovieComing = () => {
<>
{TMDB_UpComing_Data.length !== 0 ?
<div className="row row-cols-1 row-cols-md-4 g-4">
{/* <MovieCard list={TMDB_UpComing_Data} /> */}
{TMDB_UpComing_Data.map(movie => (
<div className="card h-100" style={{ backgroundColor: "black" }}>
<Link to={{
......
import styles from "./my-info.module.scss";
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 [userNickName, setUserNickName] = useState("사용자");
const [img, setImg] = useState("");
const [profile, setProfile] = useState("");
const [startTime, setStartTime] = useState("");
// 사용자 이름 가져오는 함수
const getMember = async () => {
const member = await authApi.getMember();
setUserNickName(member.nickname);
setProfile(member.img);
}
const [page, setPage] = useState(true);
//현재 비밀번호 state
const [presentPw, setPresentPw] = useState("");
const [loading, setLoading] = useState(false);
//변경할 데이터 입력받는 state
const [userRe, setUserRe] = useState({
userName: "",
userEmail: "",
......@@ -32,9 +21,7 @@ const MyInfo = () => {
})
const [confirmMb, setConfirmMb] = useState(false);
const [number, setNumber] = useState(null);
//각 타입별 error 유무 state
const [mbError,setMbError] = useState(false);
const [mbError, setMbError] = useState(false);
const [error, setError] = useState("");
const [errorMsg, setErrorMsg] = useState({
errorName: false,
......@@ -48,11 +35,16 @@ const MyInfo = () => {
getMember();
}, [])
const getMember = async () => {
const member = await authApi.getMember();
setUserNickName(member.nickname);
setProfile(member.img);
}
const handlePwOnChange = (e) => {
setPresentPw(e.target.value)
}
//입력할때마다 state에 저장
const handleUserOnChange = (e) => {
setUserRe({
...userRe,
......@@ -87,16 +79,13 @@ const MyInfo = () => {
catchErrors(error, setError);
}
}
//기존 비밀번호 확인
const handleOnSummitVerify = async (e) => {
e.preventDefault();
try {
setError("");
setLoading(true);
const pw = presentPw;
console.log(pw);
const confirmPw = await authApi.comparePw(pw);
console.log("confirmPw : ", confirmPw);
if (confirmPw) {
setPage(false);
setPresentPw("");
......@@ -118,14 +107,13 @@ const MyInfo = () => {
setLoading(true);
const phone = userRe.userMbnum;
const message = await authApi.confirmMbnum(phone);
if(message.isSuccess){
setMbError("보냄");
setStartTime(message.startTime);
if (message.isSuccess) {
setMbError("보냄");
setStartTime(message.startTime);
}
} catch (error) {
console.log('error'+ error)
}finally {
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
......@@ -139,60 +127,58 @@ const MyInfo = () => {
try {
setError("");
setLoading(true);
const confirmNum = {userMbnum : userRe.userMbnum, number : number, startTime : startTime};
const confirmNum = { userMbnum: userRe.userMbnum, number: number, startTime: startTime };
const message = await authApi.confirmNum(confirmNum);
setMbError(message);
if(message === "성공"){
if (message === "성공") {
setConfirmMb(true);
console.log("인증완료");
}
} catch (error) {
catchErrors(error, setError);
}finally {
} finally {
setLoading(false);
}
}
const validationPw = () => {
if(userRe.userPassword !== userRe.userRePassword){
return false;
}else{return true;}
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){
if (confirmMb) {
if (validPw) {
const userData = userRe;
//서버로 전송
const error = await authApi.modifyUser(userData);
if(error === "성공"){
if (error === "성공") {
alert("회원정보수정에 성공하였습니다.")
}else{
} else {
setErrorMsg(error);
alert("형식에 맞게 다시 작성해주세요");
}
}else{
} else {
throw new Error("비밀번호가 일치하지 않습니다.");
}
}else{
} else {
throw new Error("핸드폰 번호를 인증해주세요.");
}
} catch (error) {
//에러전송
catchErrors(error, setError);
} finally {
setLoading(false);
}
}
const handleOnclickOut = (e) => {
setConfirmMb(false);
}
const handleOnClick = (e) => {
e.preventDefault();
handleOnclickOut(e);
......@@ -201,7 +187,6 @@ const MyInfo = () => {
return (
<>
{/* 마이페이지 창 */}
<div className={`${styles.main}`}>
<span className={styles.title}>마이페이지</span>
<div className={`d-flex justify-content-around`}>
......@@ -215,7 +200,6 @@ const MyInfo = () => {
</div>
</div>
</div>
{/* 프로필 변경 모달창 */}
<div className="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabIndex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<form className="modal-content" onSubmit={handleOnSummitForm}>
......@@ -233,12 +217,10 @@ const MyInfo = () => {
</form>
</div>
</div>
{/* 기존 비밀번호 확인 모달창 */}
<div className="modal fade" id="verifyPassword" data-bs-backdrop="static" data-bs-keyboard="false" aria-hidden="true" aria-labelledby="verifyPasswordLabel" tabIndex="-1">
<div className="modal-dialog modal-dialog-centered modal-dialog-centered">
{page ?
<><form className="modal-content" onSubmit={handleOnSummitVerify}>
<form className="modal-content" onSubmit={handleOnSummitVerify}>
<div className="modal-header">
<h5 className="modal-title" id="verifyPasswordLabel">기존 비밀번호 확인</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close" onClick={handleOnClick}></button>
......@@ -247,38 +229,38 @@ const MyInfo = () => {
<div className="d-flex flex-column">
<div className="d-flex justify-content-around align-items-center my-4">
<label className={styles.signupLabel}>현재 비밀번호</label>
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userPassword" placeholder="8~11자리 사이" onChange={handlePwOnChange} onKeyPress={enterKey} maxLength="11" />
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userPassword" placeholder="8~11자리 사이" onChange={handlePwOnChange} onKeyPress={enterKey} maxLength="11" />
</div>
</div>
</div>
<div className="modal-footer">
<button type="submit" className={`rounded my-3 fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`} disabled={loading}>확인</button>
</div>
</form></>
: <><form className={`modal-content d-flex col-md-6 col-12 justify-content-center d-flex flex-column`} onSubmit={handleOnSummit}>
</form>
: <form className={`modal-content d-flex col-md-6 col-12 justify-content-center d-flex flex-column`} onSubmit={handleOnSummit}>
<div className="modal-header">
<h5 className="modal-title" id="modifyLabel">회원정보 수정</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close" onClick={handleOnClick}></button>
</div>
<div className={`modal-body`}>
<div className="d-flex flex-column">
<div className="d-flex flex-column">
<div className={styles.inputContent}>
<label className={styles.signupLabel}>이름</label>
<input className={`${styles.input} ${styles.inputSize}`} type="text" name="userName" placeholder="이름을 입력해주세요" onChange={handleUserOnChange} maxLength="11" />
<input className={`${styles.input} ${styles.inputSize}`} type="text" name="userName" placeholder="이름을 입력해주세요" onChange={handleUserOnChange} maxLength="11" />
</div>
{errorMsg.errorName && <p className={styles.passwordConfirmError}>이름을 입력해주세요</p>}
</div>
<div className="d-flex flex-column">
<div className={styles.inputContent}>
<label className={styles.signupLabel}>이메일</label>
<input className={`${styles.input} ${styles.inputSize}`} type="email" name="userEmail" placeholder="이메일을 입력해주세요" onChange={handleUserOnChange} maxLength="20" />
<input className={`${styles.input} ${styles.inputSize}`} type="email" name="userEmail" placeholder="이메일을 입력해주세요" onChange={handleUserOnChange} maxLength="20" />
</div>
{errorMsg.errorEmail && <p className={styles.passwordConfirmError}>이메일을 입력해주세요</p>}
</div>
<div className="d-flex flex-column">
<div className={styles.inputContent}>
<label className={styles.signupLabel}>별명</label>
<input className={`${styles.input} ${styles.inputSize}`} type="text" name="userNickName" placeholder="10자리 이내" onChange={handleUserOnChange} maxLength="10" />
<input className={`${styles.input} ${styles.inputSize}`} type="text" name="userNickName" placeholder="10자리 이내" onChange={handleUserOnChange} maxLength="10" />
</div>
{errorMsg.errorNickName && <p className={styles.passwordConfirmError}>10 이내로 입력해주세요.</p>}
</div>
......@@ -287,13 +269,12 @@ const MyInfo = () => {
<div className={styles.inputContent}>
<label className={styles.signupLabel}>휴대폰 번호</label>
<div className="d-flex col-md-auto">
<input className={`${styles.input} `} type="number" name="userMbnum" placeholder="-없이 11자리 입력" onChange={handleUserOnChange} min="" max="99999999999" />
<input className={`${styles.input} `} type="number" name="userMbnum" placeholder="-없이 11자리 입력" onChange={handleUserOnChange} min="" max="99999999999" />
<button type="button" disabled={loading} className={`rounded-2 mt-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} data-bs-toggle="collapse" data-bs-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample" onClick={handleOnClickMbnum}>인증번호받기</button>
</div>
</div>
{errorMsg.errorMbnum && <p className={styles.passwordConfirmError}>-없이 숫자 11자리를 입력해주세요.</p>}
<div className="collapse" id="collapseExample">
{/* <div className="d-flex col-md-auto justify-content-end"> */}
<div className="d-flex justify-content-around mt-3">
<label className={`${styles.confirm}`}>인증하기</label>
<div>
......@@ -311,7 +292,7 @@ const MyInfo = () => {
<div className="d-flex flex-column">
<div className={styles.inputContent}>
<label className={styles.signupLabel}> 비밀번호</label>
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userPassword" placeholder="8~11자리 사이" onChange={handleUserOnChange} maxLength="11" />
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userPassword" placeholder="8~11자리 사이" onChange={handleUserOnChange} maxLength="11" />
</div>
{errorMsg.errorPassword && <p className={styles.passwordConfirmError}>8~11자리 사이로 입력해주세요.</p>}
......@@ -320,7 +301,7 @@ const MyInfo = () => {
<div className="d-flex flex-column">
<div className={styles.inputContent}>
<label className={styles.signupLabel}> 비밀번호 확인</label>
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userRePassword" placeholder="8~11자리 사이" onChange={handleUserOnChange} maxLength="11" />
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userRePassword" placeholder="8~11자리 사이" onChange={handleUserOnChange} maxLength="11" />
</div>
{errorMsg.errorRePassword && <p className={styles.passwordConfirmError}>비밀번호가 일치하지 않습니다.</p>}
......@@ -331,7 +312,7 @@ const MyInfo = () => {
<button type="button" className="btn btn-secondary rounded my-3 py-2 fs-5" data-bs-dismiss="modal" onClick={handleOnClick} disabled={loading}>닫기</button>
<button type="submit" className={`rounded my-3 py-2 fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`} disabled={loading}>수정하기</button>
</div>
</form></>}
</form>}
</div>
</div>
</>
......
.main{
.main {
display: flex;
flex-direction: column;
align-items: center;
......@@ -6,7 +6,7 @@
width: 100%;
}
.title{
.title {
display: flex;
justify-content: center;
color: #FEDC00;
......@@ -14,7 +14,7 @@
margin: 2rem 0;
}
.confirm{
.confirm {
color: black;
padding-right: 8px;
text-align: center;
......@@ -25,144 +25,155 @@
.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;
}
.userName {
color: white;
font-size: 1.5rem;
}
.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;
}
.box:hover{
.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{
}
.hoverTxt {
display: none;
position:absolute;
top:4rem;
left:1.6rem;
color : #FEDC00;
position: absolute;
top: 4rem;
left: 1.6rem;
color: #FEDC00;
font-size: 1.5rem;
}
.box:hover .hoverTxt{
.box:hover .hoverTxt {
display: block;
}
.profile{
.profile {
width: 10rem;
height: 10rem;
&:hover {
opacity: 0.5;
}
}
.profile: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 {
margin: 0.5rem 0 0 0;
padding: 0.5rem 0 0.5rem 0;
border-radius: 3px;
text-align: center;
}
input[type=password]{
input[type=password] {
font-family: 'Courier New', Courier, monospace;
}
}
input::placeholder{
font-family: 'HangeulNuriB'
}
input::placeholder {
font-family: 'HangeulNuriB'
}
.inputSize{
width: 15.3rem;
}
.inputSize {
width: 15.3rem;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
}
.butterYellowAndBtn{
.butterYellowAndBtn {
color: black;
font-size: 1rem;
background-color: #FEDC00;
background-color: #FEDC00;
border: 1px solid black;
text-align: center;
}
}
.btnHover:hover{
.btnHover:hover {
background-color: black;
color: #FEDC00;
transition: ease-out;
border: 1px solid #FEDC00 ;
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;
}
.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: 2rem;
margin: 2rem 0;
}
.box{
width:8rem;
margin: 0px 1rem;
position: relative;
}
.profile{
@media (max-width: 576px) {
.title {
display: flex;
justify-content: center;
color: #FEDC00;
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{
.userName {
color: white;
font-size: 1.1rem;
}
.hoverTxt {
display: none;
position:absolute;
top:3.2rem;
left:1.7rem;
position: absolute;
top: 3.2rem;
left: 1.7rem;
color : #FEDC00;
font-size: 1rem;
}
......
import { Link } from "react-router-dom";
import { useAuth } from "../../context/auth_context.js"
const SubNav = () => {
const { user, logout } = useAuth();
return (
<nav className="nav justify-content-end py-1">
{(user.id === 0) ? <>
<Link className="nav-link text-white" to="/login">로그인</Link>
<Link className="nav-link text-white" to="/signup" >회원가입</Link> </>
: <>{(user.role === "admin") ?
<Link className="nav-link text-white" to="/admin">관리자페이지</Link>
: ((user.role === "member") ?
<Link className="nav-link text-white" to="/mypage">마이페이지</Link>
: <Link className="nav-link text-white" to="/guest">예매확인</Link>)}
<Link className="nav-link text-white" to="/" onClick={logout}>로그아웃</Link></>
{(user.id === 0)
?
<>
<Link className="nav-link text-white" to="/login">로그인</Link>
<Link className="nav-link text-white" to="/signup" >회원가입</Link>
</>
:
<>
{(user.role === "admin")
?
<Link className="nav-link text-white" to="/admin">관리자페이지</Link>
: ((user.role === "member")
?
<Link className="nav-link text-white" to="/mypage">마이페이지</Link>
: <Link className="nav-link text-white" to="/guest">예매확인</Link>)
}
<Link className="nav-link text-white" to="/" onClick={logout}>로그아웃</Link>
</>
}
</nav>
</nav>
)
}
export default SubNav
\ No newline at end of file
export default SubNav
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