diff --git a/src/components/Detail/BottomSlideDetail/BottomSlideDetail.tsx b/src/components/Detail/BottomSlideDetail/BottomSlideDetail.tsx index ed2468a2..877c6a7f 100644 --- a/src/components/Detail/BottomSlideDetail/BottomSlideDetail.tsx +++ b/src/components/Detail/BottomSlideDetail/BottomSlideDetail.tsx @@ -1,47 +1,46 @@ -import { Slide } from "@chakra-ui/react"; -import { useSetRecoilState } from "recoil"; +import {Slide} from '@chakra-ui/react'; +import {useRecoilValue, useSetRecoilState} from 'recoil'; -import styles from "./BottomSlideDetail.module.scss"; +import styles from './BottomSlideDetail.module.scss'; -import { isModalOpenState, modalContentState } from "@/recoil/vote/alertModal"; +import {isModalOpenState, modalContentState} from '@/recoil/vote/alertModal'; -import { BottomSlideDetailProps } from "@/types/detail"; +import {BottomSlideDetailProps} from '@/types/detail'; +import {isReviewStartState} from '@/recoil/detail/detail'; -function BottomSlideDetail({ - isOpen, - onClose, - children, - isReviewModal, - setBottomSlideContent, -}: BottomSlideDetailProps) { +function BottomSlideDetail({isOpen, onClose, children, isReviewModal, setBottomSlideContent}: BottomSlideDetailProps) { const setIsModalOpen = useSetRecoilState(isModalOpenState); const setModalContent = useSetRecoilState(modalContentState); + const isReviewStart = useRecoilValue(isReviewStartState); const checkBeforeExit = { - title: "잠깐!", - subText: "지금 나가면 작성내용이 전부 삭제돼요", - cancelText: "마저 작성할게요", - actionButton: "나갈래요", + title: '잠깐!', + subText: '지금 나가면 작성내용이 전부 삭제돼요', + cancelText: '마저 작성할게요', + actionButton: '나갈래요', isSmallSize: true, onClickAction: () => { setBottomSlideContent(null); setIsModalOpen(false); onClose(); - document.body.style.removeProperty("overflow"); + document.body.style.removeProperty('overflow'); }, }; const showCheckBeforeExitModal = () => { - setIsModalOpen(true); - setModalContent({ ...checkBeforeExit }); + if (isReviewStart) { + setIsModalOpen(true); + setModalContent({...checkBeforeExit}); + } else { + onClose(); + } }; - return ( <>
{ if (isReviewModal) { @@ -50,10 +49,10 @@ function BottomSlideDetail({ setBottomSlideContent(null); onClose(); } - document.body.style.removeProperty("overflow"); + document.body.style.removeProperty('overflow'); }} >
- +
{children}
diff --git a/src/components/Detail/Contents/Information/BasicInformation/MapModal/MapModal.tsx b/src/components/Detail/Contents/Information/BasicInformation/MapModal/MapModal.tsx index 2a505c6b..cda9c453 100644 --- a/src/components/Detail/Contents/Information/BasicInformation/MapModal/MapModal.tsx +++ b/src/components/Detail/Contents/Information/BasicInformation/MapModal/MapModal.tsx @@ -8,6 +8,7 @@ import BigHomeMarker from '@/assets/homeIcons/map/house_big.svg?react'; import BigFlagMarker from '@/assets/homeIcons/map/flag_big.svg?react'; import BigRestaurantMarker from '@/assets/homeIcons/map/restaurant_big.svg?react'; import TitleWishBtn from '@/components/Detail/Main/Title/TitleWishBtn/TitleWishBtn'; +import {translateAreaCode, translateCategoryToStr} from '@/utils/translateSearchData'; interface MapModalProps { isOpen: boolean; @@ -22,6 +23,9 @@ interface MapModalProps { } function MapModal({isOpen, onClose, lat, lng, title, thumbnail, id, contentTypeId, areaCode}: MapModalProps) { + const categoryStr = translateCategoryToStr(contentTypeId); + const areaStr = translateAreaCode(areaCode); + return (

{title}

- {contentTypeId} {areaCode} + {categoryStr}·{areaStr}

- - -
- 할인가 - 예약하러 가기 - -
- + {data.contentTypeId === 32 && ( + + +
+ 할인가 + 예약하러 가기 + +
+ + )} (false); const [isValuedCount, setIsValuedCount] = useState(false); const [isValuedDate, setIsValuedDate] = useState(false); const [isDisabled, setIsDisabled] = useState(false); + const [isReviewStart, setIsReviewStart] = useRecoilState(isReviewStartState); const setIsModalOpen = useSetRecoilState(isModalOpenState); const setModalContent = useSetRecoilState(modalContentState); @@ -34,6 +37,8 @@ function ReviewBottomSlide({placeId, contentTypeId, title, slideOnClose}: Review const [imageUrls, setImageUrls] = useState([]); const [imageFileList, setImageFileList] = useState(); + const toast = CustomToast(); + const checkBeforeExit = { title: '잠깐!', subText: '지금 나가면 작성내용이 전부 삭제돼요', @@ -47,9 +52,20 @@ function ReviewBottomSlide({placeId, contentTypeId, title, slideOnClose}: Review }, }; + useEffect(() => { + if (isValuedCount || isValuedInput || isValuedDate) { + setIsReviewStart(true); + } + return () => setIsReviewStart(false); + }, [isValuedCount, isValuedDate, isValuedInput]); + const showCheckBeforeExitModal = () => { - setIsModalOpen(true); - setModalContent({...checkBeforeExit}); + if (isReviewStart) { + setIsModalOpen(true); + setModalContent({...checkBeforeExit}); + } else { + slideOnClose(); + } }; const postReview = usePostReview(placeId); @@ -74,6 +90,7 @@ function ReviewBottomSlide({placeId, contentTypeId, title, slideOnClose}: Review visitedAt: `${time.getFullYear()}-${('00' + (time.getMonth() + 1).toString()).slice(-2)}-01`, }); slideOnClose(); + toast('리뷰가 작성되었습니다.'); document.body.style.removeProperty('overflow'); }; diff --git a/src/components/Detail/Main/ImageSwiper/Swiper.tsx b/src/components/Detail/Main/ImageSwiper/Swiper.tsx index fb75c38d..a200a41a 100644 --- a/src/components/Detail/Main/ImageSwiper/Swiper.tsx +++ b/src/components/Detail/Main/ImageSwiper/Swiper.tsx @@ -1,5 +1,5 @@ import {useDisclosure} from '@chakra-ui/react'; -import {useState} from 'react'; +import {useEffect, useRef, useState} from 'react'; import {Swiper, SwiperSlide} from 'swiper/react'; // Import Swiper styles import 'swiper/css'; @@ -20,10 +20,16 @@ interface ImageSwiperProps { function ImageSwiper({images}: ImageSwiperProps) { const [imageIndex, setImageIndex] = useState(0); const {isOpen, onOpen, onClose} = useDisclosure(); + const swiperRef = useRef(null); + + useEffect(() => { + swiperRef.current?.swiper.slideTo(imageIndex); + }, [imageIndex]); return ( <> - + <Title + id={id} + areaCode={areaCode} + contentTypeId={contentTypeId} + title={title} + rating={rating} + reviewsCount={reviewsCount} + /> </div> ); } diff --git a/src/components/Detail/Main/Title/Title.tsx b/src/components/Detail/Main/Title/Title.tsx index 1dcb1cbe..9f6258f1 100644 --- a/src/components/Detail/Main/Title/Title.tsx +++ b/src/components/Detail/Main/Title/Title.tsx @@ -6,21 +6,23 @@ import styles from './Title.module.scss'; import CustomToast from '@/components/CustomToast/CustomToast'; import TitleWishBtn from './TitleWishBtn/TitleWishBtn'; -import {translateCategoryToStr} from '@/utils/translateSearchData'; +import {translateAreaCode, translateCategoryToStr} from '@/utils/translateSearchData'; import {useLocation} from 'react-router-dom'; interface TitleProps { id: number; + areaCode: number; contentTypeId: number; title: string; rating: number; reviewsCount: number; } -function Title({id, contentTypeId, title, rating, reviewsCount}: TitleProps) { +function Title({id, areaCode, contentTypeId, title, rating, reviewsCount}: TitleProps) { const showToast = CustomToast(); const categoryStr = translateCategoryToStr(contentTypeId); + const areaStr = translateAreaCode(areaCode); // 링크 복사 const location = useLocation(); @@ -38,7 +40,9 @@ function Title({id, contentTypeId, title, rating, reviewsCount}: TitleProps) { return ( <div className={styles.container}> <h2 className={styles.container__header}>{title}</h2> - <p className={styles.container__category}>{categoryStr}</p> + <p className={styles.container__category}> + {categoryStr}·{areaStr} + </p> <div className={styles.container__alignCenter}> <GoStarFill className={styles.container__alignCenter__star} /> <span className={styles.container__alignCenter__point}>{rating}</span> diff --git a/src/components/Detail/Main/Title/TitleWishBtn/TitleWishBtn.tsx b/src/components/Detail/Main/Title/TitleWishBtn/TitleWishBtn.tsx index b86d2e98..22f50f08 100644 --- a/src/components/Detail/Main/Title/TitleWishBtn/TitleWishBtn.tsx +++ b/src/components/Detail/Main/Title/TitleWishBtn/TitleWishBtn.tsx @@ -9,8 +9,10 @@ import {useDeleteWishes, useGetIsWish, usePostWishes} from '@/hooks/Detail/useWi import {useDebounceBoolean} from '@/hooks/useDebounce'; import CustomToast from '../../../../CustomToast/CustomToast'; -import {useRecoilState} from 'recoil'; +import {useRecoilState, useSetRecoilState} from 'recoil'; import {IsHeartValued} from '@/recoil/detail/detail'; +import {modalContentState} from '@/recoil/vote/alertModal'; +import {useNavigate} from 'react-router-dom'; interface WishBtnProps { placeId: number; @@ -24,12 +26,22 @@ function TitleWishBtn({placeId, contentTypeId, size = '2.4rem', className = ''}: const [isModalOpen, setIsModalOpen] = useState<boolean>(false); const [wishInitial, setWishInitial] = useState<boolean>(false); const [isMount, setIsMount] = useState<boolean>(true); + const setModalContent = useSetRecoilState(modalContentState); const cookies = new Cookies(); const isLogin = cookies.get('isLogin'); - + const navigate = useNavigate(); + + const notLoginContent = { + title: '로그인이 필요한 기능입니다.', + subText: '로그인하고 모든 서비스를 이용해 보세요! ', + cancelText: '닫기', + actionButton: '로그인하기', + isSmallSize: true, + }; const showNotLoginModal = () => { setIsModalOpen(true); + setModalContent({...notLoginContent}); }; const showToast = CustomToast(); @@ -123,7 +135,13 @@ function TitleWishBtn({placeId, contentTypeId, size = '2.4rem', className = ''}: <button onClick={() => setIsModalOpen(false)} className={styles.buttons__cancel}> 닫기 </button> - <button onClick={() => {}} className={styles.buttons__action}> + <button + onClick={() => { + navigate('/auth/login'); + document.body.style.removeProperty('overflow'); + }} + className={styles.buttons__action} + > 로그인하기 </button> </ModalFooter> diff --git a/src/components/WishBtn/WishBtn.tsx b/src/components/WishBtn/WishBtn.tsx index bd24c156..4d33bd50 100644 --- a/src/components/WishBtn/WishBtn.tsx +++ b/src/components/WishBtn/WishBtn.tsx @@ -9,6 +9,9 @@ import {useDeleteWishes, useGetIsWish, usePostWishes} from '@/hooks/Detail/useWi import {useDebounceBoolean} from '@/hooks/useDebounce'; import CustomToast from '../CustomToast/CustomToast'; +import {useNavigate} from 'react-router-dom'; +import {modalContentState} from '@/recoil/vote/alertModal'; +import {useSetRecoilState} from 'recoil'; interface WishBtnProps { placeId: number; @@ -21,12 +24,22 @@ function WishBtn({placeId, contentTypeId, size = '2.4rem', className = ''}: Wish const [isModalOpen, setIsModalOpen] = useState<boolean>(false); const [wishInitial, setWishInitial] = useState<boolean>(false); const [isMount, setIsMount] = useState<boolean>(true); + const setModalContent = useSetRecoilState(modalContentState); const cookies = new Cookies(); const isLogin = cookies.get('isLogin'); - + const navigate = useNavigate(); + + const notLoginContent = { + title: '로그인이 필요한 기능입니다.', + subText: '로그인하고 모든 서비스를 이용해 보세요! ', + cancelText: '닫기', + actionButton: '로그인하기', + isSmallSize: true, + }; const showNotLoginModal = () => { setIsModalOpen(true); + setModalContent({...notLoginContent}); }; const showToast = CustomToast(); @@ -120,7 +133,13 @@ function WishBtn({placeId, contentTypeId, size = '2.4rem', className = ''}: Wish <button onClick={() => setIsModalOpen(false)} className={styles.buttons__cancel}> 닫기 </button> - <button onClick={() => {}} className={styles.buttons__action}> + <button + onClick={() => { + navigate('/auth/login'); + document.body.style.removeProperty('overflow'); + }} + className={styles.buttons__action} + > 로그인하기 </button> </ModalFooter> diff --git a/src/pages/Detail/Detail.tsx b/src/pages/Detail/Detail.tsx index f684fb6e..945c75e7 100644 --- a/src/pages/Detail/Detail.tsx +++ b/src/pages/Detail/Detail.tsx @@ -73,6 +73,7 @@ function Detail() { /> <Main id={placeInfo.id} + areaCode={placeInfo.location.areaCode} contentTypeId={placeInfo.contentTypeId} images={placeInfo.gallery} title={placeInfo.title} diff --git a/src/recoil/detail/detail.ts b/src/recoil/detail/detail.ts index fb1a425e..a21a88df 100644 --- a/src/recoil/detail/detail.ts +++ b/src/recoil/detail/detail.ts @@ -44,3 +44,8 @@ export const TabYPosition = atom<number>({ key: 'TabYPosition', default: 0, }); + +export const isReviewStartState = atom<boolean>({ + key: 'isReviewStartState', + default: false, +});