diff --git a/src/App.jsx b/src/App.jsx index e579f2f..92d4931 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -57,6 +57,7 @@ import AdminEvent from "./pages/adminpage/event/AdminEvent"; import AdminEventDetail from "./pages/adminpage/event/AdminEventDetail"; import AdminVision from "./pages/adminpage/vision/AdminVision"; import AdminVisionDetail from "./pages/adminpage/vision/AdminVisionDetail"; +import AdminVisionUpdate from "./pages/adminpage/vision/AdminVisionUpdate"; import AdminQuery from "./pages/adminpage/query/AdminQuery"; import AdminQueryDetail from "./pages/adminpage/query/AdminQueryDetail"; import AdminMypage from "./pages/adminpage/mypage/AdminMypage"; @@ -171,6 +172,7 @@ function App() { } /> } /> } /> + } /> } /> } /> } /> diff --git a/src/assets/icons/CheckRed.svg b/src/assets/icons/CheckRed.svg index bb6b94f..a3acfa3 100644 --- a/src/assets/icons/CheckRed.svg +++ b/src/assets/icons/CheckRed.svg @@ -1,9 +1,3 @@ -<<<<<<< HEAD - - - -======= ->>>>>>> b02da37bb73dbc412010324d1b03eaec22dae246 diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index e05944a..5af52ca 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -220,6 +220,8 @@ function Sidebar({onClose}) { } }; + const isLoggedIn = !!localStorage.getItem("accessToken"); + return ( @@ -227,14 +229,18 @@ function Sidebar({onClose}) { 시야 확인 + 소극장 공연 이벤트 확인 - 소극장 연극 게시판 Bar Icon - 로그인 - 회원가입 + {!isLoggedIn && ( + <> + 로그인 + 회원가입 + + )} 마이 페이지 diff --git a/src/components/board/PageNavigator.jsx b/src/components/board/PageNavigator.jsx index dfff1e6..e1fef0f 100644 --- a/src/components/board/PageNavigator.jsx +++ b/src/components/board/PageNavigator.jsx @@ -4,32 +4,42 @@ import ChevronLeft from "../../assets/icons/ChevronLeft.svg"; import ChevronRight from "../../assets/icons/ChevronRight.svg"; const PageNavigator = ({ currentPage, totalPages, onPageChange }) => { + const pagesPerGroup = 5; // 5개씩 끊어서 표시 + const currentGroup = Math.floor(currentPage / pagesPerGroup); + const startPage = currentGroup * pagesPerGroup; + const endPage = Math.min(startPage + pagesPerGroup, totalPages); + const handlePageClick = (page) => { - if (page >= 0 && page <= totalPages) { + if (page >= 0 && page < totalPages) { onPageChange(page); } }; return ( + {/* 이전 5개 이동 */} handlePageClick(currentPage - 1)} + visibility={currentGroup === 0 ? "hidden" : "visible"} + onClick={() => handlePageClick(startPage - pagesPerGroup)} /> - {Array.from({ length: totalPages }, (_, index) => ( + + {/* 현재 그룹의 페이지 번호 표시 */} + {Array.from({ length: endPage - startPage }, (_, index) => ( handlePageClick(index)} + key={startPage + index} + color={currentPage === startPage + index ? "#A00000" : undefined} + onClick={() => handlePageClick(startPage + index)} > - {index + 1} + {startPage + index + 1} ))} + + {/* 다음 5개 이동 */} handlePageClick(currentPage + 1)} + visibility={endPage >= totalPages ? "hidden" : "visible"} + onClick={() => handlePageClick(startPage + pagesPerGroup)} /> ); diff --git a/src/components/board/PostList.jsx b/src/components/board/PostList.jsx index a20e072..9d90910 100644 --- a/src/components/board/PostList.jsx +++ b/src/components/board/PostList.jsx @@ -92,8 +92,7 @@ const PostListWrapper = styled.table` margin-top: 32px; font-family: Pretendard, sans-serif; text-align: center; - - +table-layout: fixed; /* 고정된 레이아웃 */ th, td { @@ -118,10 +117,38 @@ const PostListWrapper = styled.table` td:nth-child(1) { text-align: left; padding-left: 50px; + min-width: 40%; + max-width: 50%; + } + td:nth-child(2) { + text-align: left; + padding-left: 50px; + width: 20%; + max-width: 190px; + } + td:nth-child(3) { + text-align: left; + padding-left: 50px; + width: 20%; + } + td:nth-child(4) { + text-align: left; + padding-left: 50px; + width: 20%; } th:nth-child(1) { text-align: left; padding-left: 94px; + min-width: 40%; + max-width: 50%; + } + th:nth-child(2) { + width:20%; + } + th:nth-child(3) { + width:20%; + } th:nth-child(4) { + width:20%; } td { @@ -129,13 +156,17 @@ const PostListWrapper = styled.table` border-bottom: 1px solid #E6E6E6; padding-top: 18px; padding-bottom: 18px; - + padding-right: 20px; /* Body-tiny-md */ font-family: Pretendard; font-size: 14px; font-style: normal; font-weight: 500; line-height: normal; + + overflow: hidden; /* 넘치는 내용 숨김 */ + white-space: nowrap; /* 줄바꿈 방지 */ + text-overflow: ellipsis; /* ... 처리 */ } tbody tr:hover { diff --git a/src/components/board/PostList2.jsx b/src/components/board/PostList2.jsx index cada59f..060a55e 100644 --- a/src/components/board/PostList2.jsx +++ b/src/components/board/PostList2.jsx @@ -113,15 +113,20 @@ const NavWrapper = styled.div` ` const Text = styled.div` - color: ${(props) => props.color ? props.color: '#000'}; - - /* Body-me */ + color: ${(props) => props.color || "#000"}; font-family: Pretendard; font-size: 16px; font-style: normal; font-weight: 500; line-height: 25px; /* 156.25% */ -` + text-align:left; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + word-break: break-word; +`; const Img = styled.img` height: 88px; width: 88px; diff --git a/src/components/buy/Step2.jsx b/src/components/buy/Step2.jsx index 023e085..598ca6e 100644 --- a/src/components/buy/Step2.jsx +++ b/src/components/buy/Step2.jsx @@ -16,7 +16,7 @@ const Step2 = () => { const navigate = useNavigate(); const location = useLocation(); const peopleCount = location.state?.peopleCount || 1; - const [selectedTicketId, setSelectedTicketId] = useState("1"); + const [selectedTicketName, setSelectedTicketName] = useState("일반 예매"); const url = `/tickets/${amateurId}/ticketInfo`; const { data, error, loading } = useCustomFetch(url, { @@ -32,18 +32,19 @@ const Step2 = () => { // 🎯 선택된 티켓 정보 찾기 - const selectedTicket = ticketInfo.tickets.find(ticket => ticket.amateurTicketId === selectedTicketId); + const selectedTicket = ticketInfo.tickets.find(ticket => ticket.ticketName === selectedTicketName); const ticketPrice = selectedTicket ? selectedTicket.price : 0; // 🎯 할인 선택 핸들러 const handleDiscountChange = (event) => { - setSelectedTicketId(event.target.value); + setSelectedTicketName(event.target.value); }; + const handleNextStep = () => { navigate('../step3', { state: { peopleCount, - selectedTicketId, + selectedTicketName, ticketInfo, }, }); @@ -69,22 +70,22 @@ const Step2 = () => { diff --git a/src/components/buy/Step3.jsx b/src/components/buy/Step3.jsx index aa42f14..21fe912 100644 --- a/src/components/buy/Step3.jsx +++ b/src/components/buy/Step3.jsx @@ -15,7 +15,7 @@ const Step3 = () => { const {amateurId} = useParams(); const navigate = useNavigate(); const location = useLocation(); - const { peopleCount = 1, selectedTicketId = '1' } = location.state || {}; + const { peopleCount = 1, selectedTicketName="일반 예매" } = location.state || {}; const url = `/tickets/${amateurId}/ticketInfo`; const { data, error, loading } = useCustomFetch(url, { @@ -32,9 +32,7 @@ const Step3 = () => { const memberInfo = data.result.reserveConfirmMemberDTO; // 선택된 티켓 정보 찾기 - const selectedTicket = ticketInfo.tickets.find( - (ticket) => ticket.amateurTicketId === selectedTicketId - ); + const selectedTicket = ticketInfo.tickets.find(ticket => ticket.ticketName === selectedTicketName); const ticketPrice = selectedTicket ? selectedTicket.price : 0; // 총 결제 금액 계산 const totalAmount = ticketPrice * peopleCount; @@ -43,12 +41,12 @@ const Step3 = () => { navigate('../step4', { state: { peopleCount, - selectedTicketId, + selectedTicketName, ticketInfo, + amateurTicketId: selectedTicket.amateurTicketId, }, }); }; - return ( diff --git a/src/components/buy/Step4.jsx b/src/components/buy/Step4.jsx index 949d56c..262da2c 100644 --- a/src/components/buy/Step4.jsx +++ b/src/components/buy/Step4.jsx @@ -8,20 +8,20 @@ const token = localStorage.getItem("accessToken"); const Step4 = () => { const navigate = useNavigate(); - const { amateurId } = useParams(); + // const { amateurTicketId } = useParams(); const [accountName, setAccountName] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); const isButtonActive = accountName.trim().length > 0; const location = useLocation(); - const { peopleCount, selectedTicketId,ticketInfo } = location.state || {}; + const { peopleCount, selectedTicketName="일반 예매",ticketInfo,amateurTicketId } = location.state || {}; + console.log("ticketId",amateurTicketId) const handleSubmit = async () => { if (!isButtonActive || isSubmitting) return; setIsSubmitting(true); - const url = `${import.meta.env.VITE_APP_SERVER_URL}/tickets/purchase/${amateurId}`; - + const url = `${import.meta.env.VITE_APP_SERVER_URL}/tickets/purchase/${amateurTicketId}`; try { const response = await fetch(url, { method: 'POST', @@ -51,9 +51,7 @@ const Step4 = () => { } }; // 선택된 티켓 정보 찾기 - const selectedTicket = ticketInfo.tickets.find( - (ticket) => ticket.amateurTicketId === selectedTicketId - ); + const selectedTicket = ticketInfo.tickets.find(ticket => ticket.ticketName === selectedTicketName); const ticketPrice = selectedTicket ? selectedTicket.price : 0; // 총 결제 금액 계산 const totalAmount = ticketPrice * peopleCount; diff --git a/src/components/mypage/myticket/TicketContainer.jsx b/src/components/mypage/myticket/TicketContainer.jsx index 6906d87..b6fb718 100644 --- a/src/components/mypage/myticket/TicketContainer.jsx +++ b/src/components/mypage/myticket/TicketContainer.jsx @@ -1,4 +1,3 @@ -// components/detail/InfoWrapper.jsx import React from "react"; import styled from "styled-components"; import ChevronRight from "../../../assets/icons/ChevronRight.svg"; @@ -14,6 +13,7 @@ const TicketContainer = ({ alt, details, isDisabled }) => { reservationDate, reservationStatus, schedule, + cancelDate, } = details || {}; const korStatus = { @@ -21,7 +21,7 @@ const TicketContainer = ({ alt, details, isDisabled }) => { RESERVED: "예매 완료", EXPIRED: "사용 완료", CANCEL_AWAIT: "취소 대기중", - CANCELED: "취소 완료", + CANCELED: "예매 취소", } const navigate = useNavigate(); @@ -37,42 +37,37 @@ const TicketContainer = ({ alt, details, isDisabled }) => { console.log(dayOfWeek); // 예: 수 return ( - + {alt} - + handleClick(memberTicketId)}>
{amateurShowName}{quantity}매
{reservationDate?.split('T')[0]} {place} {schedule?.split(' ')[0]} ({dayOfWeek}) {schedule?.split(' ')[1]} + >{cancelDate} {korStatus[reservationStatus]}
@@ -97,7 +92,8 @@ const Wrapper = styled.div` gap: 10px; border-radius: 3px; border: 1px solid var(--Gray-outline, #E6E6E6); - + background-color: ${({ reservationStatus }) => + reservationStatus === "CANCELED" ? "#F5F5F5" : "transparent"}; `; const InfoImage = styled.div` diff --git a/src/components/post/Comment.jsx b/src/components/post/Comment.jsx index f486c5c..2111ee8 100644 --- a/src/components/post/Comment.jsx +++ b/src/components/post/Comment.jsx @@ -10,8 +10,8 @@ import axios from "axios"; const token = localStorage.getItem("accessToken"); const muit_server = import.meta.env.VITE_APP_SERVER_URL; -function Comment({data, noneCommentIcon}) { - console.log('Comment.jsx', data); +function Comment({data, noneCommentIcon, isDeleted, setIsDeleted, isWrited, setIsWrited}) { + // console.log('Comment.jsx', data); const [isWriter, setIsWriter] = useState(data.nickname=='글쓴이'); const [isEditing, setIsEditing] = useState(false); @@ -37,6 +37,7 @@ function Comment({data, noneCommentIcon}) { if (response.ok) { alert("댓글이 삭제되었습니다."); + setIsDeleted(!isDeleted); // 필요하면 상태 업데이트 로직 추가 } else { alert(`삭제 실패: ${result.message}`); @@ -78,10 +79,10 @@ function Comment({data, noneCommentIcon}) { setIsReplying(true); } const reportHandler = async (commentId) => { - if (window.confirm("게시글을 신고하시겠습니까?")) { + if (window.confirm("댓글을 신고하시겠습니까?")) { try { console.log('신고할 댓글 ', commentId); - const response = await axios.post(`${muit_server}/reports/${commentId}?commentType=COMMENT`, + const response = await axios.post(`${muit_server}/comments/report/${commentId}?commentType=COMMENT`, {}, { headers: { @@ -132,7 +133,6 @@ function Comment({data, noneCommentIcon}) { ) : ( <> {/* setIsEditing(true)}>수정*/} - {console.log('댓글 닉네임', data.nickname)} 삭제 )} @@ -153,7 +153,7 @@ function Comment({data, noneCommentIcon}) { {Array.isArray(data.replies) && data.replies.length > 0 ? ( {data?.replies?.map((reply) => ( - + ))} ) : null} @@ -161,7 +161,7 @@ function Comment({data, noneCommentIcon}) {
- +
@@ -242,6 +242,7 @@ font-size: 16px; font-style: normal; font-weight: 500; line-height: 25px; /* 156.25% */ + white-space: pre-line; ` const EditInput = styled.input` width: 100%; diff --git a/src/components/post/CommentInputArea.jsx b/src/components/post/CommentInputArea.jsx index a927516..b31d8c6 100644 --- a/src/components/post/CommentInputArea.jsx +++ b/src/components/post/CommentInputArea.jsx @@ -9,7 +9,8 @@ import { GoX } from "react-icons/go"; const muit_server = import.meta.env.VITE_APP_SERVER_URL; const token = localStorage.getItem("accessToken"); {/* 에러 500 서버오류 의심? */} -function CommentInputArea({ postId, setCommentTrigger, commentTrigger, isReplying, setIsReplying }) { +function CommentInputArea({ postId, setCommentTrigger, + commentTrigger, isReplying, setIsReplying, isWrited, setIsWrited }) { // console.log('게시글', postId); const [memberId, setMemberId] = useState(1); const [comment, setComment] = useState(""); @@ -47,11 +48,14 @@ function CommentInputArea({ postId, setCommentTrigger, commentTrigger, isReplyin } }); - console.log(response); + // console.log(response); + console.log('작성 전', isWrited); if (response.data.isSuccess) { alert("댓글이 등록되었습니다."); setComment(""); // Clear the comment input after successful submission // setCommentTrigger(commentTrigger+1); // 🔹 댓글 등록 후 트리거 업데이트 + setIsWrited(!isWrited); + console.log('작성 후', isWrited); } else { setError("댓글 등록에 실패했습니다."); } diff --git a/src/components/post/Reply.jsx b/src/components/post/Reply.jsx index ec1d610..fc7e878 100644 --- a/src/components/post/Reply.jsx +++ b/src/components/post/Reply.jsx @@ -7,7 +7,7 @@ import { useState } from "react"; import axios from "axios"; const token = localStorage.getItem("accessToken"); const muit_server = import.meta.env.VITE_APP_SERVER_URL; -function Reply({key, data}) { +function Reply({key, data, isDeleted, setIsDeleted}) { console.log(data); console.log('리플라이 콘텐츠', data.content); @@ -32,6 +32,7 @@ function Reply({key, data}) { if (response.ok) { alert("댓글이 삭제되었습니다."); + setIsDeleted(!isDeleted); // 필요하면 상태 업데이트 로직 추가 } else { alert(`삭제 실패: ${result.message}`); @@ -43,10 +44,10 @@ function Reply({key, data}) { }; const reportHandler = async (commentId) => { - if (window.confirm("게시글을 신고하시겠습니까?")) { + if (window.confirm("댓글을 신고하시겠습니까?")) { try { console.log('신고할 답댓글 ', commentId); - const response = await axios.post(`${muit_server}/reports/${commentId}?commentType=REPLY`, + const response = await axios.post(`${muit_server}/comments/report/${commentId}?commentType=REPLY`, {}, { headers: { diff --git a/src/components/small-theater/CastList.jsx b/src/components/small-theater/CastList.jsx index 0f019dc..0aba473 100644 --- a/src/components/small-theater/CastList.jsx +++ b/src/components/small-theater/CastList.jsx @@ -22,13 +22,14 @@ function CastList() { // 캐스팅 정보 추출 const castings = data.result.castings; + const castingImages=data.result.castingImages return ( {castings.map((casting, index) => ( - {casting.actorName} + {casting.actorName} {casting.actorName} {casting.castingName} diff --git a/src/components/small-theater/CreditInfo.jsx b/src/components/small-theater/CreditInfo.jsx index de929fd..5600e33 100644 --- a/src/components/small-theater/CreditInfo.jsx +++ b/src/components/small-theater/CreditInfo.jsx @@ -47,7 +47,7 @@ const CreditsWrapper = styled.div` `; const CreditRow = styled.div` display: grid; - grid-template-columns: auto 1fr; /* Two columns for position and name */ + grid-template-columns: 120px 1fr; /* Two columns for position and name */ column-gap: 35px; /* Gap between position and name */ align-items: center; `; diff --git a/src/pages/EventCheck.jsx b/src/pages/EventCheck.jsx index f23a7dc..f0032c0 100644 --- a/src/pages/EventCheck.jsx +++ b/src/pages/EventCheck.jsx @@ -124,7 +124,7 @@ const Header = styled.div` ` const Container = styled.div` - width: 100%; + width: 1240px; font-family: Pretendard; padding: 100px; diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index ce7d6b0..d62fc90 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -6,7 +6,6 @@ import axios from 'axios'; import ArrowPrevIcon from '../assets/icons/ArrowPrev.svg'; import ArrowNextIcon from '../assets/icons/ArrowNext.svg'; -import useCustomFetch from "../hooks/fetchWithAxios"; import Upcoming from "./Upcoming"; // 색상, 폰트 상수, 레이아웃 (디자인 가이드) @@ -38,7 +37,7 @@ function Home() { fetchHotNow(); fetchTicketOpen(); fetchRanking(); - }, []); + }, [token]); //Hot Now const fetchHotNow = async () => { @@ -64,7 +63,7 @@ function Home() { // 오픈예정 const fetchTicketOpen = async () => { try { - const response = await useCustomFetch(`${baseURL}/musicals/open`, { + const response = await axios.get(`${baseURL}/musicals/open`, { headers: { Authorization: `Bearer ${token}`, } diff --git a/src/pages/Ranking.jsx b/src/pages/Ranking.jsx index 035f611..e3950fc 100644 --- a/src/pages/Ranking.jsx +++ b/src/pages/Ranking.jsx @@ -209,6 +209,7 @@ const CardImage = styled(Link)` height: 100%; object-fit: cover; display: block; + `; const CardRank = styled.div` @@ -287,6 +288,13 @@ const BottomPoster = styled(Link)` object-fit: cover; margin-bottom: 8px; border: 1px solid ${COLOR_GRAY_UNSELECTED}; + img { + transition: transform 0.2s ease; + } + + img:hover { + transform: scale(1.04); + } `; const BottomInfo = styled.div` diff --git a/src/pages/Upcoming.jsx b/src/pages/Upcoming.jsx index acc8e55..ed5e248 100644 --- a/src/pages/Upcoming.jsx +++ b/src/pages/Upcoming.jsx @@ -4,6 +4,7 @@ import styled from "styled-components"; import FormattedDate from "../components/date/FormattedDate"; // import useFetch from "../hooks/useFetch"; import useCustomFetch from "../hooks/useCustomFetch"; +import { Link } from 'react-router-dom'; //const token = import.meta.env.VITE_APP_ACCESS_TOKEN; const token = localStorage.getItem("accessToken"); @@ -94,7 +95,9 @@ const Upcoming = () => { style={{ zIndex: index === activeIndex ? 2 : 1 }} // 클릭된 이미지가 위로 onClick={() => handleMusicalClick(index)} > - {musical.name} + + {musical.name} + {index === activeIndex && (
@@ -117,7 +120,12 @@ const Upcoming = () => { {ticketListMusicals.map((musical) => ( {musical.dday} - {musical.name} + + + {musical.name} + + +
{musical.name} @@ -276,6 +284,7 @@ const TicketList = styled.div` `; const MusicalItem = styled.div` + position: relative; text-align: left; font-family: Pretendard; overflow: hidden; @@ -325,11 +334,10 @@ const MusicalItem = styled.div` `; const DdayBadge = styled.div` position: absolute; - top: 100px; /* 기존보다 아래로 이동 */ - left: 70px; /* 기존보다 오른쪽으로 이동 */ -width: 54px; + top: 13px; /* 기존보다 아래로 이동 */ + left: 11px; /* 기존보다 오른쪽으로 이동 */ +width: 35px; height: 20px; -flex-shrink: 0; display: flex; flex-direction: column; justify-content: center; @@ -343,4 +351,19 @@ font-size: 16px; font-style: normal; font-weight: 700; line-height: normal; -`; \ No newline at end of file +`; + +const CardLink = styled(Link)` + width: 100%; + height: 100%; + object-fit: cover; + display: block; + +`; + +const CardWrapper = styled.div` +&:hover { + transform: scale(1.04); + transition: transform 0.2s ease; +} +` \ No newline at end of file diff --git a/src/pages/adminpage/components/TheatreInfo.jsx b/src/pages/adminpage/components/TheatreInfo.jsx new file mode 100644 index 0000000..da0d005 --- /dev/null +++ b/src/pages/adminpage/components/TheatreInfo.jsx @@ -0,0 +1,84 @@ +import styled from "styled-components" +import location from '../../../assets/icons/location.svg'; +import ChevronRight from '../../../assets/icons/ChevronRight.svg'; +import { useNavigate } from "react-router-dom"; + +const TheatreInfo = (props) => { + const navigate = useNavigate(); + return ( + + + + +

{props?.data?.placeName}

+

{props?.data?.address}

+ + +

현재 공연

+ {navigate(`/detail/${props?.data?.musicalId}`)}}> + +   {props?.data?.musicalName} + +
+
+
+
+ ) +} + +const Container = styled.div` + +` +const TheaterInfo = styled.div` + width: 400px; + + h3{margin:0px;} + p{margin: 0px;} + + + .hr-line{ + border : 0px; + border-top: 1px solid #E6E6E6; + margin-bottom: 24px; + } + .title-B{ + font-size: 24px; + font-weight: 700; + } + + .body-M-500{ + font-size: 16px; + font-weight: 500; + color: #000000; + } + +` +const Text = styled.div` + margin-top:25px; + + display: flex; + align-items: center; + gap: 12px; + + .body-M-400{ + font-size: 16px; + font-weight: 500; + color: #919191; + } + + .ShowTitle{ + font-size: 16px; + font-weight: 700; + color: #000000; + + display: flex; + align-items: center; + } +` + +const MusicalLink = styled.div` + cursor: pointer; +` + +export default TheatreInfo; \ No newline at end of file diff --git a/src/pages/adminpage/small-theater/reservation/AdminSmallReserve.jsx b/src/pages/adminpage/small-theater/reservation/AdminSmallReserve.jsx index 0a5493c..8509d2a 100644 --- a/src/pages/adminpage/small-theater/reservation/AdminSmallReserve.jsx +++ b/src/pages/adminpage/small-theater/reservation/AdminSmallReserve.jsx @@ -58,7 +58,7 @@ export default function AdminSmallReserve() { statusText = "취소 중"; break; case "CANCELED": - statusText = "취소 완료"; + statusText = "예매 취소"; break; default: break; diff --git a/src/pages/adminpage/small-theater/reservation/AdminSmallReserveDetail.jsx b/src/pages/adminpage/small-theater/reservation/AdminSmallReserveDetail.jsx index 708f597..641fcc2 100644 --- a/src/pages/adminpage/small-theater/reservation/AdminSmallReserveDetail.jsx +++ b/src/pages/adminpage/small-theater/reservation/AdminSmallReserveDetail.jsx @@ -32,7 +32,7 @@ function mapStatusToKorean(reservationStatus) { case "CANCEL_AWAIT": return "취소 중"; case "CANCELED": - return "취소 완료"; + return "예매 취소"; default: return reservationStatus || ""; } @@ -47,7 +47,7 @@ function mapKoreanToStatus(koreanString) { return "EXPIRED"; case "취소 중": return "CANCEL_AWAIT"; - case "취소 완료": + case "예매 취소": return "CANCELED"; default: return ""; @@ -242,7 +242,7 @@ export default function AdminSmallReserveDetail() { - + diff --git a/src/pages/adminpage/vision/AdminVisionDetail.jsx b/src/pages/adminpage/vision/AdminVisionDetail.jsx index 04753d1..762da8a 100644 --- a/src/pages/adminpage/vision/AdminVisionDetail.jsx +++ b/src/pages/adminpage/vision/AdminVisionDetail.jsx @@ -1,8 +1,578 @@ +// 샤롯시어터 +import React, { useState, useEffect } from 'react'; +import { useParams, useNavigate, Link } from 'react-router-dom'; +import styled from 'styled-components'; +import axios from 'axios'; +import SearchBar_Mock from "../components/SearchBar_Mock"; +import { + A_Before, + B_Before, + C_Before, + D_Before, + E_Before, + F_Before, + G_Before, + H_Before, + I_Before, + J_Before, + K_Before, + L_Before, + M_Before, + N_Before, + O_Before, + A_After, + B_After, + C_After, + D_After, + E_After, + F_After, + G_After, + H_After, + I_After, + J_After, + K_After, + L_After, + M_After, + N_After, + O_After +} from "../../../assets/theaterSeat/charlotte/charlotteSeat" +import TheatreInfo from '../components/TheatreInfo'; +const COLOR_WHITE = "#FFFFFF"; +const COLOR_MUIT_RED = "#A00000"; +const COLOR_GRAY_MAINTEXT = "#000000"; +const COLOR_GRAY_UNSELECTED = "#C1C1C1"; +const COLOR_GRAY_SUB = "#919191"; + +const baseURL = import.meta.env.VITE_APP_SERVER_URL; +const token_admin = localStorage.getItem("adminToken"); export default function AdminVisionDetail() { -} \ No newline at end of file + const { placeId } = useParams(); + const navigate = useNavigate(); + const [theaterInfo, setTheaterInfo] = useState(null); + useEffect(() => { + if (placeId) { + fetchTheaterDetail(placeId); + } + }, [placeId]); + // 극장 정보 상세 조회 API + const fetchTheaterDetail = async (placeId) => { + try { + const res = await axios.get(`${baseURL}/admin/views/${placeId}`, { + headers: { + Authorization: `Bearer ${token_admin}`, + }, + }); + const data = res.data.result || {}; + const refined = { + palceId: data.theatreId, + placeName: data.theatreName, + address: data.address, + + musicalId: data.musicalId, + musicalName: data.musicalName, + theatrePic: data.theatrePic, + allSeatImg: data.allSeatImg, + }; + setTheaterInfo(refined); + } catch (err) { + console.error("극장 정보 조회 실패:", err); + alert("해당 극장을 조회할 수 없습니다."); + navigate("/adminpage/vision"); + } + }; + + const [activeFloor, setActiveFloor] = useState(1); + const [selectedArea, setSelectedArea] = useState(null); + const [selectedSeatData, setSelectedSeatData] = useState(null); + const [seatStates, setSeatStates] = useState({ + A: "Before", + B: "Before", + C: "Before", + D: "Before", + E: "Before", + F: "Before", + G: "Before", + H: "Before", + I: "Before", + J: "Before", + K: "Before", + L: "Before", + M: "Before", + N: "Before", + O: "Before", + }); +const areaImages = { + A: { Before: A_Before, After: A_After }, + B: { Before: B_Before, After: B_After }, + C: { Before: C_Before, After: C_After }, + D: { Before: D_Before, After: D_After }, + E: { Before: E_Before, After: E_After }, + F: { Before: F_Before, After: F_After }, + G: { Before: G_Before, After: G_After }, + H: { Before: H_Before, After: H_After }, + I: { Before: I_Before, After: I_After }, + J: { Before: J_Before, After: J_After }, + K: { Before: K_Before, After: K_After }, + L: { Before: L_Before, After: L_After }, + M: { Before: M_Before, After: M_After }, + N: { Before: N_Before, After: N_After }, + O: { Before: O_Before, After: O_After }, +}; +const handleFloorToggle = (floor) => { + setActiveFloor(floor); + setSelectedArea(null); + setSelectedSeatData(null); + setSeatStates({ + A: "Before", + B: "Before", + C: "Before", + D: "Before", + E: "Before", + F: "Before", + G: "Before", + H: "Before", + I: "Before", + J: "Before", + K: "Before", + L: "Before", + M: "Before", + N: "Before", + O: "Before", + }); +}; + +const toggleAreaState = async (area) => { + setSeatStates((prevStates) => { + const newStates = {}; + Object.keys(prevStates).forEach((key) => { + newStates[key] = key === area ? "After" : "Before"; + }); + return newStates; + }); + setSelectedArea(area); + + // 좌석 상세 조회 API + try { + const response = await axios.get(`${baseURL}/admin/views/${placeId}/section?sectionType=${area}`, { + headers: { Authorization: `Bearer ${token_admin}` } + }); + const seatData = response.data?.result; + setSelectedSeatData(seatData); + } catch (error) { + console.error("섹션 정보 조회 실패:", error); + alert("해당 섹션을 조회할 수 없습니다."); + } +}; + + + + +return ( + + 시야 관리 + + + + + + + + navigate(`/adminpage/vision`)}> + < + +   {theaterInfo?.placeName} + + + + +
+ +
STAGE
+

1층

+ + {["A", "B", "C", "D", "E", "F", "G", "H", "I"].map((area) => ( + {area} + ))} + +

2층

+ + {["J", "K", "L", "M", "N", "O"].map((area) => ( + {area} + ))} + +
+
+ + + + + + + + + + {activeFloor === 1 && + ["A", "B", "C", "D", "E", "F", "G", "H", "I"].map((area) => ( + + ))} + + {activeFloor === 2 && + ["J", "K", "L", "M", "N", "O"].map((area) => ( + + ))} + + +
+ + + {selectedSeatData && ( + {selectedSeatData?.floor}
{selectedSeatData?.seatRange}
+ )} + + 좌석 시야 + + {selectedSeatData && ( + <> + 특징 + {selectedSeatData?.viewDetail} + + )} +
+
+ +
+
+); +} + + +/* ---------------- styled components ---------------- */ + + +const Container = styled.div` + position: relative; + width: 1150px; + height: 916px; + background-color: ${COLOR_WHITE}; + padding-left: 71px; + padding-right: 80px; + box-sizing: border-box; + + display: flex; + flex-direction: column; +`; + +const Tilte = styled.div` + margin-top: 4px; + font-family: "Pretendard"; + font-size: 24px; + font-weight: 500; + color: ${COLOR_MUIT_RED}; +`; + +const SearchSection = styled.div` + margin-top: 15px; + display: flex; + justify-content: space-between; + align-items: center; +`; + +const Subtitle = styled.div` + margin-top: 30px; + font-family: "Pretendard"; + font-size: 24px; + font-weight: 500; + color: ${COLOR_GRAY_MAINTEXT}; +`; + +const BackButton = styled.button` + background: transparent; + border: none; + cursor: pointer; + font-family: "Pretendard"; + font-size: 24px; + font-weight: 500; + color: ${COLOR_GRAY_MAINTEXT}; +`; + +const Button = styled.div` + margin-top: -16px; + display: flex; + justify-content: flex-end; + align-items: center; +`; + +const EditButton = styled(Link)` + text-decoration: none; + text-align: center; + font-family: "Pretendard"; + font-size: 14px; + font-weight: 500; + color: ${COLOR_MUIT_RED}; + cursor: pointer; + box-sizing: border-box; + border: 1px solid ${COLOR_MUIT_RED}; + border-radius: 3px; + background-color: ${COLOR_WHITE}; + padding: 5px 14px 5px 14px; + + &:hover { + background-color: ${COLOR_MUIT_RED}; + color: ${COLOR_WHITE}; + } + `; + +const DetailArea = styled.div` + display: flex; + gap: 40px; + margin-left: -25px; + //align-items: flex-start; +`; + +const SeatArea = styled.div` + width: 580px; + margin-top: 50px; + + .Stage{ + justify-self: center; + margin-left: 12px; + + width: 264px; + height: 20px; + border-radius: 3.946px; + border: 0.789px solid ${COLOR_GRAY_SUB}; + + text-align: center; + color: #8F8E94; + font-family: Pretendard; + font-size: 12.628px; + font-style: normal; + font-weight: 500; + } + .FloorTag{ + width: 26px; + height: 17px; + border-radius: 1.579px; + background: ${COLOR_MUIT_RED}; + + text-align: center; + color: #FFF; + font-family: Pretendard; + font-size: 12px; + font-style: normal; + font-weight: 500; + } + .left-seat-img{ + justify-self: end; + } + .center-seat-img{ + justify-self: center; + } + .right-seat-img{ + justify-self: start; + } +`; + +const Floor = styled.div` + transform: scale(0.78); + transform-origin: top left; + padding-left: 12px; + + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 4px; + + img { + width: auto; + height: auto; + object-fit: contain; + } +`; + +const SeatInfo = styled.div` + width: 400px; + + h3{margin:0px;} + p{margin: 0px;} + + .NowShowing{ + margin-top:25px; + display: flex; + align-items: center; + } + .ShowTitle{ + font-size: 16px; + font-weight: 700; + color: ${COLOR_GRAY_MAINTEXT}; + } + .hr-line{ + border : 0px; + border-top: 1px solid #E6E6E6; + margin-bottom: 24px; + } + .title-B{ + font-size: 24px; + font-weight: 700; + } + .body-M-400{ + font-size: 16px; + font-weight: 500; + color: ${COLOR_GRAY_SUB}; + } + .body-M-500{ + font-size: 16px; + font-weight: 500; + color: ${COLOR_GRAY_MAINTEXT}; + } +`; + +const AreaBtn = styled.div` + display: flex; + gap: 8px; + margin: 20px 0; + + .FloorBtn { + font-size: 14px; + color: ${COLOR_GRAY_SUB}; + text-align: center; + font-family: "Pretendard Variable"; + font-size: 16px; + font-style: normal; + font-weight: 500; + background: none; + border: none; + + cursor: pointer; + + &.active { + color: ${COLOR_MUIT_RED}; + border-bottom: solid 2px; + border-radius: 1px; + border-color: ${COLOR_MUIT_RED}; + } + } +`; + +const AreaSelector = styled.div` + width: 100%; + display: flex; + gap: 8px; + flex-wrap: wrap; + margin: 16px 0; + + .AreaBtn { + width: 55px; + height: 32px; + padding: 3px 15px; + border-radius: 3px; + background: #fff; + border: 1px solid #E6E6E6; + + cursor: pointer; + + color: ${COLOR_GRAY_SUB}; + text-align: center; + /* Body-tiny-md */ + font-family: "Pretendard Variable"; + font-size: 14px; + font-style: normal; + font-weight: 500; + + &.active { + background: #FFF; + color: ${COLOR_MUIT_RED}; + border-color: ${COLOR_MUIT_RED}; + } + } +`; + +const AreaInfo = styled.div` + font-family: "Pretendard"; + font-size: 16px; + font-weight: 500; + color: ${COLOR_GRAY_MAINTEXT}; +`; + +const SeatView = styled.div` + width: 100%; + display: flex + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; +`; + +const ViewImg = styled.div` + width: 388px; + height: 280px; + margin-top: 10px; +`; + +const ViewChar = styled.div` + font-family: "Pretendard"; + font-size: 16px; + font-weight: 700; + color: ${COLOR_GRAY_MAINTEXT}; +`; + +const ViewText = styled.div` + margin-top: 8px; + font-family: "Pretendard"; + font-size: 14px; + font-weight: 500; + color: ${COLOR_GRAY_SUB}; +`; \ No newline at end of file diff --git a/src/pages/adminpage/vision/AdminVisionUpdate.jsx b/src/pages/adminpage/vision/AdminVisionUpdate.jsx new file mode 100644 index 0000000..b166a76 --- /dev/null +++ b/src/pages/adminpage/vision/AdminVisionUpdate.jsx @@ -0,0 +1,332 @@ + +import React, { useState, useEffect } from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; +import styled from 'styled-components'; +import axios from 'axios'; + +import PlusButton from "../../../assets/icons/AddButton.svg"; + +const COLOR_WHITE = "#FFFFFF"; +const COLOR_MUIT_RED = "#A00000"; +const COLOR_GRAY_MAINTEXT = "#000000"; +const COLOR_GRAY_SUB = "#919191"; + +const baseURL = import.meta.env.VITE_APP_SERVER_URL; +const token_admin = localStorage.getItem("adminToken"); + +export default function AdminVisionUpdate() { + + const { placeId } = useParams(); + const [sectionData, setSectionData] = useState([]); + const [theaterName, setTheaterName] = useState(""); + useEffect(() => { + if (placeId) { + fetchSections(placeId); + } + }, [placeId]); + const fetchSections = async (placeId) => { + try { + const response = await axios.get(`${baseURL}/admin/views/${placeId}/edit`, { + headers: { Authorization: `Bearer ${token_admin}` }, + } + ); + const sections = response.data.result.theatreSections || []; + const name = response.data.result.theatreName; + setSectionData(sections); + setTheaterName(name); + } catch (err) { + console.error("섹션 정보 조회 실패:", err); + alert("섹션 정보를 불러오는 중 오류가 발생했습니다."); + } + }; + console.log(theaterName + 1); + + return ( + + 시야 관리 + + + 시야 등록 + 등록하기 +
+
+ + + 장소 + {theaterName} +
+
+ + + + 공연장 전체 사진 + 검색 페이지 검색 결과로 사용됩니다. + + 수정 + + + + + + + + 칸 + 층 + 좌석 + 특징 + 사진 + + + + {sectionData.map((section, idx) => ( + + {section.sectionType} + {section.floor} + {section.seatRange} + {section.viewDetail} + + {section.isViewPic ? ( + 수정 + ) : ( + 미등록 + )} + + + ))} + {/* 마지막 행 */} + + + + Plus + + + + + + + + +
+ ); +} + + +/* ---------------- styled components ---------------- */ + + +const Container = styled.div` + position: relative; + width: 1150px; + height: 916px; + background-color: ${COLOR_WHITE}; + padding-left: 71px; + padding-right: 131px; + box-sizing: border-box; + display: flex; + flex-direction: column; +`; + +const Tilte = styled.div` + font-family: "Pretendard"; + font-size: 24px; + font-weight: 500; + color: ${COLOR_MUIT_RED}; + margin-top: 4px; +`; + +const SubTitleLine = styled.div` + margin-top: 64px; + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + position: relative; + + hr { + position: absolute; + top: 48px; + left: 2px; + border: none; + border-top: 1px solid #E6E6E6; + width: 99%; + } +`; + +const SubTitle = styled.div` + font-family: "Pretendard"; + font-size: 24px; + font-weight: 700; + color: ${COLOR_GRAY_MAINTEXT}; +`; + +const ApplyButton = styled.button` + width: 72px; + height: 28px; + font-family: "Pretendard"; + font-size: 14px; + font-weight: 500; + color: ${COLOR_WHITE}; + border: 1px solid ${COLOR_MUIT_RED}; + border-radius: 2px; + background-color: ${COLOR_MUIT_RED}; + cursor: pointer; +`; + +const Place = styled.div` + margin-top: 50px; + display: flex; + justify-content: flex-start; + align-items: center; + gap: 24px; + position: relative; + + hr { + position: absolute; + top: 24px; + left: 100px; + border: none; + border-top: 1px solid #E6E6E6; + width: 607px; + } +`; + +const PlaceTitle = styled.div` + width: 80px; + font-family: "Pretendard"; + font-size: 16px; + font-weight: 700; + color: ${COLOR_GRAY_MAINTEXT}; + +`; + +const PlaceText = styled.div` + font-family: "Pretendard"; + font-size: 16px; + font-weight: 500; + color: ${COLOR_GRAY_MAINTEXT}; +`; + +////// Table /////// + +const TableContainer = styled.div` + width: 100%; + margin-top: 20px; + font-family: "Pretendard"; +`; + +const TabHeader = styled.div` + margin-top: 28px; + display: flex; + font-size: 16px; + font-weight: 500; + height: 45px; +`; + +const HeaderCol1 = styled.div` + color: #8F8E94; + box-sizing: border-box; + border-top: 1px solid #8F8E94; + border-bottom: 1px solid #8F8E94; + padding-top: 11px; + padding-left: 16px; + width: 140px; +`; + +const HeaderCol2 = styled.div` + color: #424242; + box-sizing: border-box; + border: 1px solid #8F8E94; + padding-top: 11px; + padding-left: 20px; + width: 744px; +`; + +const HeaderCol3 = styled.div` + box-sizing: border-box; + border-top: 1px solid #8F8E94; + border-bottom: 1px solid #8F8E94; + padding-top: 11px; + padding-left: 20px; + width: 69px; +`; + +const UpdateButton = styled.button` + background-color: #D9D9D9; + border: 1px solid #D9D9D9; + cursor: pointer; + width: 40px; + height: 20px; + font-size: 10px; + font-weight: 500; + color: #555555; + + &:hover { + border-color: #A00000; + color: #A00000; +} +`; + +const ScrollWrapper = styled.div` + margin-top: 24px; + max-height: 400px; + overflow-y: auto; // 스크롤 + width: 958px; + padding-right: 10px; + + &::-webkit-scrollbar { + width: 8px; + } + &::-webkit-scrollbar-track { + background-color: ${COLOR_WHITE}; + border-radius: 6px; + } + &::-webkit-scrollbar-thumb { + background-color: #d9d9d9; + border-radius: 6px; + } + &::-webkit-scrollbar-thumb:hover { + background-color: #a0a0a0; + } +`; + +const StyledTable = styled.table` + width: 100%; + border-collapse: collapse; + + thead tr { + background-color: ${COLOR_WHITE}; + border-left: 1px solid #FFFFFF; + border-right: 1px solid #FFFFFF; + } + th, + td { + border: 1px solid #8F8E94; + padding: 8px; + text-align: center; + font-size: 16px; + color: #424242; + } +`; + +const UploadButton = styled.button` + background-color: ${COLOR_MUIT_RED}; + border: 1px solid ${COLOR_MUIT_RED}; + cursor: pointer; + width: 40px; + height: 20px; + font-size: 10px; + font-weight: 500; + color: ${COLOR_WHITE}; + + &:hover { + border-color: ${COLOR_WHITE}; + color: ${COLOR_MUIT_RED}; +} +`; + +const AddButton = styled.button` + border: none; + background-color: transparent; + cursor: pointer; +`; \ No newline at end of file diff --git a/src/pages/board/post/AnonymousPost.jsx b/src/pages/board/post/AnonymousPost.jsx index 366cdd2..45e0bdb 100644 --- a/src/pages/board/post/AnonymousPost.jsx +++ b/src/pages/board/post/AnonymousPost.jsx @@ -31,17 +31,21 @@ function AnonymousPost() { // 게시글 데이터 // const token = import.meta.env.VITE_APP_ACCESS_TOKEN; const token = localStorage.getItem("accessToken"); - console.log(token); + // console.log(token); const url = `/posts/${postId}`; + const { data, error, loading } = useFetch(url, { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); console.log('데이터', data); + const [isButtonLiked, setIsButtonLiked] = useState(data?.result?.isLiked); const [likeCount, setLikeCount] = useState(data?.result?.likeCount); + const [isWrited, setIsWrited] = useState(false); + const [isDeleted, setIsDeleted] = useState(false); useEffect(() => { if (data?.result?.isLiked !== undefined) { @@ -58,7 +62,16 @@ function AnonymousPost() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); + + useEffect(() => { + if (isWrited||isDeleted) { + setTimeout(() => { + window.location.reload(); + }, 50); + } + }, [isWrited, isDeleted]); + console.log("코멘트 데이터:", comment); console.log("에러:", commentError); console.log("로딩:", commentLoading); @@ -156,10 +169,10 @@ function AnonymousPost() { - + {comment?.result?.comments?.map((data) => ( - + ))} diff --git a/src/pages/board/post/FoundPost.jsx b/src/pages/board/post/FoundPost.jsx index 9c56bce..72bc811 100644 --- a/src/pages/board/post/FoundPost.jsx +++ b/src/pages/board/post/FoundPost.jsx @@ -8,7 +8,8 @@ import Info from "../../../components/detail/Info"; import { useNavigate, useParams } from "react-router-dom"; import useFetch from "../../../hooks/useFetch"; import PostMenu from "../../../components/post/PostMenu"; - +import { useState } from "react"; +import { useEffect } from "react"; // const token = import.meta.env.VITE_APP_ACCESS_TOKEN; const token = localStorage.getItem("accessToken"); console.log(token); @@ -25,8 +26,11 @@ function FoundPost() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); console.log('데이터', data); + + const [isWrited, setIsWrited] = useState(false); + const [isDeleted, setIsDeleted] = useState(false); // 🔹 댓글 데이터 (commentTrigger 변경 시 재요청) const { data: comment, error: commentError, loading: commentLoading } = useFetch( @@ -35,7 +39,15 @@ function FoundPost() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); + + useEffect(() => { + if (isWrited||isDeleted) { + setTimeout(() => { + window.location.reload(); + }, 50); + } + }, [isWrited, isDeleted]); console.log("코멘트 데이터:", comment); console.log("에러:", commentError); console.log("로딩:", commentLoading); @@ -96,10 +108,10 @@ function FoundPost() { {/*댓글 작성부분 - 한 컴포넌트로 묶기 */} 댓글 {commentCount}개 - + {comment?.result?.comments?.map((data) => ( - + ))} diff --git a/src/pages/board/post/ItemPost.jsx b/src/pages/board/post/ItemPost.jsx index cbdf41f..5e98e11 100644 --- a/src/pages/board/post/ItemPost.jsx +++ b/src/pages/board/post/ItemPost.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import styled from "styled-components"; import itemImg from "../../../assets/images/lost-item-1.png"; import CommentInputArea from "../../../components/post/CommentInputArea"; @@ -10,7 +10,6 @@ import useFetch from "../../../hooks/useFetch"; import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { BsThreeDotsVertical } from "react-icons/bs"; - // const token = import.meta.env.VITE_APP_ACCESS_TOKEN; const token = localStorage.getItem("accessToken"); console.log(token); @@ -36,9 +35,12 @@ function ItemPost() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); console.log('데이터', data); + const [isWrited, setIsWrited] = useState(false); + const [isDeleted, setIsDeleted] = useState(false); + // 🔹 댓글 데이터 (commentTrigger 변경 시 재요청) const { data: comment, error: commentError, loading: commentLoading } = useFetch( `/comments/${postId}?page=0&size=20`, @@ -46,7 +48,17 @@ function ItemPost() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); + + + useEffect(() => { + if (isWrited||isDeleted) { + setTimeout(() => { + window.location.reload(); + }, 50); + } + }, [isWrited, isDeleted]); + console.log("코멘트 데이터:", comment); console.log("에러:", commentError); console.log("로딩:", commentLoading); @@ -108,10 +120,10 @@ function ItemPost() { {/*댓글 작성부분 - 한 컴포넌트로 묶기 */} 댓글 {commentCount}개 - + {comment?.result?.comments?.map((data) => ( - + ))} diff --git a/src/pages/board/post/ReviewPost.jsx b/src/pages/board/post/ReviewPost.jsx index bfc3aa6..72738ef 100644 --- a/src/pages/board/post/ReviewPost.jsx +++ b/src/pages/board/post/ReviewPost.jsx @@ -9,6 +9,7 @@ import { RatingStars } from "../../../components/detail/RatingStars"; import { useNavigate, useParams } from "react-router-dom"; import useFetch from "../../../hooks/useFetch"; import PostMenu from "../../../components/post/PostMenu"; +import { useState, useEffect } from "react"; // const token = import.meta.env.VITE_APP_ACCESS_TOKEN; const token = localStorage.getItem("accessToken"); console.log(token); @@ -22,9 +23,12 @@ function ReviewPost() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); console.log('데이터', data); + const [isWrited, setIsWrited] = useState(false); + const [isDeleted, setIsDeleted] = useState(false); + // 🔹 댓글 데이터 (commentTrigger 변경 시 재요청) const { data: comment, error: commentError, loading: commentLoading } = useFetch( `/comments/${postId}?page=0&size=20`, @@ -32,7 +36,16 @@ function ReviewPost() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); + + useEffect(() => { + if (isWrited||isDeleted) { + setTimeout(() => { + window.location.reload(); + }, 50); + } + }, [isWrited, isDeleted]); + console.log("코멘트 데이터:", comment); console.log("에러:", commentError); console.log("로딩:", commentLoading); @@ -97,10 +110,10 @@ function ReviewPost() { {/*댓글 작성부분 - 한 컴포넌트로 묶기 */} 댓글 {commentCount}개 - + {comment?.result?.comments?.map((data) => ( - + ))} diff --git a/src/pages/board/post/SeatsPost.jsx b/src/pages/board/post/SeatsPost.jsx index 47e2913..061566c 100644 --- a/src/pages/board/post/SeatsPost.jsx +++ b/src/pages/board/post/SeatsPost.jsx @@ -10,6 +10,7 @@ import { useParams } from "react-router-dom"; import useFetch from "../../../hooks/useFetch"; import PostMenu from "../../../components/post/PostMenu"; // const token = import.meta.env.VITE_APP_ACCESS_TOKEN; +import { useState, useEffect } from "react"; const token = localStorage.getItem("accessToken"); console.log(token); function ReviewPost() { @@ -21,8 +22,11 @@ function ReviewPost() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); console.log('데이터', data); + + const [isWrited, setIsWrited] = useState(false); + const [isDeleted, setIsDeleted] = useState(false); // 🔹 댓글 데이터 (commentTrigger 변경 시 재요청) const { data: comment, error: commentError, loading: commentLoading } = useFetch( @@ -31,7 +35,17 @@ function ReviewPost() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); + + useEffect(() => { + if (isWrited||isDeleted) { + setTimeout(() => { + window.location.reload(); + }, 50); + } + }, [isWrited, isDeleted]); + + console.log("코멘트 데이터:", comment); console.log("에러:", commentError); console.log("로딩:", commentLoading); @@ -87,10 +101,10 @@ function ReviewPost() { {/*댓글 작성부분 - 한 컴포넌트로 묶기 */} 댓글 {commentCount}개 - + {comment?.result?.comments?.map((data) => ( - + ))} diff --git a/src/pages/detail/MainContent.jsx b/src/pages/detail/MainContent.jsx index ba0c037..4e7fcc2 100644 --- a/src/pages/detail/MainContent.jsx +++ b/src/pages/detail/MainContent.jsx @@ -72,10 +72,9 @@ function MainContent({data,loading, error}) { musicalId={musical.id} /> -
반별 test용으로 별점을 4.6 고정으로 해둠
- + - + {score} diff --git a/src/pages/detail/subpages/Casts.jsx b/src/pages/detail/subpages/Casts.jsx index 9d3192f..cca85e8 100644 --- a/src/pages/detail/subpages/Casts.jsx +++ b/src/pages/detail/subpages/Casts.jsx @@ -19,33 +19,33 @@ function CastsDetail() { console.log('캐스팅 데이터', data?.result); return ( - <> - {data?.result?.map((role) => ( - -

{role?.roleName}

- - - {role?.actorList?.map((actor) => ( - - - {`${actor?.realName} - { - - - - } - -
{actor?.realName}
-
- ))} -
-
- ))} - - - + {data?.result?.length === 0 ? ( +

캐스팅 정보가 없습니다.

+ ) : ( + data?.result?.map((role) => ( + +

{role?.roleName}

+ + + {role?.actorList?.map((actor) => ( + + + {`${actor?.realName} + + + + +
{actor?.realName}
+
+ ))} +
+
+ )) + )} + ); + } export default CastsDetail; @@ -99,4 +99,5 @@ const ActorsWrapper = styled.div` display:flex; flex-direction: row; gap: 40px; +max-width: 800px; ` \ No newline at end of file diff --git a/src/pages/detail/subpages/Performance.jsx b/src/pages/detail/subpages/Performance.jsx index ad9c730..daf624b 100644 --- a/src/pages/detail/subpages/Performance.jsx +++ b/src/pages/detail/subpages/Performance.jsx @@ -8,10 +8,19 @@ function Performance({ data }) { return ( <> - + {data?.result?.desImgUrl[0] ? ( + + ) : ( +
공연정보가 없습니다.
+ ) + } ); } export default Performance; + +const Img = styled.img` + max-width: 800px; +` \ No newline at end of file diff --git a/src/pages/mypage/MyPage.jsx b/src/pages/mypage/MyPage.jsx index ec9ffb7..8b2bc7b 100644 --- a/src/pages/mypage/MyPage.jsx +++ b/src/pages/mypage/MyPage.jsx @@ -81,7 +81,15 @@ function MyPage() { />
- 로그아웃 + { + localStorage.removeItem("userId"); + localStorage.removeItem("accessToken"); // 토큰도 있다면 같이 삭제 + navigate("/login"); // 로그인 페이지로 이동 + }} + > + 로그아웃 + navigate('/mypage/account-deletion')}>회원탈퇴 diff --git a/src/pages/mypage/my/LikedMusical.jsx b/src/pages/mypage/my/LikedMusical.jsx index f51146f..38c850b 100644 --- a/src/pages/mypage/my/LikedMusical.jsx +++ b/src/pages/mypage/my/LikedMusical.jsx @@ -16,7 +16,7 @@ function LikedMusical() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - },); + },[token]); console.log(data); diff --git a/src/pages/mypage/my/MyPosts.jsx b/src/pages/mypage/my/MyPosts.jsx index 97f8a0f..97a1d5c 100644 --- a/src/pages/mypage/my/MyPosts.jsx +++ b/src/pages/mypage/my/MyPosts.jsx @@ -27,7 +27,7 @@ function MyPosts() { headers: { Authorization: token ? `Bearer ${token}` : "", }, - },); + },[token]); console.log(data); diff --git a/src/pages/mypage/my/ticket/CancelTicket.jsx b/src/pages/mypage/my/ticket/CancelTicket.jsx index 8ad0442..867fab9 100644 --- a/src/pages/mypage/my/ticket/CancelTicket.jsx +++ b/src/pages/mypage/my/ticket/CancelTicket.jsx @@ -46,7 +46,7 @@ function CancelTicket() { RESERVED: "예매 완료", EXPIRED: "사용 완료", CANCEL_AWAIT: "취소 대기중", - CANCELED: "취소 완료", + CANCELED: "예매 취소", } @@ -69,7 +69,7 @@ function CancelTicket() { // API 응답 확인 if (response.ok) { - // 취소 완료 후 'complete' 페이지로 이동 + // 예매 취소후 'complete' 페이지로 이동 setLastCanceledTicket({ amateurShowName: amateurShowName, quantity: quantity, diff --git a/src/pages/mypage/my/ticket/TicketDetailPage.jsx b/src/pages/mypage/my/ticket/TicketDetailPage.jsx index 968917f..e876e22 100644 --- a/src/pages/mypage/my/ticket/TicketDetailPage.jsx +++ b/src/pages/mypage/my/ticket/TicketDetailPage.jsx @@ -59,7 +59,7 @@ function TicketDetailPage() { RESERVED: "예매 완료", EXPIRED: "사용 완료", CANCEL_AWAIT: "취소 대기중", - CANCELED: "취소 완료", + CANCELED: "예매 취소", } diff --git a/src/pages/mypage/my/ticket/TicketList.jsx b/src/pages/mypage/my/ticket/TicketList.jsx index 6b23415..e0b8243 100644 --- a/src/pages/mypage/my/ticket/TicketList.jsx +++ b/src/pages/mypage/my/ticket/TicketList.jsx @@ -19,7 +19,7 @@ const TicketList = ({ status }) => { headers: { Authorization: token ? `Bearer ${token}` : "", }, - },); + }, [token]); console.log(data); return ( diff --git a/src/pages/mypage/support/ContactPost.jsx b/src/pages/mypage/support/ContactPost.jsx index 5e778f5..f441e12 100644 --- a/src/pages/mypage/support/ContactPost.jsx +++ b/src/pages/mypage/support/ContactPost.jsx @@ -74,8 +74,8 @@ function ContactPost() { const comment = { id: 1, nickname: '관리자', - content: '안녕하세요, 고객님. [알라딘] 티켓 결제 관련하여 문의 주셔서 감사합니다. 현재 고객님의 결제 내역을 확인하고 있습니다. 결제가 정상적으로 완료되지 않았거나 오류가 발생했을 경우, 추가로 필요한 조치를 안내드리겠습니다. 결제 상태를 확인하는 데 약간의 시간이 소요될 수 있으니 양해 부탁드립니다. 만약 결제 확인 이메일이나 문자를 아직 받지 못하셨다면, 스팸메일함을 한 번 확인해 주시고, 결제 당시 사용하신 결제 수단의 상세 내역(거래일시, 승인번호 등)을 알려주시면 더욱 빠르게 처리할 수 있습니다. 추가적으로 궁금한 사항이 있으시다면 언제든 말씀해 주세요. 빠르게 확인 후 다시 연락드리겠습니다. 감사합니다.', - createdAt: '2025-01-15', + content: '안녕하세요, 고객님. 문의 주셔서 감사합니다. \n\n현재 확인 중에 있으니 잠시만 기다려 주시길 바랍니다. \n빠른 시일 내에 답변 드릴 수 있도록 최선을 다하겠습니다. \n추가로 궁금하신 사항이 있으시면 언제든지 말씀해주세요. \n\n감사합니다.', + createdAt: d?.createdAt?.split('T')[0], } const listSize = '?' // comment?.result?.listSize; @@ -102,15 +102,14 @@ function ContactPost() { -
{/*댓글 작성부분 - 한 컴포넌트로 묶기 */} - 답변 {listSize}개 +
- + diff --git a/src/pages/mypage/support/SupportContact.jsx b/src/pages/mypage/support/SupportContact.jsx index f3bf9cb..0bd4f11 100644 --- a/src/pages/mypage/support/SupportContact.jsx +++ b/src/pages/mypage/support/SupportContact.jsx @@ -26,7 +26,7 @@ const SupportContact = () => { headers: { Authorization: token ? `Bearer ${token}` : "", }, - }); + }, [token]); console.log('데이터', data); const tableHeaders = ["제목", "날짜", "상태"]; diff --git a/src/pages/small-theater/SmallDetail.jsx b/src/pages/small-theater/SmallDetail.jsx index 283a129..214ba4c 100644 --- a/src/pages/small-theater/SmallDetail.jsx +++ b/src/pages/small-theater/SmallDetail.jsx @@ -34,12 +34,12 @@ function SmallDetail() { // API에서 받아온 데이터를 처리합니다. const musical = data.result; const name = musical.name; - const content = musical.summaries.content || ''; // content가 없으면 빈 문자열로 처리 + const content = musical.summaryContent || ''; // content가 없으면 빈 문자열로 처리 const [quote, ...descriptionParts] = content.split("\n"); const description = descriptionParts.join("\n").replace(/\n/g, "
"); - const imageUrls = musical.notice.imgUrls; - const poster = musical.posterImgUrl + const imageUrls = musical.noticeImages; + const poster = musical.posterImage; const details = [ { label: "장소", value: musical.place}, { label: "공연 기간", value: musical.schedule }, @@ -54,13 +54,27 @@ function SmallDetail() {
))} }, // 가격 상세 구현 필요 - { label: "티켓 수", value: "200매 (표가 없을 시 구매 불가)" }, + { label: "티켓 수", value: musical.totalTicket }, ]; return ( <> {/*빨간배너 */} + {poster ? ( + + ) : ( + + )} + +
{name}
{musical.hashtag @@ -73,6 +87,7 @@ function SmallDetail() { +
{/* 본문 */} @@ -102,7 +117,7 @@ function SmallDetail() { 공연시간 정보 {musical.timeInfo} 공지사항 - {musical.notice.content} + {musical.noticeContent} {imageUrls && imageUrls.length > 0 && ( @@ -126,15 +141,13 @@ function SmallDetail() { export default SmallDetail; /*빨간배너 */ const BannerContainer = styled.div` - background: linear-gradient( - var(--Muit-Red-main, #A00000), - rgba(160, 0, 0, 0.5) - ), - url(${(props) => props.poster}) no-repeat center center / cover; - width: 1250px; - height:822px; - padding: 101px 95px; position: relative; + width: 1440px; + height: 1024px; + overflow: hidden; + &:hover img { + transform: scale(1.1); + } `; const Header = styled.div` @@ -173,13 +186,22 @@ const Quote = styled.blockquote` `; const Description = styled.div` - color: #FFF; - width: 870px; + width: 740px; + height: 380px; font-family: Pretendard; font-size: 16px; - font-style: normal; - line-height: 30px; /* 156.25% */ -` + line-height: 24px; + overflow-y: auto; + position: relative; + &::-webkit-scrollbar { + display: none; + } + scrollbar-width: none; + -ms-overflow-style: none; + -webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 90%, rgba(0, 0, 0, 0) 100%); + mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 90%, rgba(0, 0, 0, 0) 100%); +`; + const Tag = styled.li` display: flex; width: 120px; @@ -358,3 +380,31 @@ const DetailImage = styled.div` height: 888px; flex-shrink: 0; `; +const BannerImage = styled.img` + width: 100%; + height: 100%; + object-fit: cover; + display: block; + position: absolute; + top: 108; + left: 0; + transition: transform 1s ease-in-out; +`; + +const Overlay = styled.div` + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(var(--Muit-Red-main, #A00000), rgba(160, 0, 0, 0.5)); + z-index: 1; + pointer-events: none; +`; +const Content = styled.div` + position: relative; + z-index: 2; + padding: 101px 95px; + padding-top: 190px; + color: #FFF; +`; \ No newline at end of file