diff --git a/package-lock.json b/package-lock.json index 2e1b0bc9..2b8c16ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "axios": "^1.6.5", "date-fns": "^2.0.0-alpha.27", "date-fns-tz": "^2.0.0", + "lodash": "^4.17.21", "react": "^18.2.0", "react-chartjs-2": "^5.2.0", "react-datepicker": "^4.25.0", @@ -36,6 +37,7 @@ "@swc/jest": "^0.2.29", "@tanstack/eslint-plugin-query": "^5.17.7", "@types/jest": "^29.5.11", + "@types/lodash": "^4.14.202", "@types/react": "^18.2.43", "@types/react-datepicker": "^4.19.5", "@types/react-dom": "^18.2.17", @@ -2821,6 +2823,12 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "dev": true + }, "node_modules/@types/node": { "version": "20.10.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", diff --git a/package.json b/package.json index 36b230f0..dbe30b84 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "axios": "^1.6.5", "date-fns": "^2.0.0-alpha.27", "date-fns-tz": "^2.0.0", + "lodash": "^4.17.21", "react": "^18.2.0", "react-chartjs-2": "^5.2.0", "react-datepicker": "^4.25.0", @@ -39,6 +40,7 @@ "@swc/jest": "^0.2.29", "@tanstack/eslint-plugin-query": "^5.17.7", "@types/jest": "^29.5.11", + "@types/lodash": "^4.14.202", "@types/react": "^18.2.43", "@types/react-datepicker": "^4.19.5", "@types/react-dom": "^18.2.17", diff --git a/src/api/lib/getCouponList.ts b/src/api/lib/getCouponList.ts index 4f18e474..8b5bc0bf 100644 --- a/src/api/lib/getCouponList.ts +++ b/src/api/lib/getCouponList.ts @@ -11,12 +11,14 @@ export const getCouponList = async ( accommodationId: number, date?: string, status?: string, - title?: string + title?: string, + size?: number ): Promise => { const params = { date, status, - title + title, + size }; const response = await instance.get( `/v1/accommodations/${accommodationId}/coupons`, @@ -46,7 +48,16 @@ export const couponDeleteApi = async ( return response.data; }; -// 토클 on/off api +// // 토클 on/off api +// export const couponToggleApi = async (credential: CouponToggleCredential) => { +// const couponNumber = credential.coupon_number; +// const response = await instance.put( +// `/v1/coupons/${couponNumber}/expose`, +// credential +// ); +// return response.data; +// }; + export const couponToggleApi = async (credential: CouponToggleCredential) => { const couponNumber = credential.coupon_number; await new Promise(resolve => setTimeout(resolve, 500)); @@ -54,5 +65,6 @@ export const couponToggleApi = async (credential: CouponToggleCredential) => { `/v1/coupons/${couponNumber}/expose`, credential ); + return response.data; }; diff --git a/src/assets/icons/ic-catchphrase-rocket.svg b/src/assets/icons/ic-catchphrase-rocket.svg index 7a6d56a4..acc99cfe 100644 --- a/src/assets/icons/ic-catchphrase-rocket.svg +++ b/src/assets/icons/ic-catchphrase-rocket.svg @@ -4,6 +4,6 @@ - + diff --git a/src/assets/icons/ic-couponlist-mobileregister.svg b/src/assets/icons/ic-couponlist-mobileregister.svg new file mode 100644 index 00000000..98a7ca4c --- /dev/null +++ b/src/assets/icons/ic-couponlist-mobileregister.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/ic-couponlist-speaker.svg b/src/assets/icons/ic-couponlist-speaker.svg index b19656ca..57a3909c 100644 --- a/src/assets/icons/ic-couponlist-speaker.svg +++ b/src/assets/icons/ic-couponlist-speaker.svg @@ -4,6 +4,6 @@ - + diff --git a/src/components/CouponList/CouponBanner/index.tsx b/src/components/CouponList/CouponBanner/index.tsx index b4e5ed1f..76e71e3b 100644 --- a/src/components/CouponList/CouponBanner/index.tsx +++ b/src/components/CouponList/CouponBanner/index.tsx @@ -4,12 +4,12 @@ import theme from '@styles/theme'; import bannerIcon from '@assets/icons/ic-couponlist-speaker.svg'; import { useRecoilValue } from 'recoil'; import { headerAccommodationState } from '@recoil/index'; -// import { useGetCouponRanking } from '@hooks/queries/useGetCouponRanking'; +import { useGetCouponRanking } from '@hooks/index'; const CouponBanner = () => { const headerAccommodation = useRecoilValue(headerAccommodationState); const sigunguData = headerAccommodation.sigungu; - // const { data } = useGetCouponRanking(headerAccommodation.id); + const { data } = useGetCouponRanking(headerAccommodation.id); return ( @@ -22,7 +22,7 @@ const CouponBanner = () => { 이번 달 우리 지역 인기 쿠폰 {sigunguData}에서 가장 많이 사용된 쿠폰은? - {/* {data.first_coupon_title}쿠폰이에요! */} + {data.first_coupon_title}쿠폰이에요! @@ -33,7 +33,11 @@ const CouponBanner = () => { export default CouponBanner; const BannerContainer = styled.div` - margin: 20px 50px; + margin: 20px 25px; + + @media (max-width: 656px) { + display: none; + } `; const TabBanner = styled.div` diff --git a/src/components/CouponList/CouponHeader/index.tsx b/src/components/CouponList/CouponHeader/index.tsx index 4fd530b4..90ff492b 100644 --- a/src/components/CouponList/CouponHeader/index.tsx +++ b/src/components/CouponList/CouponHeader/index.tsx @@ -28,17 +28,25 @@ const CouponHeader = () => { export default CouponHeader; const CouponHeaderContainer = styled.div` - margin: 56px 50px 0px; + margin: 36px 25px 0px; border-bottom: 1px solid #dde1e6; display: flex; justify-content: space-between; align-items: center; + + @media (max-width: 656px) { + display: none; + } `; const CouponHeaderWrapper = styled.div` display: flex; align-items: center; + + @media (max-width: 656px) { + display: flex; + } `; const CouponTitle = styled.div` diff --git a/src/components/CouponList/CouponItem/CouponExpired/index.tsx b/src/components/CouponList/CouponItem/CouponExpired/index.tsx index 59d9261b..ce898b30 100644 --- a/src/components/CouponList/CouponItem/CouponExpired/index.tsx +++ b/src/components/CouponList/CouponItem/CouponExpired/index.tsx @@ -5,11 +5,13 @@ import theme from '@styles/theme'; import rightIcon from '@assets/icons/ic-couponlist-right.svg'; import deleteIcon from '@assets/icons/ic-couponlist-delete.svg'; import { useCouponDelete, useOutsideClick } from '@hooks/index'; -import { CouponListProps } from '@/types/couponList'; +import { CouponListProps, RoomListProps } from '@/types/couponList'; import Modal from '@components/modal'; import { couponCondition } from '@utils/lib/couponCondition'; import { useToast } from '@components/common/ToastContext'; import couponRoomType from '@utils/lib/couponRoomType'; +import { useUpdateRoomListPosition } from '@utils/lib/roomListPosition'; +import concatTitle from '@utils/lib/concatTitle'; const CouponExpired = ({ couponInfo }: CouponListProps) => { const [isShowRoomList, setIsShowRoomList] = useState(false); @@ -17,9 +19,15 @@ const CouponExpired = ({ couponInfo }: CouponListProps) => { const [isShowModal, setIsShowModal] = useState(false); const { mutateAsync } = useCouponDelete(); const { showToast } = useToast(); + const roomListStyleRef = useRef(null); + const [isBottom, setIsBottom] = useState(false); // RoomList가 하단에 닿았는지 여부를 나타내는 상태 useOutsideClick(roomListRef, () => setIsShowRoomList(false)); + const formatDate = (dateString: string) => { + return dateString.replace(/-/g, '.'); + }; + const handleRoomList = () => { setIsShowRoomList(!isShowRoomList); }; @@ -28,7 +36,6 @@ const CouponExpired = ({ couponInfo }: CouponListProps) => { setIsShowModal(true); }; - // 모달 확인 버튼에 대한 동작 const handleModalConfirm = () => { try { mutateAsync({ coupon_number: couponInfo.coupon_number }); @@ -40,11 +47,13 @@ const CouponExpired = ({ couponInfo }: CouponListProps) => { setIsShowModal(false); }; - // 모달 취소 버튼에 대한 동작 const handleModalClose = () => { setIsShowModal(false); }; + // 객실 리스트 스크롤에 따라 위치 조정 + useUpdateRoomListPosition({ isShowRoomList, roomListStyleRef, setIsBottom }); + return ( @@ -52,7 +61,13 @@ const CouponExpired = ({ couponInfo }: CouponListProps) => { {couponInfo.title} 기간만료 - {couponInfo.coupon_concat_title} + + {concatTitle({ + customer_type: couponInfo.customer_type, + discount_flat_rate: couponInfo.discount_flat_rate, + discount_flat_value: couponInfo.discount_flat_value + })} + @@ -67,7 +82,10 @@ const CouponExpired = ({ couponInfo }: CouponListProps) => { 가격 - {couponInfo.minimum_reservation_price}원 이상 + {new Intl.NumberFormat().format( + couponInfo.minimum_reservation_price as number + )} + 원 이상 @@ -75,7 +93,10 @@ const CouponExpired = ({ couponInfo }: CouponListProps) => { {couponRoomType(couponInfo.coupon_room_types).join(', ')}, - {couponCondition(couponInfo.coupon_use_condition_days)} + {couponCondition({ + day: couponInfo.coupon_use_condition_days, + dayOfWeek: couponInfo.coupon_use_condition_days + })} @@ -85,7 +106,10 @@ const CouponExpired = ({ couponInfo }: CouponListProps) => { 전체 ) : ( <> - +
일부 객실
{ />
{isShowRoomList && ( - + 쿠폰 적용 객실 { 노출기간 - {couponInfo.exposure_start_date} ~ {couponInfo.exposure_end_date} + {formatDate(couponInfo.exposure_start_date)} ~{' '} + {formatDate(couponInfo.exposure_end_date)} 등록일 - {couponInfo.created_date} + + {formatDate(couponInfo.created_date)} + 삭제 @@ -342,33 +372,42 @@ const ContentRoom = styled.div` } `; -const RoomList = styled.div` +const RoomList = styled.div` position: absolute; - top: 0; + top: ${({ $isBottom }) => ($isBottom ? 'auto' : '0')}; + bottom: ${({ $isBottom }) => ($isBottom ? '0' : 'auto')}; right: 0; - z-index: 1; + z-index: 50; + transform: ${({ $isBottom }) => ($isBottom ? 'translateY(-100%)' : 'none')}; width: 188px; height: 204px; - margin-top: 150px; + margin-top: ${({ $isBottom }) => ($isBottom ? 'auto' : '150px')}; + margin-bottom: ${({ $isBottom }) => ($isBottom ? '-110px' : '150px')}; border-radius: 18px; - text-align: center; + text-align: center; background: #415574; &::before { content: ''; position: absolute; - top: -10px; + top: ${({ $isBottom }) => ($isBottom ? 'auto' : '-10px')}; + bottom: ${({ $isBottom }) => ($isBottom ? '0px' : 'auto')}; left: 50%; - transform: translateX(-50%); + transform: translateX(-50%) + ${({ $isBottom }) => ($isBottom ? 'translateY(100%)' : '')}; width: 0; height: 0; + border-left: 10px solid transparent; border-right: 10px solid transparent; - border-bottom: 10px solid #415574; + border-top: ${({ $isBottom }) => + $isBottom ? '10px solid #415574' : 'none'}; + border-bottom: ${({ $isBottom }) => + $isBottom ? 'none' : '10px solid #415574'}; } `; diff --git a/src/components/CouponList/CouponItem/CouponExpose/index.tsx b/src/components/CouponList/CouponItem/CouponExpose/index.tsx index dd3163a0..363a3fc7 100644 --- a/src/components/CouponList/CouponItem/CouponExpose/index.tsx +++ b/src/components/CouponList/CouponItem/CouponExpose/index.tsx @@ -6,19 +6,32 @@ import toggleOnIcon from '@assets/icons/ic-couponlist-toggleOn.svg'; import toggleOffIcon from '@assets/icons/ic-couponlist-toggleOff.svg'; import rightIcon from '@assets/icons/ic-couponlist-right.svg'; import deleteIcon from '@assets/icons/ic-couponlist-delete.svg'; -import { CouponListProps, ToggleStyleProps } from '@/types/couponList'; +import { + CouponListProps, + RoomListProps, + ToggleStyleProps +} from '@/types/couponList'; import { useOutsideClick, useToggleChange } from '@hooks/index'; import couponCondition from '@utils/lib/couponCondition'; import { useToast } from '@components/common/ToastContext'; import couponRoomType from '@utils/lib/couponRoomType'; +import { useUpdateRoomListPosition } from '@utils/lib/roomListPosition'; +import concatTitle from '@utils/lib/concatTitle'; const CouponExpose = ({ couponInfo }: CouponListProps) => { const [isToggle, setIsToggle] = useState(true); const [isShowRoomList, setIsShowRoomList] = useState(false); const roomListRef = useRef(null); + const roomListStyleRef = useRef(null); + const [isBottom, setIsBottom] = useState(false); // RoomList가 하단에 닿았는지 여부를 나타내는 상태 + const { mutateAsync } = useToggleChange(); const { showToast } = useToast(); + const formatDate = (dateString: string) => { + return dateString.replace(/-/g, '.'); + }; + const handleRoomList = () => { setIsShowRoomList(!isShowRoomList); }; @@ -30,6 +43,11 @@ const CouponExpose = ({ couponInfo }: CouponListProps) => { toggleUpdate(); }; + const filterTitle = + couponInfo.title.length > 10 + ? `${couponInfo.title.substring(0, 10)}...` + : couponInfo.title; + const toggleUpdate = async () => { try { await mutateAsync({ @@ -39,10 +57,13 @@ const CouponExpose = ({ couponInfo }: CouponListProps) => { console.log(couponInfo.coupon_number); showToast( -
- {couponInfo.title} 쿠폰의 노출이 중단되었습니다. - 실행 취소 -
, + +
+ {filterTitle} 쿠폰의
+ 노출이 중단되었습니다. +
+

실행 취소

+
, 2000 ); } catch (error) { @@ -50,28 +71,27 @@ const CouponExpose = ({ couponInfo }: CouponListProps) => { } }; - const retryToggleUpdate = () => { - setIsToggle(!isToggle); - mutateAsync({ - coupon_number: couponInfo.coupon_number, - coupon_status: '노출 ON' - }); - showToast(
{couponInfo.title} 쿠폰이 노출되었습니다.
, 2000); + const retryToggleUpdate = async () => { + try { + setIsToggle(!isToggle); + await mutateAsync({ + coupon_number: couponInfo.coupon_number, + coupon_status: '노출 ON' + }); + showToast( + + {couponInfo.title} 쿠폰이
+ 노출되었습니다. +
, + 2000 + ); + } catch (error) { + console.log(error); + } }; - // const retryToggleUpdate = async () => { - // try { - // setIsToggle(!isToggle); - // mutateAsync({ - // coupon_number: couponInfo.coupon_number, - // coupon_status: '노출 ON' - // }); - // console.log(isToggle); - // showToast(
{couponInfo.title} 쿠폰의 노출되었습니다.
, 3000); - // } catch (error) { - // console.log(error); - // } - // }; + // 객실 리스트 스크롤에 따라 위치 조정 + useUpdateRoomListPosition({ isShowRoomList, roomListStyleRef, setIsBottom }); return ( @@ -101,7 +121,13 @@ const CouponExpose = ({ couponInfo }: CouponListProps) => { )} - {couponInfo.coupon_concat_title} + + {concatTitle({ + customer_type: couponInfo.customer_type, + discount_flat_rate: couponInfo.discount_flat_rate, + discount_flat_value: couponInfo.discount_flat_value + })} + @@ -116,7 +142,10 @@ const CouponExpose = ({ couponInfo }: CouponListProps) => { 가격 - {couponInfo.minimum_reservation_price}원 이상 + {new Intl.NumberFormat().format( + couponInfo.minimum_reservation_price as number + )} + 원 이상 @@ -124,7 +153,10 @@ const CouponExpose = ({ couponInfo }: CouponListProps) => { {couponRoomType(couponInfo.coupon_room_types).join(', ')}, - {couponCondition(couponInfo.coupon_use_condition_days)} + {couponCondition({ + day: couponInfo.coupon_use_condition_days, + dayOfWeek: couponInfo.coupon_use_condition_days + })} @@ -134,7 +166,10 @@ const CouponExpose = ({ couponInfo }: CouponListProps) => { 전체 ) : ( <> - +
일부 객실
{ />
{isShowRoomList && ( - + 쿠폰 적용 객실 { 노출기간 - {couponInfo.exposure_start_date} ~ {couponInfo.exposure_end_date} + {formatDate(couponInfo.exposure_start_date)} ~{' '} + {formatDate(couponInfo.exposure_end_date)} 등록일 - {couponInfo.created_date} + + {formatDate(couponInfo.created_date)} +
@@ -339,33 +380,42 @@ const ContentRoom = styled.div` } `; -const RoomList = styled.div` +const RoomList = styled.div` position: absolute; - top: 0; + top: ${({ $isBottom }) => ($isBottom ? 'auto' : '0')}; + bottom: ${({ $isBottom }) => ($isBottom ? '0' : 'auto')}; right: 0; - z-index: 1; + z-index: 50; + transform: ${({ $isBottom }) => ($isBottom ? 'translateY(-100%)' : 'none')}; width: 188px; height: 204px; - margin-top: 150px; + margin-top: ${({ $isBottom }) => ($isBottom ? 'auto' : '150px')}; + margin-bottom: ${({ $isBottom }) => ($isBottom ? '-110px' : '150px')}; border-radius: 18px; - text-align: center; + text-align: center; background: #415574; &::before { content: ''; position: absolute; - top: -10px; + top: ${({ $isBottom }) => ($isBottom ? 'auto' : '-10px')}; + bottom: ${({ $isBottom }) => ($isBottom ? '0px' : 'auto')}; left: 50%; - transform: translateX(-50%); + transform: translateX(-50%) + ${({ $isBottom }) => ($isBottom ? 'translateY(100%)' : '')}; width: 0; height: 0; + border-left: 10px solid transparent; border-right: 10px solid transparent; - border-bottom: 10px solid #415574; + border-top: ${({ $isBottom }) => + $isBottom ? '10px solid #415574' : 'none'}; + border-bottom: ${({ $isBottom }) => + $isBottom ? 'none' : '10px solid #415574'}; } `; @@ -469,3 +519,13 @@ const RegisterDateValue = styled.div` font-style: normal; font-weight: 400; `; + +const ToastWrap = styled.div` + display: flex; + justify-content: space-between; + align-items: center; +`; + +const ToastText = styled.div` + text-align: center; +`; diff --git a/src/components/CouponList/CouponItem/CouponStop/index.tsx b/src/components/CouponList/CouponItem/CouponStop/index.tsx index 427b805a..af4d7dfc 100644 --- a/src/components/CouponList/CouponItem/CouponStop/index.tsx +++ b/src/components/CouponList/CouponItem/CouponStop/index.tsx @@ -6,11 +6,17 @@ import toggleOnIcon from '@assets/icons/ic-couponlist-toggleOn.svg'; import toggleOffIcon from '@assets/icons/ic-couponlist-toggleOff.svg'; import rightIcon from '@assets/icons/ic-couponlist-right.svg'; import deleteIcon from '@assets/icons/ic-couponlist-delete.svg'; -import { CouponListProps, ToggleStyleProps } from '@/types/couponList'; +import { + CouponListProps, + RoomListProps, + ToggleStyleProps +} from '@/types/couponList'; import { useOutsideClick, useToggleChange } from '@hooks/index'; import { couponCondition } from '@utils/lib/couponCondition'; import { useToast } from '@components/common/ToastContext'; import couponRoomType from '@utils/lib/couponRoomType'; +import { useUpdateRoomListPosition } from '@utils/lib/roomListPosition'; +import concatTitle from '@utils/lib/concatTitle'; const CouponStop = ({ couponInfo }: CouponListProps) => { const [isToggle, setIsToggle] = useState(false); @@ -18,9 +24,15 @@ const CouponStop = ({ couponInfo }: CouponListProps) => { const roomListRef = useRef(null); const { mutateAsync } = useToggleChange(); const { showToast } = useToast(); + const roomListStyleRef = useRef(null); + const [isBottom, setIsBottom] = useState(false); // RoomList가 하단에 닿았는지 여부를 나타내는 상태 useOutsideClick(roomListRef, () => setIsShowRoomList(false)); + const formatDate = (dateString: string) => { + return dateString.replace(/-/g, '.'); + }; + const handleRoomList = () => { setIsShowRoomList(!isShowRoomList); }; @@ -30,6 +42,11 @@ const CouponStop = ({ couponInfo }: CouponListProps) => { toggleUpdate(); }; + const filterTitle = + couponInfo.title.length > 10 + ? `${couponInfo.title.substring(0, 10)}...` + : couponInfo.title; + const toggleUpdate = async () => { try { await mutateAsync({ @@ -39,10 +56,13 @@ const CouponStop = ({ couponInfo }: CouponListProps) => { console.log(couponInfo.coupon_number); showToast( -
- {couponInfo.title} 쿠폰이 노출되었습니다. - 실행 취소 -
, + +
+ {filterTitle} 쿠폰이
+ 노출되었습니다. +
+

실행 취소

+
, 2000 ); } catch (error) { @@ -50,18 +70,28 @@ const CouponStop = ({ couponInfo }: CouponListProps) => { } }; - const retryToggleUpdate = () => { - setIsToggle(!isToggle); - mutateAsync({ - coupon_number: couponInfo.coupon_number, - coupon_status: '노출 OFF' - }); - showToast( -
{couponInfo.title} 쿠폰의 노출이 중단되었습니다.
, - 2000 - ); + const retryToggleUpdate = async () => { + try { + setIsToggle(!isToggle); + await mutateAsync({ + coupon_number: couponInfo.coupon_number, + coupon_status: '노출 OFF' + }); + showToast( + + {filterTitle} 쿠폰의 노출이
+ 중단되었습니다. +
, + 2000 + ); + } catch (error) { + console.log(error); + } }; + // 객실 리스트 스크롤에 따라 위치 조정 + useUpdateRoomListPosition({ isShowRoomList, roomListStyleRef, setIsBottom }); + return ( @@ -90,7 +120,13 @@ const CouponStop = ({ couponInfo }: CouponListProps) => { )} - {couponInfo.coupon_concat_title} + + {concatTitle({ + customer_type: couponInfo.customer_type, + discount_flat_rate: couponInfo.discount_flat_rate, + discount_flat_value: couponInfo.discount_flat_value + })} + @@ -105,7 +141,10 @@ const CouponStop = ({ couponInfo }: CouponListProps) => { 가격 - {couponInfo.minimum_reservation_price}원 이상 + {new Intl.NumberFormat().format( + couponInfo.minimum_reservation_price as number + )} + 원 이상 @@ -113,7 +152,10 @@ const CouponStop = ({ couponInfo }: CouponListProps) => { {couponRoomType(couponInfo.coupon_room_types).join(', ')}, - {couponCondition(couponInfo.coupon_use_condition_days)} + {couponCondition({ + day: couponInfo.coupon_use_condition_days, + dayOfWeek: couponInfo.coupon_use_condition_days + })} @@ -123,7 +165,10 @@ const CouponStop = ({ couponInfo }: CouponListProps) => { 전체 ) : ( <> - +
일부 객실
{ />
{isShowRoomList && ( - + 쿠폰 적용 객실 { 노출기간 - {couponInfo.exposure_start_date} ~ {couponInfo.exposure_end_date} + {formatDate(couponInfo.exposure_start_date)} ~ + {formatDate(couponInfo.exposure_end_date)} 등록일 - {couponInfo.created_date} + + {formatDate(couponInfo.created_date)} +
@@ -383,33 +434,42 @@ const ContentRoom = styled.div` } `; -const RoomList = styled.div` +const RoomList = styled.div` position: absolute; - top: 0; + top: ${({ $isBottom }) => ($isBottom ? 'auto' : '0')}; + bottom: ${({ $isBottom }) => ($isBottom ? '0' : 'auto')}; right: 0; - z-index: 1; + z-index: 50; + transform: ${({ $isBottom }) => ($isBottom ? 'translateY(-100%)' : 'none')}; width: 188px; height: 204px; - margin-top: 150px; + margin-top: ${({ $isBottom }) => ($isBottom ? 'auto' : '150px')}; + margin-bottom: ${({ $isBottom }) => ($isBottom ? '-110px' : '150px')}; border-radius: 18px; - text-align: center; + text-align: center; background: #415574; &::before { content: ''; position: absolute; - top: -10px; + top: ${({ $isBottom }) => ($isBottom ? 'auto' : '-10px')}; + bottom: ${({ $isBottom }) => ($isBottom ? '0px' : 'auto')}; left: 50%; - transform: translateX(-50%); + transform: translateX(-50%) + ${({ $isBottom }) => ($isBottom ? 'translateY(100%)' : '')}; width: 0; height: 0; + border-left: 10px solid transparent; border-right: 10px solid transparent; - border-bottom: 10px solid #415574; + border-top: ${({ $isBottom }) => + $isBottom ? '10px solid #415574' : 'none'}; + border-bottom: ${({ $isBottom }) => + $isBottom ? 'none' : '10px solid #415574'}; } `; @@ -459,3 +519,13 @@ const RoomListItem = styled.div` text-overflow: ellipsis; } `; + +const ToastWrap = styled.div` + display: flex; + justify-content: space-between; + align-items: center; +`; + +const ToastText = styled.div` + text-align: center; +`; diff --git a/src/components/CouponList/CouponItem/CouponWait/index.tsx b/src/components/CouponList/CouponItem/CouponWait/index.tsx index d921469b..fefd19ea 100644 --- a/src/components/CouponList/CouponItem/CouponWait/index.tsx +++ b/src/components/CouponList/CouponItem/CouponWait/index.tsx @@ -7,10 +7,12 @@ import centerIcon from '@assets/icons/ic-couponlist-center.svg'; import rightIcon from '@assets/icons/ic-couponlist-right.svg'; import deleteIcon from '@assets/icons/ic-couponlist-delete.svg'; import { useCouponDelete, useOutsideClick } from '@hooks/index'; -import { CouponListProps } from '@/types/couponList'; +import { CouponListProps, RoomListProps } from '@/types/couponList'; import Modal from '@components/modal'; import { couponCondition } from '@utils/lib/couponCondition'; import couponRoomType from '@utils/lib/couponRoomType'; +import { useUpdateRoomListPosition } from '@utils/lib/roomListPosition'; +import concatTitle from '@utils/lib/concatTitle'; const CouponWait = ({ couponInfo }: CouponListProps) => { const [isShowRoomList, setIsShowRoomList] = useState(false); @@ -18,6 +20,8 @@ const CouponWait = ({ couponInfo }: CouponListProps) => { const roomListRef = useRef(null); const [modalType, setModalType] = useState(''); const navigate = useNavigate(); + const roomListStyleRef = useRef(null); + const [isBottom, setIsBottom] = useState(false); // RoomList가 하단에 닿았는지 여부를 나타내는 상태 const [modalContent, setModalContent] = useState({ modalText: '', subText: false @@ -26,6 +30,10 @@ const CouponWait = ({ couponInfo }: CouponListProps) => { useOutsideClick(roomListRef, () => setIsShowRoomList(false)); + const formatDate = (dateString: string) => { + return dateString.replace(/-/g, '.'); + }; + const handleRoomList = () => { setIsShowRoomList(!isShowRoomList); }; @@ -63,6 +71,9 @@ const CouponWait = ({ couponInfo }: CouponListProps) => { setIsShowModal(false); }; + // 객실 리스트 스크롤에 따라 위치 조정 + useUpdateRoomListPosition({ isShowRoomList, roomListStyleRef, setIsBottom }); + return ( @@ -70,7 +81,13 @@ const CouponWait = ({ couponInfo }: CouponListProps) => { {couponInfo.title} 노출대기 - {couponInfo.coupon_concat_title} + + {concatTitle({ + customer_type: couponInfo.customer_type, + discount_flat_rate: couponInfo.discount_flat_rate, + discount_flat_value: couponInfo.discount_flat_value + })} + @@ -85,7 +102,10 @@ const CouponWait = ({ couponInfo }: CouponListProps) => { 가격 - {couponInfo.minimum_reservation_price}원 이상 + {new Intl.NumberFormat().format( + couponInfo.minimum_reservation_price as number + )} + 원 이상 @@ -93,7 +113,10 @@ const CouponWait = ({ couponInfo }: CouponListProps) => { {couponRoomType(couponInfo.coupon_room_types).join(', ')}, - {couponCondition(couponInfo.coupon_use_condition_days)} + {couponCondition({ + day: couponInfo.coupon_use_condition_days, + dayOfWeek: couponInfo.coupon_use_condition_days + })} @@ -103,7 +126,10 @@ const CouponWait = ({ couponInfo }: CouponListProps) => { 전체 ) : ( <> - +
일부 객실
{ />
{isShowRoomList && ( - + 쿠폰 적용 객실 { 노출기간 - {couponInfo.exposure_start_date} ~ {couponInfo.exposure_end_date} + {formatDate(couponInfo.exposure_start_date)} ~ + {formatDate(couponInfo.exposure_end_date)} 등록일 - {couponInfo.created_date} + + {formatDate(couponInfo.created_date)} + @@ -382,33 +414,42 @@ const ContentRoom = styled.div` }s `; -const RoomList = styled.div` +const RoomList = styled.div` position: absolute; - top: 0; + top: ${({ $isBottom }) => ($isBottom ? 'auto' : '0')}; + bottom: ${({ $isBottom }) => ($isBottom ? '0' : 'auto')}; right: 0; - z-index: 1; + z-index: 50; + transform: ${({ $isBottom }) => ($isBottom ? 'translateY(-100%)' : 'none')}; width: 188px; height: 204px; - margin-top: 150px; + margin-top: ${({ $isBottom }) => ($isBottom ? 'auto' : '150px')}; + margin-bottom: ${({ $isBottom }) => ($isBottom ? '-110px' : '150px')}; border-radius: 18px; - text-align: center; + text-align: center; background: #415574; &::before { content: ''; position: absolute; - top: -10px; + top: ${({ $isBottom }) => ($isBottom ? 'auto' : '-10px')}; + bottom: ${({ $isBottom }) => ($isBottom ? '0px' : 'auto')}; left: 50%; - transform: translateX(-50%); + transform: translateX(-50%) + ${({ $isBottom }) => ($isBottom ? 'translateY(100%)' : '')}; width: 0; height: 0; + border-left: 10px solid transparent; border-right: 10px solid transparent; - border-bottom: 10px solid #415574; + border-top: ${({ $isBottom }) => + $isBottom ? '10px solid #415574' : 'none'}; + border-bottom: ${({ $isBottom }) => + $isBottom ? 'none' : '10px solid #415574'}; } `; diff --git a/src/components/CouponList/CouponMain/index.tsx b/src/components/CouponList/CouponMain/index.tsx index de9308ad..c3ae9229 100644 --- a/src/components/CouponList/CouponMain/index.tsx +++ b/src/components/CouponList/CouponMain/index.tsx @@ -1,5 +1,6 @@ import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; +import { useNavigate } from 'react-router-dom'; import { CouponExpired, @@ -7,55 +8,72 @@ import { CouponStop, CouponWait } from '../CouponItem'; -import couponListState from '@recoil/atoms/couponListState'; +import theme from '@styles/theme'; +import mobileRegister from '@assets/icons/ic-couponlist-mobileregister.svg'; +import categoryTabState from '@recoil/atoms/categoryTabState'; +import { CouponListResponse } from '@/types/couponList'; -const CouponMain = () => { - const coupons = useRecoilValue(couponListState); +interface CouponMainProps { + coupons: CouponListResponse; +} - // // 최근 등록일 기준으로 나열 - // const sortedCoupons = coupons?.content - // ? [...coupons.content].sort((a, b) => { - // const dateA = new Date(a.created_date).getTime(); - // const dateB = new Date(b.created_date).getTime(); - // return dateB - dateA; - // }) - // : []; - // console.log('recoil로 관리되는 쿠폰 리스트 ', coupons); +const CouponMain = ({ coupons }: CouponMainProps) => { + const navigate = useNavigate(); + const categoryTab = useRecoilValue(categoryTabState); + + const handleRegisterClick = () => { + navigate('/coupons/register'); + }; return ( - {coupons?.content?.map(coupon => { + + {categoryTab.categoryTab} + {coupons?.content.length}개 + + 모든 쿠폰은 다운로드 후 14일까지 사용 가능하며, 등록 후 1년이 경과한 + 쿠폰은 조회되지 않습니다. + + + {coupons?.content.map((coupon, index) => { switch (coupon.coupon_status) { case '노출 ON': return ( ); case '노출 OFF': return ( ); case '노출 대기중': return ( ); case '노출 기간 만료': return ( ); } })} + + 모바일 등록 버튼 이미지 +

쿠폰 등록하기

+
); }; @@ -63,10 +81,105 @@ const CouponMain = () => { export default CouponMain; const MainContainer = styled.div` - margin-left: 50px; + margin-left: 25px; margin-bottom: 30px; display: flex; flex-flow: row wrap; - gap: 36px; + gap: 25px; + + @media (max-width: 900px) { + margin: 20px 20px 0px 20px; + border-radius: 10px; + padding-bottom:30px; + + display: flex; + justify-content: center; + gap: 27px; + align-items: center; + + background-color: ${theme.colors.white}; +`; + +const TabBottomWrap = styled.div` + display: none; + + @media (max-width: 656px) { + margin: 20px 28px -5px 28px; + + display: flex; + align-items: center; + } +`; + +const SecondTabName = styled.div` + margin-right: 5px; + + color: #a4a4a4; + font-size: 14px; + font-weight: 700; + + @media (max-width: 656px) { + font-size: 11px; + font-weight: 700; + white-space: nowrap; + } +`; + +const SecondTabCount = styled.div` + margin-right: 10px; + + color: #1a2849; + font-size: 14px; + font-weight: 700; + + @media (max-width: 656px) { + font-size: 11px; + font-weight: 700; + white-space: nowrap; + } +`; + +const CouponDescription = styled.div` + color: #a4a4a4; + font-size: 14px; + font-style: normal; + font-weight: 700; + + @media (max-width: 656px) { + width: 220px; + + font-size: 10.5px; + font-style: normal; + font-weight: 400; + line-height: 14px; + } +`; + +const MobileRegister = styled.div` + display: none; + + @media (max-width: 656px) { + position: absolute; + bottom: 0; + left: 0; + + margin-left: 15px; + margin-bottom: 15px; + + display: flex; + + cursor: pointer; + + p { + position: absolute; + + margin-left: 68px; + margin-top: 23px; + + color: ${theme.colors.white}; + font-size: 14px; + font-weight: 600; + } + } `; diff --git a/src/components/CouponList/CouponNav/index.tsx b/src/components/CouponList/CouponNav/index.tsx index 930f522c..d1c09055 100644 --- a/src/components/CouponList/CouponNav/index.tsx +++ b/src/components/CouponList/CouponNav/index.tsx @@ -1,88 +1,86 @@ import styled from '@emotion/styled'; -import { useEffect, useState } from 'react'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { useSetRecoilState } from 'recoil'; import theme from '@styles/theme'; import searchIcon from '@assets/icons/ic-couponlist-search.svg'; import centerIcon from '@assets/icons/ic-couponlist-period-center.svg'; -import { couponListState, headerAccommodationState } from '@recoil/index'; import { CategoryTabStyleProps, ResisterDateStyleProps } from '@/types/couponList'; -import { useGetCouponList } from '@hooks/queries/useCouponList'; - -const CouponNav = () => { - const [resisterDateClick, setResisterDateClick] = useState('1년'); - const [categoryTab, setCategoryTab] = useState('전체'); - const [searchText, setSearchText] = useState(''); - const headerAccommodation = useRecoilValue(headerAccommodationState); - const setGlobalCoupons = useSetRecoilState(couponListState); - const [searchAPI, setSearchAPI] = useState(''); +import categoryTabState from '@recoil/atoms/categoryTabState'; + +interface CouponNavProps { + all: number; + expiration: number; + exposure_off: number; + exposure_on: number; + length: number; + search: string; + onSearchChange: (value: string) => void; + registerDateClick: string; + onRegisterDateChange: (value: string) => void; + categoryTab: string; + onCategoryTabChange: (value: string) => void; +} + +const CouponNav = ({ + all, + expiration, + exposure_on, + exposure_off, + length, + search, + onSearchChange, + registerDateClick, + onRegisterDateChange, + categoryTab, + onCategoryTabChange +}: CouponNavProps) => { + const setGlobalCategoryTab = useSetRecoilState(categoryTabState); const handleDateClick = (period: string) => { - setResisterDateClick(period); - setSearchAPI(''); + onRegisterDateChange(period); }; const handleCategoryTab = (tab: string) => { - setCategoryTab(tab); - setSearchAPI(''); + onCategoryTabChange(tab); + setGlobalCategoryTab({ categoryTab: tab }); + onSearchChange(''); }; const handleSearchChange = (e: React.ChangeEvent) => { - setSearchText(e.target.value); + onSearchChange(e.target.value); }; const handleSearch = (e: React.FormEvent) => { e.preventDefault(); - setSearchAPI(searchText); - setSearchText(''); }; - const { data: coupons } = useGetCouponList( - headerAccommodation.id, - resisterDateClick !== '1년' ? resisterDateClick : undefined, - categoryTab !== '전체' ? categoryTab : undefined, - searchAPI - ); - - useEffect(() => { - setGlobalCoupons(coupons); - }, [ - headerAccommodation.id, - resisterDateClick, - categoryTab, - searchAPI, - coupons - ]); - return ( handleCategoryTab('전체')}> 전체 - - {coupons.category.all} - + {all} handleCategoryTab('노출 ON')}> 노출 ON - {coupons?.category.exposure_on} + {exposure_on} handleCategoryTab('노출 OFF')}> 노출 OFF - {coupons?.category.exposure_off} + {exposure_off} handleCategoryTab('만료')}> 만료 - {coupons?.category.expiration} + {expiration} @@ -90,7 +88,7 @@ const CouponNav = () => { @@ -104,7 +102,7 @@ const CouponNav = () => { {categoryTab} - {coupons?.content.length}개 + {length}개 모든 쿠폰은 다운로드 후 14일까지 사용 가능하며, 등록 후 1년이 경과한 쿠폰은 조회되지 않습니다. @@ -113,7 +111,7 @@ const CouponNav = () => { 등록일 기준 최근 handleDateClick('1년')} > 1년 @@ -123,7 +121,7 @@ const CouponNav = () => { alt="centerIcon" /> handleDateClick('6개월')} > 6개월 @@ -133,7 +131,7 @@ const CouponNav = () => { alt="centerIcon" /> handleDateClick('3개월')} > 3개월 @@ -147,24 +145,41 @@ const CouponNav = () => { export default CouponNav; const TabContainer = styled.div` - margin: 14px 50px; + margin: 14px 25px; + + @media (max-width: 656px) { + position: sticky; + top: 0; + z-index: 60; + + margin: 0px; + + background-color: ${theme.colors.white}; + box-shadow: 0 8px 10px -5px rgba(0, 0, 0, 0.2); + } `; const TabNavContainer = styled.div` - margin: 19px 0px; - display: flex; justify-content: space-between; flex-wrap: wrap; border-bottom: 1px solid #dde1e6; + + @media (max-width: 656px) { + border-bottom: none; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } `; const TabWrap = styled.div` margin-bottom: 19px; display: flex; - flex-wrap: wrap; `; const TapItemWrapper = styled.div` @@ -175,12 +190,22 @@ const TapItemWrapper = styled.div` align-items: center; cursor: pointer; + + @media (max-width: 656px) { + margin-right: 1px; + } `; const TabName = styled.div` font-size: 20px; font-weight: 700; color: #404446; + + @media (max-width: 656px) { + white-space: nowrap; + + font-size: 11px; + } `; const TabCount = styled.div` @@ -200,6 +225,15 @@ const TabCount = styled.div` color: ${props => (props.$categoryTab ? theme.colors.white : '#404040')}; background: ${props => (props.$categoryTab ? '#404446' : '#F2F4F5')}; + + @media (max-width: 656px) { + width: 41.019px; + height: 23.439px; + + margin: 0px 4px; + + font-size: 13px; + } `; const SearchWrap = styled.form` @@ -221,6 +255,16 @@ const SearchInput = styled.input` background: #f3f3f3; color: #646464; font-size: 14px; + + @media (max-width: 656px) { + width: 248px; + height: 37.123px; + + margin: 0px 13px 10px 0px; + padding-left: 33px; + + font-size: 11px; + } `; const SearchImg = styled.img` @@ -228,6 +272,14 @@ const SearchImg = styled.img` margin-top: 7px; margin-left: 20px; + + @media (max-width: 656px) { + width: 18px; + height: 18px; + + margin-top: 10px; + margin-left: 10px; + } `; const SearchButton = styled.button` @@ -244,6 +296,12 @@ const SearchButton = styled.button` color: ${theme.colors.white}; background-color: #1a2849; cursor: pointer; + + @media (max-width: 656px) { + width: 70px; + + font-size: 14px; + } `; const TabBottomContainer = styled.div` @@ -252,11 +310,19 @@ const TabBottomContainer = styled.div` display: flex; align-items: center; justify-content: space-between; + + @media (max-width: 656px) { + display: none; + } `; const TabBottomWrap = styled.div` display: flex; align-items: center; + + @media (max-width: 656px) { + margin: 0px 28px; + } `; const SecondTabName = styled.div` @@ -265,6 +331,13 @@ const SecondTabName = styled.div` color: #a4a4a4; font-size: 14px; font-weight: 700; + + @media (max-width: 656px) { + white-space: nowrap; + + font-size: 11px; + font-weight: 700; + } `; const SecondTabCount = styled.div` @@ -273,6 +346,13 @@ const SecondTabCount = styled.div` color: #1a2849; font-size: 14px; font-weight: 700; + + @media (max-width: 656px) { + font-size: 11px; + font-style: normal; + font-weight: 700; + white-space: nowrap; + } `; const CouponDescription = styled.div` @@ -280,18 +360,32 @@ const CouponDescription = styled.div` font-size: 14px; font-style: normal; font-weight: 700; + + @media (max-width: 656px) { + width: 220px; + + font-size: 10.5px; + font-style: normal; + font-weight: 400; + line-height: 14px; + } `; const ResisterPeriodWrap = styled.div` display: flex; align-items: center; + + @media (max-width: 1200px) { + display: none; + } `; const ResisterPeriodTitle = styled.div` + margin: 0px 5px; + color: #a4a4a4; font-size: 12px; font-weight: 400; - margin: 0px 5px; `; const ResisterPeriod = styled.div` diff --git a/src/components/CouponList/CouponOld/CouponExpired.tsx b/src/components/CouponList/CouponOld/CouponExpired.tsx deleted file mode 100644 index 0ba20f8b..00000000 --- a/src/components/CouponList/CouponOld/CouponExpired.tsx +++ /dev/null @@ -1,288 +0,0 @@ -import styled from '@emotion/styled'; -import expiredIcon from '@assets/icons/CouponList/ic_expose_expired.svg'; - -const CouponExpired = () => { - return ( -
- - - - expiredIcon - 쿠폰 기간 만료 - - - - 적용 객실 - 전체 - - - - 크리스마스 이벤트1 - 모든 고객 10% 할인 - - - - - 다운로드 -

50

-
- - 사용완료 -

50

-
-
- - -
가격 조건
-

300,000원 이상

-
- -
일정 조건
-

2박 이상, 금~토

-
-
- - -
노출 일자
-

2023.12.01 ~ 2023.12.31

-
- -
등록일
-
2023.12.01
-
-
- 삭제 -
-
- ); -}; - -export default CouponExpired; - -const CouponHeader = styled.div` - width: 219px; - height: 77px; - - border-radius: 10.608px 10.608px 0px 0px; - - display: flex; - flex-direction: column; - justify-content: center; - - background: #b1b1b1; -`; - -const ExposeContainer = styled.div` - display: flex; - justify-content: space-between; - padding: 4px 10px; -`; - -const ExposeWrap = styled.div` - display: flex; - align-items: center; - justify-content: center; -`; - -const ExposeText = styled.div` - color: #e3e5e5; - - margin-left: 2px; - - font-size: 12px; -`; - -const RoomWrap = styled.div` - display: flex; - align-items: center; - justify-content: center; -`; - -const ApplyRoom = styled.div` - position: relative; - - width: 194px; - height: 31px; - - padding-top: 12px; - padding-left: 10px; - border-radius: 8px; - - background-color: ${props => props.theme.colors.white}; - - font-size: 10px; - color: #b1b1b1; -`; - -const RoomButton = styled.button` - position: absolute; - - width: 113px; - height: 23px; - - margin-left: 76px; - border-radius: 12px; - border: 1px solid #b1b1b1; - - background-color: transparent; - - color: #b1b1b1; - font-size: 11px; -`; - -const CouponNabWrap = styled.div` - width: 217px; - height: 72px; - - margin-left: 1px; - padding: 15px; - box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.25); - border-bottom: 2px dashed #cdcfd0; - - background-color: ${props => props.theme.colors.white}; -`; - -const CouponTitle = styled.div` - color: #979c9e; - font-size: 13px; -`; - -const CouponCustomer = styled.div` - font-size: 16.997px; - font-weight: 700; - - margin-top: 5px; - color: #979c9e; -`; - -const CouponMain = styled.div` - width: 217px; - height: 245px; - - margin-left: 1px; - border-bottom: 1px dashed #b2b2b2; - - display: flex; - flex-direction: column; - align-items: center; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); - background: #fafafb; -`; - -const CountWrap = styled.div` - display: flex; - margin-top: 10px; -`; - -const CountItemWrap = styled.div` - width: 79px; - height: 83px; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin: 8px; - - border-radius: 12px; - - background-color: ${props => props.theme.colors.white}; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); - - p { - color: #cdcfd0; - font-size: 18px; - font-weight: 700; - } -`; - -const CountItemText = styled.div` - font-size: 12px; - font-weight: 600; - color: #cdcfd0; - margin: 5px; -`; - -const ConditionWrap = styled.div` - width: 176px; - height: 56px; - - display: flex; - flex-direction: column; - padding: 16px 15px 13px 14px; - margin-top: 5px; - - border-radius: 12px; - background-color: ${props => props.theme.colors.white}; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); -`; - -const ConditionWrapText = styled.div` - display: flex; - margin-top: 2px; - - div { - color: #cdcfd0; - font-size: 11px; - font-weight: 600; - margin-right: 10px; - } - - p { - color: #cdcfd0; - font-size: 11px; - font-weight: 400; - } -`; - -const ExposeDateContainer = styled.div` - margin-top: 20px; -`; - -const ExposeDateWrap = styled.div` - display: flex; - align-items: center; - - div { - color: #cdcfd0; - font-size: 11px; - font-weight: 600; - margin-right: 3px; - } - - p { - color: #cdcfd0; - font-size: 12px; - font-weight: 700; - text-decoration-line: underline; - } -`; - -const RegisterDateWrap = styled.div` - display: flex; - align-items: center; - - div { - color: #cdcfd0; - font-size: 9.724px; - font-weight: 400; - margin-top: 8px; - margin-right: 3px; - } -`; - -const DeleteButton = styled.button` - border: none; - - margin-left: 150px; - margin-top: -3px; - - font-size: 11px; - font-weight: 700; - color: #6c7072; - background: transparent; - cursor: pointer; -`; diff --git a/src/components/CouponList/CouponOld/CouponExpose.tsx b/src/components/CouponList/CouponOld/CouponExpose.tsx deleted file mode 100644 index d423a992..00000000 --- a/src/components/CouponList/CouponOld/CouponExpose.tsx +++ /dev/null @@ -1,308 +0,0 @@ -import exposeIcon from '@assets/icons/CouponList/ic_expose.svg'; -import toggleOnIcon from '@assets/icons/CouponList/ic_toggleOn.svg'; -import styled from '@emotion/styled'; - -const CouponExpose = () => { - return ( -
- - - - exposeIcon - 현재 노출 중 - - - ON - toggleOnIcon - - - - 적용 객실 - 전체 - - - - 크리스마스 이벤트1 - 모든 고객 10% 할인 - - - - - 다운로드 -

50

-
- - 사용완료 -

50

-
-
- - -
가격 조건
-

300,000원 이상

-
- -
일정 조건
-

2박 이상, 금~토

-
-
- - -
노출 일자
-

2023.12.01 ~ 2023.12.31

-
- -
등록일
-
2023.12.01
-
-
-
-
- ); -}; - -export default CouponExpose; - -const CouponHeader = styled.div` - width: 219px; - height: 77px; - - border-radius: 10.608px 10.608px 0px 0px; - - display: flex; - flex-direction: column; - justify-content: center; - - background: var( - --gradient, - linear-gradient(91deg, #ff3478 1.39%, #ff83ad 98.63%) - ); -`; - -const ExposeContainer = styled.div` - display: flex; - justify-content: space-between; - padding: 4px 10px; -`; - -const ExposeWrap = styled.div` - display: flex; - align-items: center; - justify-content: center; -`; - -const ExposeText = styled.div` - color: ${props => props.theme.colors.white}; - - margin-left: 2px; - - font-size: 12px; -`; - -const ToggleWrap = styled.div` - width: 48.229px; - height: 23.526px; - - border-radius: 17.68px; - border: 1px solid #e3e5e5; - - display: flex; - align-items: center; - justify-content: space-between; - padding-top: 3px; - padding-left: 5px; - - background-color: ${props => props.theme.colors.white}; - cursor: pointer; -`; - -const ToggleText = styled.div` - font-size: 10px; - - color: ${props => props.theme.colors.pink500}; -`; - -const RoomWrap = styled.div` - display: flex; - align-items: center; - justify-content: center; -`; - -const ApplyRoom = styled.div` - position: relative; - - width: 194px; - height: 31px; - - padding-top: 12px; - padding-left: 10px; - border-radius: 8px; - - background-color: ${props => props.theme.colors.white}; - - font-size: 10px; - color: #404446; -`; - -const RoomButton = styled.button` - position: absolute; - - width: 113px; - height: 23px; - - margin-left: 76px; - border-radius: 12px; - border: 1px solid #ffadc8; - - background-color: transparent; - - color: ${props => props.theme.colors.pink500}; - font-size: 11px; -`; - -const CouponNabWrap = styled.div` - width: 217px; - height: 72px; - - margin-left: 1px; - padding: 15px; - box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.25); - border-bottom: 2px dashed ${props => props.theme.colors.pink500}; - - background-color: ${props => props.theme.colors.white}; -`; - -const CouponTitle = styled.div` - color: #6c7072; - font-size: 13px; -`; - -const CouponCustomer = styled.div` - font-size: 16.997px; - font-weight: 700; - - margin-top: 5px; - color: #202325; -`; - -const CouponMain = styled.div` - width: 217px; - height: 245px; - - margin-left: 1px; - border-bottom: 1px dashed #b2b2b2; - - display: flex; - flex-direction: column; - align-items: center; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); - background: #fafafb; -`; - -const CountWrap = styled.div` - display: flex; - margin-top: 10px; -`; - -const CountItemWrap = styled.div` - width: 79px; - height: 83px; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin: 8px; - - border-radius: 12px; - - background-color: ${props => props.theme.colors.white}; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); - - p { - color: #404446; - font-size: 18px; - font-weight: 700; - } -`; - -const CountItemText = styled.div` - font-size: 12px; - font-weight: 600; - color: #757676; - margin: 5px; -`; - -const ConditionWrap = styled.div` - width: 176px; - height: 56px; - - display: flex; - flex-direction: column; - padding: 16px 15px 13px 14px; - margin-top: 5px; - - border-radius: 12px; - background-color: ${props => props.theme.colors.white}; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); -`; - -const ConditionWrapText = styled.div` - display: flex; - margin-top: 2px; - - div { - color: #404446; - font-size: 11px; - font-weight: 600; - margin-right: 10px; - } - - p { - color: #404446; - font-size: 11px; - font-weight: 400; - } -`; - -const ExposeDateContainer = styled.div` - margin-top: 18px; -`; - -const ExposeDateWrap = styled.div` - display: flex; - align-items: center; - - div { - color: #404446; - font-size: 11px; - font-weight: 600; - margin-right: 3px; - } - - p { - color: ${props => props.theme.colors.pink500}; - font-size: 12px; - font-weight: 700; - text-decoration-line: underline; - } -`; - -const RegisterDateWrap = styled.div` - display: flex; - align-items: center; - - div { - color: #757676; - font-size: 9.724px; - font-weight: 400; - margin-top: 8px; - margin-right: 3px; - } -`; diff --git a/src/components/CouponList/CouponOld/CouponStop.tsx b/src/components/CouponList/CouponOld/CouponStop.tsx deleted file mode 100644 index ade3bd13..00000000 --- a/src/components/CouponList/CouponOld/CouponStop.tsx +++ /dev/null @@ -1,305 +0,0 @@ -import styled from '@emotion/styled'; -import stopIcon from '@assets/icons/CouponList/ic_expose_stop.svg'; -import toggleOffIcon from '@assets/icons/CouponList/ic_toggleOff.svg'; -const CouponStop = () => { - const handleExpose = () => {}; - - return ( -
- - - - stopIcon - 쿠폰 노출 중지 - - - toggleOffIcon - OFF - - - - 적용 객실 - 전체 - - - - 크리스마스 이벤트1 - 모든 고객 10% 할인 - - - - - 다운로드 -

50

-
- - 사용완료 -

50

-
-
- - -
가격 조건
-

300,000원 이상

-
- -
일정 조건
-

2박 이상, 금~토

-
-
- - -
노출 일자
-

2023.12.01 ~ 2023.12.31

-
- -
등록일
-
2023.12.01
-
-
-
-
- ); -}; - -export default CouponStop; - -const CouponHeader = styled.div` - width: 219px; - height: 77px; - - border-radius: 10.608px 10.608px 0px 0px; - - display: flex; - flex-direction: column; - justify-content: center; - - background: #b1b1b1; -`; - -const ExposeContainer = styled.div` - display: flex; - justify-content: space-between; - padding: 4px 10px; -`; - -const ExposeWrap = styled.div` - display: flex; - align-items: center; - justify-content: center; -`; - -const ExposeText = styled.div` - color: #da1e28; - - margin-left: 2px; - - font-size: 12px; -`; - -const ToggleWrap = styled.div` - width: 48.229px; - height: 23.526px; - - border-radius: 17.68px; - border: 1px solid #e3e5e5; - - display: flex; - align-items: center; - padding-top: 3px; - padding-left: 2px; - - background-color: ${props => props.theme.colors.white}; - cursor: pointer; -`; - -const ToggleText = styled.div` - font-size: 10px; - - color: #cdcfd0; -`; - -const RoomWrap = styled.div` - display: flex; - align-items: center; - justify-content: center; -`; - -const ApplyRoom = styled.div` - position: relative; - - width: 194px; - height: 31px; - - padding-top: 12px; - padding-left: 10px; - border-radius: 8px; - - background-color: ${props => props.theme.colors.white}; - - font-size: 10px; - color: #404446; -`; - -const RoomButton = styled.button` - position: absolute; - - width: 113px; - height: 23px; - - margin-left: 76px; - border-radius: 12px; - border: 1px solid #6c7072; - - background-color: transparent; - - color: #6c7072; - font-size: 11px; -`; - -const CouponNabWrap = styled.div` - width: 217px; - height: 72px; - - margin-left: 1px; - padding: 15px; - box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.25); - border-bottom: 2px dashed #cdcfd0; - - background-color: ${props => props.theme.colors.white}; -`; - -const CouponTitle = styled.div` - color: #6c7072; - font-size: 13px; -`; - -const CouponCustomer = styled.div` - font-size: 16.997px; - font-weight: 700; - - margin-top: 5px; - color: #202325; -`; - -const CouponMain = styled.div` - width: 217px; - height: 245px; - - margin-left: 1px; - border-bottom: 1px dashed #b2b2b2; - - display: flex; - flex-direction: column; - align-items: center; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); - background: #fafafb; -`; - -const CountWrap = styled.div` - display: flex; - margin-top: 10px; -`; - -const CountItemWrap = styled.div` - width: 79px; - height: 83px; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin: 8px; - - border-radius: 12px; - - background-color: ${props => props.theme.colors.white}; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); - - p { - color: #404446; - font-size: 18px; - font-weight: 700; - } -`; - -const CountItemText = styled.div` - font-size: 12px; - font-weight: 600; - color: #757676; - margin: 5px; -`; - -const ConditionWrap = styled.div` - width: 176px; - height: 56px; - - display: flex; - flex-direction: column; - padding: 16px 15px 13px 14px; - margin-top: 5px; - - border-radius: 12px; - background-color: ${props => props.theme.colors.white}; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); -`; - -const ConditionWrapText = styled.div` - display: flex; - margin-top: 2px; - - div { - color: #404446; - font-size: 11px; - font-weight: 600; - margin-right: 10px; - } - - p { - color: #404446; - font-size: 11px; - font-weight: 400; - } -`; - -const ExposeDateContainer = styled.div` - margin-top: 18px; -`; - -const ExposeDateWrap = styled.div` - display: flex; - align-items: center; - - div { - color: #404446; - font-size: 11px; - font-weight: 600; - margin-right: 3px; - } - - p { - color: ${props => props.theme.colors.pink500}; - font-size: 12px; - font-weight: 700; - text-decoration-line: underline; - } -`; - -const RegisterDateWrap = styled.div` - display: flex; - align-items: center; - - div { - color: #757676; - font-size: 9.724px; - font-weight: 400; - margin-top: 8px; - margin-right: 3px; - } -`; diff --git a/src/components/CouponList/CouponOld/CouponWait.tsx b/src/components/CouponList/CouponOld/CouponWait.tsx deleted file mode 100644 index 92ac74c0..00000000 --- a/src/components/CouponList/CouponOld/CouponWait.tsx +++ /dev/null @@ -1,299 +0,0 @@ -import styled from '@emotion/styled'; -import waitIcon from '@assets/icons/CouponList/ic_expose_wait.svg'; -import centerIcon from '@assets/icons/CouponList/ic_center.svg'; - -const CouponWait = () => { - return ( -
- - - - waitIcon - 쿠폰 노출 대기 - - - - 적용 객실 - 전체 - - - - 크리스마스 이벤트1 - 모든 고객 10% 할인 - - - - - 다운로드 -

50

-
- - 사용완료 -

50

-
-
- - -
가격 조건
-

300,000원 이상

-
- -
일정 조건
-

2박 이상, 금~토

-
-
- - -
노출 일자
-

2023.12.01 ~ 2023.12.31

-
- -
등록일
-
2023.12.01
-
-
- - - centerIcon - - -
-
- ); -}; - -export default CouponWait; - -const CouponHeader = styled.div` - width: 219px; - height: 77px; - - border-radius: 10.608px 10.608px 0px 0px; - - display: flex; - flex-direction: column; - justify-content: center; - - background: #b1b1b1; -`; - -const ExposeContainer = styled.div` - display: flex; - justify-content: space-between; - padding: 4px 10px; -`; - -const ExposeWrap = styled.div` - display: flex; - align-items: center; - justify-content: center; -`; - -const ExposeText = styled.div` - color: #202325; - - margin-left: 2px; - - font-size: 12px; -`; - -const RoomWrap = styled.div` - display: flex; - align-items: center; - justify-content: center; -`; - -const ApplyRoom = styled.div` - position: relative; - - width: 194px; - height: 31px; - - padding-top: 12px; - padding-left: 10px; - border-radius: 8px; - - background-color: ${props => props.theme.colors.white}; - - font-size: 10px; - color: #404446; -`; - -const RoomButton = styled.button` - position: absolute; - - width: 113px; - height: 23px; - - margin-left: 76px; - border-radius: 12px; - border: 1px solid #6c7072; - - background-color: transparent; - - color: #6c7072; - font-size: 11px; -`; - -const CouponNabWrap = styled.div` - width: 217px; - height: 72px; - - margin-left: 1px; - padding: 15px; - box-shadow: 0px -4px 4px 0px rgba(0, 0, 0, 0.25); - border-bottom: 2px dashed #cdcfd0; - - background-color: ${props => props.theme.colors.white}; -`; - -const CouponTitle = styled.div` - color: #6c7072; - font-size: 13px; -`; - -const CouponCustomer = styled.div` - font-size: 16.997px; - font-weight: 700; - - margin-top: 5px; - color: #202325; -`; - -const CouponMain = styled.div` - width: 217px; - height: 245px; - - margin-left: 1px; - border-bottom: 1px dashed #b2b2b2; - - display: flex; - flex-direction: column; - align-items: center; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); - background: #fafafb; -`; - -const CountWrap = styled.div` - display: flex; - margin-top: 10px; -`; - -const CountItemWrap = styled.div` - width: 79px; - height: 83px; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin: 8px; - - border-radius: 12px; - - background-color: ${props => props.theme.colors.white}; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); - - p { - color: #404446; - font-size: 18px; - font-weight: 700; - } -`; - -const CountItemText = styled.div` - font-size: 12px; - font-weight: 600; - color: #757676; - margin: 5px; -`; - -const ConditionWrap = styled.div` - width: 176px; - height: 56px; - - display: flex; - flex-direction: column; - padding: 16px 15px 13px 14px; - margin-top: 5px; - - border-radius: 12px; - background-color: ${props => props.theme.colors.white}; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); -`; - -const ConditionWrapText = styled.div` - display: flex; - margin-top: 2px; - - div { - color: #404446; - font-size: 11px; - font-weight: 600; - margin-right: 10px; - } - - p { - color: #404446; - font-size: 11px; - font-weight: 400; - } -`; - -const ExposeDateContainer = styled.div` - margin-top: 18px; -`; - -const ExposeDateWrap = styled.div` - display: flex; - align-items: center; - - div { - color: #404446; - font-size: 11px; - font-weight: 600; - margin-right: 3px; - } - - p { - color: ${props => props.theme.colors.pink500}; - font-size: 12px; - font-weight: 700; - text-decoration-line: underline; - } -`; - -const RegisterDateWrap = styled.div` - display: flex; - align-items: center; - - div { - color: #757676; - font-size: 9.724px; - font-weight: 400; - margin-top: 8px; - margin-right: 3px; - } -`; - -const ButtonWrap = styled.div` - display: flex; - margin-left: 115px; - margin-top: -3px; - - button { - background: transparent; - border: none; - color: #6c7072; - font-size: 11px; - font-style: normal; - font-weight: 700; - cursor: pointer; - } -`; diff --git a/src/components/common/ToastContext/index.tsx b/src/components/common/ToastContext/index.tsx index 716fc116..ef582207 100644 --- a/src/components/common/ToastContext/index.tsx +++ b/src/components/common/ToastContext/index.tsx @@ -52,29 +52,27 @@ const ToastContainer = styled.div` bottom: 50px; left: 50%; transform: translateX(-50%); + z-index: 100; + + width: 336px; + + padding: 24px 28px; white-space: nowrap; - padding: 15px 31px; border-radius: 5px; background: #404446; - font-size: 13px; color: ${theme.colors.white}; + font-size:15px; + line-height:20px; - span { - margin-left: 59px; - - color: #3182f6; - font-size: 15px; - text-decoration-line: underline; - cursor: pointer; - } - @media (max-width: 900px) { - font-size: 10px; - span { - margin-left: 20px; - font-size: 10px; + p { + color: #65a6eb; + font-size: 15px; + text-decoration-line: underline; + cursor: pointer; + text-align: center; } } `; diff --git a/src/components/modal/index.tsx b/src/components/modal/index.tsx index dd7717ad..52eea9eb 100644 --- a/src/components/modal/index.tsx +++ b/src/components/modal/index.tsx @@ -30,8 +30,8 @@ const Modal = ({ 삭제한 쿠폰은 복구할 수 없습니다. )} - 확인 취소 + 확인 @@ -42,14 +42,14 @@ export default Modal; const ModalContainer = styled.div` position: fixed; - z-index: 1; + z-index: 100; top: 0; left: 0; width: 100%; height: 100%; - background: var(--Back-Ground, rgba(66, 66, 66, 0.5)); + background: rgba(66, 66, 66, 0.5); `; const ModalWrap = styled.div` @@ -70,6 +70,13 @@ const ModalWrap = styled.div` background: var(--Main-Color-White, #fff); box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); + + @media (max-width: 900px) { + width: 336px; + height: 210px; + + transform: translate(-50%, -50%); + } `; const ModalText = styled.div` @@ -110,6 +117,11 @@ const ConfirmButton = styled.button` &:hover { background: #5f6980; } + + @media (max-width: 900px) { + width: 140px; + height: 40px; + } `; const CancelButton = styled.button` width: 158px; @@ -125,4 +137,9 @@ const CancelButton = styled.button` &:hover { background: #404446; } + + @media (max-width: 900px) { + width: 140px; + height: 40px; + } `; diff --git a/src/hooks/queries/useCouponList.ts b/src/hooks/queries/useCouponList.ts index f2394b7f..de92c43e 100644 --- a/src/hooks/queries/useCouponList.ts +++ b/src/hooks/queries/useCouponList.ts @@ -1,19 +1,21 @@ +import { getCouponList } from './../../api/lib/getCouponList'; import { CouponDeleteCredential, CouponListResponse, CouponToggleCredential, CouponUpdateCredential } from '@/types/couponList'; + import { useMutation, useQueryClient, useSuspenseQuery } from '@tanstack/react-query'; + import { couponDeleteApi, couponToggleApi, - couponUpdateApi, - getCouponList + couponUpdateApi } from 'src/api/lib/getCouponList'; // 쿠폰 조회 @@ -21,11 +23,12 @@ export const useGetCouponList = ( accommodationId: number, date?: string, status?: string, - title?: string + title?: string, + size?: number ) => useSuspenseQuery({ - queryKey: ['CouponList', accommodationId, status, date, title], - queryFn: () => getCouponList(accommodationId, date, status, title) + queryKey: ['CouponList', accommodationId, status, date, title, size], + queryFn: () => getCouponList(accommodationId, date, status, title, size) }); // 쿠폰 수정 diff --git a/src/pages/CouponList/index.tsx b/src/pages/CouponList/index.tsx index 6d8bcaee..5d72ba15 100644 --- a/src/pages/CouponList/index.tsx +++ b/src/pages/CouponList/index.tsx @@ -4,16 +4,118 @@ import { CouponMain, CouponBanner } from '@components/CouponList'; +import styled from '@emotion/styled'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { debounce } from 'lodash'; +import { useRecoilValue } from 'recoil'; +import { headerAccommodationState } from '@recoil/index'; +import { useGetCouponList } from '@hooks/queries/useCouponList'; +import { CouponListResponse } from '@/types/couponList'; const CouponList = () => { + const [search, setSearch] = useState(''); + const [debouncePrefix, setDebouncePrefix] = useState(''); + const headerAccommodation = useRecoilValue(headerAccommodationState); + const [registerDateClick, setRegisterDateClick] = useState('1년'); + const [categoryTab, setCategoryTab] = useState('전체'); + const observerRef = useRef(null); + const [page, setPage] = useState(1); + const couponRef = useRef(null); + + const { data: coupons } = useGetCouponList( + headerAccommodation.id, + registerDateClick !== '1년' ? registerDateClick : undefined, + categoryTab !== '전체' ? categoryTab : undefined, + debouncePrefix, + page * 10 + ); + + const debounceOnChange = useCallback( + debounce((value: string) => { + setDebouncePrefix(value); + }, 500), + [] + ); + + useEffect(() => { + if (coupons) { + couponRef.current = coupons; + } + }, [coupons]); + + useEffect(() => { + const observer = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + // console.log(page); + if (couponRef.current && page <= couponRef.current.total_pages) { + setPage(prev => prev + 1); + } + } + }); + }); + + if (observerRef.current) { + observer.observe(observerRef.current); + } + + return () => { + observer.disconnect(); + }; + }, [page]); + + const handleChangeSearch = (value: string) => { + setSearch(value); + debounceOnChange(value); + }; + + const handleChangeDate = (value: string) => { + setRegisterDateClick(value); + setPage(1); + }; + + const handleChangeCategory = (value: string) => { + setCategoryTab(value); + setPage(1); + }; + return ( -
- - - - -
+ + {coupons && ( + <> + + + + + + + )} + ); }; export default CouponList; + +const CouponListContainer = styled.div` + @media (max-width: 656px) { + min-height: 100vh; + background: #f2f3f5; + } +`; + +const ObserverContainer = styled.div` + width: 100%; + height: 10px; +`; diff --git a/src/recoil/atoms/categoryTabState.ts b/src/recoil/atoms/categoryTabState.ts new file mode 100644 index 00000000..31737de0 --- /dev/null +++ b/src/recoil/atoms/categoryTabState.ts @@ -0,0 +1,10 @@ +import { atom } from 'recoil'; + +import { CategoryTab } from '@/types/couponList'; + +const categoryTabState = atom({ + key: 'categoryTabState', + default: { categoryTab: '전체' } +}); + +export default categoryTabState; diff --git a/src/types/couponList.ts b/src/types/couponList.ts index 6681befa..f45a4c5d 100644 --- a/src/types/couponList.ts +++ b/src/types/couponList.ts @@ -1,3 +1,5 @@ +import { RefObject } from 'react'; + export interface ToggleStyleProps { $isToggle: boolean; } @@ -10,6 +12,10 @@ export interface CategoryTabStyleProps { $categoryTab: boolean; } +export interface RoomListProps { + $isBottom: boolean; +} + // api 쿠폰 리스트정보 응답 데이터 export interface CouponListResponse { content: CouponInformationResponse[]; @@ -37,10 +43,14 @@ export interface CouponInformationResponse { coupon_concat_title: string; discount_type: string; discount_value: number; + discount_flat_rate: number | null; + discount_flat_value: number | null; + maximum_discount_price: number | null; customer_type: string; coupon_room_types: string[]; minimum_reservation_price: number; coupon_use_condition_days: string; + coupon_use_condition_day_of_week: string; exposure_start_date: string; exposure_end_date: string; coupon_expiration: number; @@ -56,12 +66,15 @@ export interface CouponListProps { couponInfo: CouponInformationResponse; } +// 쿠폰 수정 export interface CouponUpdateCredential { coupon_number: string | undefined; accommodation_id: number; customer_type: string; discount_type: string; discount_value: number; + discount_flat_rate: number | null; + maximum_discount_price: number | null; coupon_room_type: string; register_all_room: false; register_rooms: string[]; @@ -71,6 +84,7 @@ export interface CouponUpdateCredential { exposure_end_date: string; } +// 쿠폰 삭제 export interface CouponDeleteCredential { coupon_number: string | undefined; } @@ -81,10 +95,23 @@ export interface CouponToggleCredential { coupon_status: string; } -// HACK : 쿠폰 요청 타입 -// export interface GetCouponListCredential { -// accommodationId: number; -// date?: string; -// status?: string; -// title?: string; -// } +export interface CategoryTab { + categoryTab: string; +} + +export interface RoomListStyleProps { + isShowRoomList: boolean; + roomListStyleRef: RefObject; + setIsBottom: (isBottom: boolean) => void; +} + +export interface CouponConditionProps { + day: string | null; + dayOfWeek: string | null; +} + +export interface ConcatTitleProps { + customer_type: string; + discount_flat_rate: number | null; + discount_flat_value: number | null; +} diff --git a/src/utils/lib/concatTitle.ts b/src/utils/lib/concatTitle.ts new file mode 100644 index 00000000..5358d93a --- /dev/null +++ b/src/utils/lib/concatTitle.ts @@ -0,0 +1,18 @@ +import { ConcatTitleProps } from '@/types/couponList'; + +export const concatTitle = ({ + customer_type, + discount_flat_rate, + discount_flat_value +}: ConcatTitleProps) => { + if (discount_flat_rate !== null) { + return `${customer_type} ${discount_flat_rate}% 할인`; + } else if (discount_flat_value !== null) { + const formattedValue = new Intl.NumberFormat().format(discount_flat_value); + return `${customer_type} ${formattedValue}원 할인`; + } + + return null; +}; + +export default concatTitle; diff --git a/src/utils/lib/couponCondition.ts b/src/utils/lib/couponCondition.ts index bc39eec2..0d4fc0ef 100644 --- a/src/utils/lib/couponCondition.ts +++ b/src/utils/lib/couponCondition.ts @@ -1,12 +1,14 @@ -export const couponCondition = (conditionDays: string): string => { - if (conditionDays.length === 1) { - return `${conditionDays}요일`; - } else if (conditionDays === '평일') { +import { CouponConditionProps } from '@/types/couponList'; + +export const couponCondition = ({ day, dayOfWeek }: CouponConditionProps) => { + if (day === '하루만') { + return `${dayOfWeek}`; + } else if (day === '평일') { return '일~목'; - } else if (conditionDays === '주말') { + } else if (day === '주말') { return '금~토'; } - return conditionDays; + return '전체'; }; export default couponCondition; diff --git a/src/utils/lib/roomListPosition.ts b/src/utils/lib/roomListPosition.ts new file mode 100644 index 00000000..f9e0fa9b --- /dev/null +++ b/src/utils/lib/roomListPosition.ts @@ -0,0 +1,35 @@ +import { RoomListStyleProps } from '@/types/couponList'; +import { useEffect } from 'react'; + +export const useUpdateRoomListPosition = ({ + isShowRoomList, + roomListStyleRef, + setIsBottom +}: RoomListStyleProps) => { + const updateRoomListPosition = () => { + if (roomListStyleRef.current) { + const roomListRect = roomListStyleRef.current.getBoundingClientRect(); + const viewportHeight = window.innerHeight; + setIsBottom(roomListRect.bottom > viewportHeight); + } + }; + + useEffect(() => { + const handleResizeOrScroll = () => { + updateRoomListPosition(); + }; + + // 스크롤 및 창 크기 변경 이벤트에 리스너 추가 + window.addEventListener('scroll', handleResizeOrScroll); + window.addEventListener('resize', handleResizeOrScroll); + + // 컴포넌트 마운트 시 또는 isShowRoomList 상태 변경 시 위치 업데이트 + handleResizeOrScroll(); + + // 컴포넌트 언마운트 시 또는 의존성 배열 내 값이 변경될 때 이벤트 리스너 제거 + return () => { + window.removeEventListener('scroll', handleResizeOrScroll); + window.removeEventListener('resize', handleResizeOrScroll); + }; + }, [isShowRoomList]); // 의존성 배열에 isShowRoomList 추가 +};