Commit ba5429cf authored by Kim, Subin's avatar Kim, Subin
Browse files

master 병합

parent c465b924
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 (
<>
<div className="d-flex flex-column">
<span className={styles.title}>마이페이지</span>
<div className="d-flex flex mh-100">
<img src="/images/cat.jpg" className="img-thumbnail rounded-circle" />
<div className={`d-flex justify-content-around`}>
<div className={`${styles.box}`}>
<p className={`${styles.hoverTxt}`}>프로필 변경</p>
<img src={`/upload/${profile}`} className={`figure-img img-fluid rounded-circle ${styles.img} ${styles.profile}`} role="button" data-bs-toggle="modal" data-bs-target="#staticBackdrop" />
</div>
<div className="d-flex flex-column py-2 justify-content-around">
<span className={`${styles.userName}`}>{`${userNickName}`} 반갑습니다!</span>
<button className={`rounded my-2 fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`} data-bs-toggle="modal" href="#verifyPassword" >회원정보 수정</button>
</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}>
<div className="modal-header">
<h5 className="modal-title" id="staticBackdropLabel">프로필변경</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<input type="file" onChange={handleOnChange} />
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
<button type="submit" className={`rounded fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`}>변경</button>
</div>
</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}>
<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>
</div>
<div className="modal-body">
<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" />
</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}>
<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={styles.inputContent}>
<label className={styles.signupLabel}>이름</label>
<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" />
</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" />
</div>
{errorMsg.errorNickName && <p className={styles.passwordConfirmError}>10 이내로 입력해주세요.</p>}
</div>
<div className="d-flex flex-column">
<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" />
<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 justify-content-around mt-3">
<label className={`${styles.confirm}`}>인증하기</label>
<div>
<span>{`${userNickName}`} 반갑습니다!</span>
<button>수정</button>
<input className={`${styles.input}`} type="number" placeholder="인증번호를 입력" onChange={handleOnChangeMb} />
<button type="button" className={`rounded-2 py-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} onClick={handleOnClickMbConfirm}>확인</button>
<button type="button" className={`rounded-2 py-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} onClick={handleOnClickMbnum}>재전송</button>
</div>
</div>
{(mbError === "재전송") && <p className={styles.passwordConfirmError}>유효시간이 만료되었습니다. 재전송해주세요.</p>}
{(mbError === "보냄") && <p className={styles.passwordConfirmError}>5분이내에 입력해주세요.</p>}
{(mbError === "성공") && <p className={styles.passwordConfirmError}>인증되었습니다.</p>}
{(mbError === "실패") && <p className={styles.passwordConfirmError}>인증번호를 다시 입력해주세요.</p>}
</div>
</div>
<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" />
</div>
{errorMsg.errorPassword && <p className={styles.passwordConfirmError}>8~11자리 사이로 입력해주세요.</p>}
</div>
<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" />
</div>
{errorMsg.errorRePassword && <p className={styles.passwordConfirmError}>비밀번호가 일치하지 않습니다.</p>}
</div>
</div>
<div className="modal-footer">
<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>}
</div>
</div>
</>
)
}
......
.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: 25px;
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: 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
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 (
<nav className="nav justify-content-evenly border border-start-0 border-end-0 border-white border-2 py-1">
<a className="nav-link text-white" href="/movielist">영화</a>
<a className="nav-link text-white" href="/ticket">빠른예매</a>
<a className="nav-link text-white" href="/theater">극장</a>
<Link className="nav-link text-white" to="/movielist">영화</Link>
<Link className="nav-link text-white" to="/ticket">빠른예매</Link>
<Link className="nav-link text-white" to="/theater">극장</Link>
<Search search={search} setSearch={setSearch} handleClick={searchMovie} />
</nav>
)
......
import { Link } from "react-router-dom";
import { useAuth } from "../../context/auth_context.js"
const SubNav = () => {
const { user, logout } = useAuth();
return (
<> {(user) ?
<nav className="nav justify-content-end py-1">
{(user.role === "member")
? <Link className="nav-link text-white" to="/mypage">마이페이지</Link>
: <Link className="nav-link text-white" to="/admin">관리자페이지</Link>}
<Link className="nav-link text-white" to="/" onClick={logout}>로그아웃 </Link>
</nav> :
<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>
</>}
</nav>
}
</>
)
}
export default SubNav
\ No newline at end of file
import styles from "./reservation-details.module.scss";
const ReservationDetails = () => {
return (
<div className={`d-flex flex-column align-items-center ${styles.width}`}>
<div className={`${styles.header}`}>나의 예매 내역</div>
<div className={`${styles.body}`}>
<div className={`d-flex justify-content-around align-items-center py-3`}>
<div className={`${styles.span} d-flex justify-content-center`}>
<span className={`${styles.layout}`}>영화 포스터</span>
</div>
<div className={`${styles.span} d-flex flex-column`}>
<span className={`${styles.layout}`}>영화제목</span>
<span className={`${styles.layout}`}>예매확인번호</span>
<span className={`${styles.layout}`}>예매날짜</span>
<span className={`${styles.layout}`}>상영관</span>
<span className={`${styles.layout}`}>좌석정보</span>
<span className={`${styles.layout}`}>결제금액</span>
<span className={`${styles.layout}`}>결제수단</span>
</div>
</div>
</div>
<div className={`${styles.header}`}>나의 리뷰</div>
</div>
)
}
export default ReservationDetails
\ No newline at end of file
export { default } from "./ReservationDetails"
\ No newline at end of file
.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
......@@ -26,7 +26,7 @@ const SearchResult = () => {
}
return (
<>
<div className="container">
{result.length !== 0 ? (
<>
<h3 className="text-white text-center my-5">'{title}' 관한 검색 결과입니다.</h3>
......@@ -36,7 +36,7 @@ const SearchResult = () => {
</>
) : <h3 className="text-white text-center my-5 vh-100" style={{ wordBreak: "keep-all" }}>'{title}' 관한 검색 결과가 존재하지 않습니다.</h3>
}
</>
</div>
)
}
......
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(<span className="me-3" style={{color:"gray"}}>{String.fromCharCode(rowIndex + 65)}</span>)
// console.log(String.fromCharCode(rowIndex+65))
for (let colIndex = 0; colIndex < props.allSeat.col; colIndex++) {
table.push(
<span>
<button className={props.selectedSeats.find(el => el === String.fromCharCode(rowIndex + 65) + String(colIndex + 1)) ? styles.on : styles.btn} name={`${String.fromCharCode(rowIndex + 65)}${colIndex + 1}`} type="button" onClick={handleClick}> {colIndex + 1} </button>
</span>
)
if (theaterInfo) {
for (let rowIndex = 0; rowIndex < theaterInfo.rows; rowIndex++) {
table.push(<span className="me-3" style={{ color: "gray" }}>{String.fromCharCode(rowIndex + 65)}</span>)
for (let colIndex = 0; colIndex < theaterInfo.columns; colIndex++) {
table.push(<span>
{reservedSeats.find(el => el === String(rowIndex + 1) + '-' + String(colIndex + 1))
?
<button className={styles.btnBlock} name={rowIndex + 1} id={colIndex + 1} type="button" disabled>{colIndex + 1}</button>
:
<button className={selectedSeats.find(el => el === String(rowIndex + 1) + '-' + String(colIndex + 1)) ? styles.on : styles.btn} name={rowIndex + 1} id={colIndex + 1} type="button" onClick={handleClick}> {colIndex + 1} </button>
}
</span>)
}
table.push(<br />)
}
}
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)
} else {
if (props.selectedSeats.length > num - 1) {
alert("선택한 좌석이 예매인원보다 많습니다.")
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 {
//추가
props.setSelectedSeats([...props.selectedSeats, event.target.name])
if (selectedSeats.length > num - 1) alert("선택한 좌석이 예매인원보다 많습니다.")
else setSelectedSeats([...selectedSeats, event.target.name + '-' + event.target.id])
}
}
}
return (
<div className="text-center">
{console.log(props.selectedSeats)}
<div className="mb-2" style={{ backgroundColor: "gray" }}>Screen</div>
{table}
</div>
......
.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
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 <Redirect to="/login" />;
}
return (
// 데이터 입력과 유효성 검사 후 보이는 경고창
<form className={`d-flex col-md-6 col-12 justify-content-center`} onSubmit={handleOnSummit}>
<div className="d-flex flex-column">
<span className={styles.title}>회원가입</span>
<div className="d-flex flex-column">
<div className={styles.inputContent}>
<label className={styles.signupLabel}>아이디</label>
<div className="d-flex col-md-auto">
<input className={styles.input} type="text" name="userId" placeholder="5~10자리 사이" onChange={handleUserOnChange} maxLength="10" required />
<button type="button" disabled={loading} name="errorId" className={`rounded-2 mt-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} onClick={handleOnClickId}>중복확인</button>
<input className={`${styles.input} ${styles.inputSize}`} type="text" name="userId" placeholder="5~10자리 사이" onChange={handleUserOnChange} maxLength="10" />
</div>
{errorMsg.errorId && <p className={styles.errorMsg}>5~10자리 사이로 입력해주세요.</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="userName" placeholder="이름을 입력해주세요" onChange={handleUserOnChange} maxLength="20" />
</div>
{(overlapId === false) && errorMsg.errorId && <p className={styles.passwordConfirmError}>5~10자리 사이로 입력해주세요.</p>}
{overlapId && (errorMsg.errorId === false) && <p className={styles.passwordConfirmError}>아이디 중복이 확인되었습니다.</p>}
{(errorMsg.errorId === false) && (overlapId === false) && <p className={styles.passwordConfirmError}>아이디 중복확인을 해주세요.</p>}
{errorMsg.errorName && <p className={styles.errorMsg}>이름을 입력해주세요</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" required />
<input className={`${styles.input} ${styles.inputSize}`} type="email" name="userEmail" placeholder="이메일을 입력해주세요" onChange={handleUserOnChange} maxLength="20" />
</div>
{errorMsg.errorEmail && <p className={styles.passwordConfirmError}>이메일을 입력해주세요</p>}
{errorMsg.errorEmail && <p className={styles.errorMsg}>이메일을 입력해주세요</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" required />
<input className={`${styles.input} ${styles.inputSize}`} type="text" name="userNickName" placeholder="10자리 이내" onChange={handleUserOnChange} maxLength="20" />
</div>
{errorMsg.errorNickName && <p className={styles.passwordConfirmError}>10 이내로 입력해주세요.</p>}
{errorMsg.errorNickName && <p className={styles.errorMsg}>10 이내로 입력해주세요.</p>}
</div>
<div className="d-flex flex-column">
<div className={styles.inputContent}>
<label className={styles.signupLabel}>생년월일</label>
<input className={`${styles.input} ${styles.inputSize} ${styles.input.placeholder}`} type="number" name="userBirthday" placeholder="6자리(예시: 991225)" onChange={handleUserOnChange} min="0" max="999999" required />
<input className={`${styles.input} ${styles.inputSize} ${styles.input.placeholder}`} type="number" name="userBirthday" placeholder="6자리(예시: 991225)" onChange={handleUserOnChange} min="0" max="999999" />
</div>
{errorMsg.errorBirthday && <p className={styles.passwordConfirmError}>숫자 6자리를 입력해주세요.</p>}
{errorMsg.errorBirthday && <p className={styles.errorMsg}>숫자 6자리를 입력해주세요.</p>}
</div>
<div className="d-flex flex-column">
<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" required />
<button type="button" disabled={loading} name="errorId" className={`rounded-2 mt-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} onClick={handleOnClickMbnum}>인증번호받기</button>
<input className={`${styles.input} ${styles.input2}`} type="number" name="userMbnum" placeholder="-없이 11자리 입력" onChange={handleUserOnChange} min="0" 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.errorMsg}>-없이 숫자 11자리를 입력해주세요.</p>}
<div className="collapse" id="collapseExample">
<div className="d-flex justify-content-between mt-3">
<label className={`${styles.confirm}`}>인증하기</label>
<div>
<input className={`${styles.input} ${styles.input2}`} type="number" placeholder="인증번호를 입력" onChange={handleOnChangeMb} />
<button type="button" className={`rounded-2 py-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} onClick={handleOnClickMbConfirm}>확인</button>
<button type="button" className={`rounded-2 py-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} onClick={handleOnClickMbnum}>재전송</button>
</div>
</div>
{(mbError === "재전송") && <p className={styles.errorMsg}>유효시간이 만료되었습니다. 재전송해주세요.</p>}
{(mbError === "보냄") && <p className={styles.errorMsg}>5분이내에 입력해주세요.</p>}
{(mbError === "성공") && <p className={styles.errorMsg}>인증되었습니다.</p>}
{(mbError === "실패") && <p className={styles.errorMsg}>인증번호를 다시 입력해주세요.</p>}
</div>
{errorMsg.errorMbnum && <p className={styles.passwordConfirmError}>-없이 숫자 11자리를 입력해주세요.</p>}
</div>
<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" required />
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userPassword" placeholder="8~11자리 사이" onChange={handleUserOnChange} maxLength="20" />
</div>
{errorMsg.errorPassword && <p className={styles.passwordConfirmError}>8~11자리 사이로 입력해주세요.</p>}
{errorMsg.errorPassword && <p className={styles.errorMsg}>8~11자리 사이로 입력해주세요.</p>}
</div>
<div className="d-flex flex-column">
<div className={styles.inputContent}>
<div className={`d-flex ${styles.inputContent}`}>
<label className={styles.signupLabel}>비밀번호 확인</label>
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userRePassword" placeholder="8~11자리 사이" onChange={handleUserOnChange} maxLength="11" required />
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userRePassword" placeholder="8~11자리 사이" onChange={handleUserOnChange} maxLength="20" />
</div>
{errorMsg.errorRePassword && <p className={styles.passwordConfirmError}>비밀번호가 일치하지 않습니다.</p>}
</div>
<button className={`rounded my-3 py-2 fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`} type="submit" disabled={loading}>가입하기</button>
</div>
</form>
......
......@@ -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;
......
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: '<div style="color:black; width:150px;text-align:center;padding:6px 0;">Butter Studio</div>'
});
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 ?
<div>
{console.log(cinemaInfo)}
<h2 className="m-5">{cinemaInfo.cinemaName}</h2>
<div className="my-3 text-center">
<img src="/images/movieTheater.jpg" style={{ width: "80%" }} />
</div>
<div className="m-3"> 상영관 : {cinemaInfo.theaterNum}</div>
<div className="m-3">{cinemaInfo.address}</div>
<div className="row justify-content-sm-center py-5">
<div className="col-sm-4 text-end">
<div className="m-2">
<img src="/images/icon-bus.png" style={{ width: "35px" }} />
<button className="px-3" name="대중교통 안내" id="transportation" value={cinemaInfo.transportation} type="button" onClick={handleClick} style={{ background: "black", borderLeftColor: "black", borderTopColor: "black", borderBottomColor: "black", color: "white", borderRightColor: currentInfo.title === "transportation" ? "white" : "black" }}>대중교통 안내
</button>
</div>
<div className="m-2">
<img src="/images/icon-car.png" style={{ width: "35px" }} />
<button className="px-3" name="자가용/주차 안내" id="parking" value={cinemaInfo.parking} type="button" onClick={handleClick} style={{ background: "black", borderLeftColor: "black", borderTopColor: "black", borderBottomColor: "black", color: "white", borderRightColor: currentInfo.title === "parking" ? "white" : "black" }}>자가용/주차 안내
</button>
</div>
<div className="m-2">
<img src="/images/icon-map.png" style={{ width: "35px" }} />
<button className="px-3" name="지도보기" id="address" value={cinemaInfo.address} type="button" onClick={handleClick} style={{ background: "black", borderLeftColor: "black", borderTopColor: "black", borderBottomColor: "black", color: "white", borderRightColor: currentInfo.title === "address" ? "white" : "black" }}>지도보기
</button>
</div>
</div>
<div className="col-sm-6">
<div className="m-2">
<div id="parking" style={{ display: currentInfo.title === "parking" ? 'block' : 'none' }}>{currentInfo.information}</div>
<div id="map" ref={container} style={{ width: "400px", height: "300px", display: currentInfo.title === "address" ? 'block' : 'none' }}></div>
<div id="transportaion" style={{ display: currentInfo.title === "transportation" ? 'block' : 'none' }} >{currentInfo.information}</div>
</div>
</div>
</div>
<div id="map"></div>
</div>
:
<div>
극장정보를 불러올 없습니다.
</div>}
</>
)
}
export default TheaterInfo
\ No newline at end of file
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import { 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 (
<div >
{console.log(props.ticketInfo.movieId)}
<div className="d-grid gap-2">
{movieList.length > 0
? movieList.map(movie => (
<button name={movie.id} className={`${props.ticketInfo.movieId == movie.id ? styles.on : styles.btn}`} onClick={handleClick}>
<button name={movie.id} className={`${ticketInfo.movieId == movie.id ? styles.on : styles.btn}`} onClick={handleClick}>
{movie.title}
</button>
))
......
import styles from "./ticketingTheater.module.scss"
const TicketingTheater = (props) => {
const TicketingTheater = ({ ticketInfo, cinemaInfo, setTicketInfo }) => {
function handleClick(event) {
// event.preventDefault()
console.log(event.target.name)
props.setTicketInfo({ ...props.ticketInfo, theater:event.target.name})
setTicketInfo({ ...ticketInfo, cinema: event.target.name })
}
return (
<div >
<div className="d-grid gap-2">
{props.theaterInfo.theater.length > 0
? props.theaterInfo.theater.map(name => (
<button name={name} className={`${props.ticketInfo.theater === name ? styles.on : styles.btn}`} onClick={handleClick}>{name}</button>
))
: <div>영화관 정보가 존재하지 않습니다.</div>}
<button name={cinemaInfo.cinemaName} className={`${ticketInfo.cinema === cinemaInfo.cinemaName ? styles.on : styles.btn}`} onClick={handleClick}>{cinemaInfo.cinemaName}</button>
</div>
</div>
)
......
const TicketingTimeTable = (props) => {
const TicketingTimeTable = ({ ticketInfo }) => {
return (
<div>
<div className="text-center" style={{color:"white"}}>
{console.log(props.ticketInfo.movieId, props.ticketInfo.theater)}
{props.ticketInfo.movieId && props.ticketInfo.theater
? <div>{props.ticketInfo.movieId} {props.ticketInfo.theater}</div>
<div className="text-center" style={{ color: "white" }}>
{ticketInfo.movieId && ticketInfo.cinema
? <div>{ticketInfo.movieId} {ticketInfo.cinema}</div>
: <div>영화와 극장을 모두 선택해주세요.</div>}
</div>
</div>
......
import { useEffect, useState } from 'react'
import movieApi from '../apis/movie.api.js'
const Video = (props) => {
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 (
<div>
{videoUrls.length > 0
......
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);
}, []);
......
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 (
<>
<BoxOffice />
<Collection />
<BoxOffice TMDB_TopRated_Data={TMDB_TopRated_Data} />
<Collection TMDB_TopRated_Data={TMDB_TopRated_Data} />
<Footer />
</>
)
......
......@@ -3,28 +3,15 @@ import MovieChart from '../components/MovieChart.js'
import MovieComing from '../components/MovieComing.js'
const MovieListPage = () => {
const [state, setState] = useState(true)
const [state, setState] = useState(0)
return (
<div className="container">
<div>
<ul className="nav nav-tabs justify-content-center my-4 border-0" id="myTab" role="tablist">
<li className="nav-item" role="presentation">
<button className="nav-link active mx-auto" style={{color:"white", borderColor: "black", backgroundColor:"black", borderBottom: state? "3px solid":"none" ,borderBottomColor:state?"#FEDC00":"black"}} id="moviechart-tab" data-bs-toggle="tab" data-bs-target="#moviechart" type="button" role="tab" aria-controls="moviechart" aria-selected="true" onClick={() => setState(true)}>무비차트</button>
</li>
<li className="nav-item" role="presentation">
<button className="nav-link mx-auto" style={{color:"white", borderColor: "black",backgroundColor:"black", borderBottom: state?"none" :"3px solid", borderBottomColor:state?"black": "#FEDC00"}} id="moviecomming-tab" data-bs-toggle="tab" data-bs-target="#moviecomming" type="button" role="tab" aria-controls="moviecomming" aria-selected="false" onClick={() => setState(false)}>상영예정작</button>
</li>
</ul>
</div>
<div className="tab-content" id="myTabContent">
<div className="tab-pane fade show active" id="moviechart" role="tabpanel" aria-labelledby="moviechart-tab">
<MovieChart />
</div>
<div className="tab-pane fade" id="moviecomming" role="tabpanel" aria-labelledby="moviecomming-tab">
<MovieComing />
</div>
<div className="text-center my-5">
<button className="mx-auto" style={{ color: "white", borderColor: "black", backgroundColor: "black", borderBottom: !state ? "3px solid" : "none", borderBottomColor: !state ? "#FEDC00" : "black" }} type="button" onClick={() => setState(0)}>무비차트</button>
<button className="mx-auto" style={{ color: "white", borderColor: "black", backgroundColor: "black", borderBottom: !state ? "none" : "3px solid", borderBottomColor: !state ? "black" : "#FEDC00" }} type="button" onClick={() => setState(1)}>상영예정작</button>
</div>
<div>{state === 0 ? <MovieChart /> : <MovieComing />}</div>
</div>
)
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment