Skip to content

Commit

Permalink
✨ Feat, 🔧 Fix, ♻️ Refactor : 결제 페이지 및 검색 결과 개선
Browse files Browse the repository at this point in the history
✨ Feat, 🔧 Fix, ♻️ Refactor : 결제 페이지 및 검색 결과 개선
  • Loading branch information
eunjju2 authored Jan 10, 2025
2 parents 6537fe8 + 1ff3b30 commit 49b8f66
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 26 deletions.
88 changes: 88 additions & 0 deletions src/pages/PaymentPage/components/CollectionModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { useEffect, useRef } from 'react';
import { AiOutlineClose } from 'react-icons/ai';

interface CollectionModalProps {
onClose: () => void;
}

const CollectionModal = (props: CollectionModalProps) => {
const { onClose } = props;

const modalRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const handleOutsideClose = (e: { target: unknown }) => {
if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
onClose();
}
};
document.addEventListener('mousedown', handleOutsideClose);

return () => document.removeEventListener('mousedown', handleOutsideClose);
}, [onClose]);

return (
<div className='fixed left-[50%] top-0 z-[1500] flex h-[100%] w-[375px] translate-x-[-50%] items-center justify-center bg-[rgba(0,0,0,0.4)]'>
<div
ref={modalRef}
className='flex h-auto min-h-[500px] w-[330px] flex-col gap-4 rounded-lg bg-[rgba(255,255,255,0.98)] px-8 py-10 text-center'
>
<button
type='button'
className='-mt-4 flex w-full justify-end'
onClick={onClose}
>
<AiOutlineClose size={20} />
</button>
<p className='font-medium'>개인정보 수집/이용 동의</p>
<p className='text-sm'>
(주)룸잇(ROOM:IT)은 아래의 목적으로 개인정보를 수집 및 이용하며,
회원의 개인정보를 안전하게 처리하는데 최선을 다하고 있습니다. 아래의
내용을 확인 후 동의하여 주시기 바랍니다.
</p>
<table className='w-full table-auto border-collapse border border-focusColor text-left text-sm'>
<thead className='bg-subfont text-xs'>
<tr>
<th className='border border-focusColor px-2 py-2 text-center align-middle'>
수집 목적
</th>
<th className='border border-focusColor px-2 py-2 text-center align-middle'>
필수 항목
</th>
<th className='border border-focusColor px-2 py-2 text-center align-middle'>
보유 및 이용기간
</th>
</tr>
</thead>
<tbody className='text-xs'>
<tr>
<td className='border border-focusColor px-2 py-2'>
사업자와 사용자의 거래의 원활한 진행
</td>
<td className='border border-focusColor px-2 py-2'>
주문자 정보 (성함)
<br />
<br />
휴대폰 정보 (전화번호)
<br />
<br />
예약 및 결제 내역
</td>
<td className='border border-focusColor px-2 py-2'>
탈퇴 요청 시 지체 없이 파기
<br />
<br />
단, 관련 법령에 따른 보관 의무가 있는 경우에 그 기간동안 보관
</td>
</tr>
</tbody>
</table>
<p className='text-sm'>
필수적인 개인정보 수집 및 이용에 동의하지 않을 권리가 있습니다. 다만,
동의하지 않을 경우 거래가 제한됩니다.
</p>
</div>
</div>
);
};

export default CollectionModal;
92 changes: 92 additions & 0 deletions src/pages/PaymentPage/components/OfferModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { useEffect, useRef } from 'react';
import { AiOutlineClose } from 'react-icons/ai';

interface OfferModalProps {
onClose: () => void;
workplaceName: string;
}

const OfferModal = (props: OfferModalProps) => {
const { onClose, workplaceName } = props;

const modalRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const handleOutsideClose = (e: { target: unknown }) => {
if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
onClose();
}
};
document.addEventListener('mousedown', handleOutsideClose);

return () => document.removeEventListener('mousedown', handleOutsideClose);
}, [onClose]);

return (
<div className='fixed left-[50%] top-0 z-[1500] flex h-[100%] w-[375px] translate-x-[-50%] items-center justify-center bg-[rgba(0,0,0,0.4)]'>
<div
ref={modalRef}
className='flex h-auto min-h-[500px] w-[330px] flex-col gap-4 rounded-lg bg-[rgba(255,255,255,0.98)] px-8 py-10 text-center'
>
<button
type='button'
className='-mt-4 flex w-full justify-end'
onClick={onClose}
>
<AiOutlineClose size={20} />
</button>
<p className='font-medium'>개인정보 제3자 제공 동의</p>
<p className='text-sm'>
(주)룸잇(ROOM:IT)은 사업자 회원과 예약 이용자의 원활한 거래 진행을
위해 판매자에게 아래와 같이 개인정보를 제공하고 있습니다. 아래의
내용을 확인 후 동의하여 주시기 바랍니다.
</p>
<table className='w-full table-auto border-collapse border border-focusColor text-left text-sm'>
<tbody>
<tr>
<th className='w-1/3 border border-focusColor bg-subfont px-2 py-2 text-center align-middle'>
제공받는 자
</th>
<td className='border border-focusColor px-2 py-2'>
{workplaceName}
</td>
</tr>
<tr>
<th className='border border-focusColor bg-subfont px-2 py-2 text-center align-middle'>
제공 목적
</th>
<td className='border border-focusColor px-2 py-2'>
예약 서비스 제공, 서비스 분석과 통계에 따른 맞춤 서비스 제공,
고객 상담 및 관리
</td>
</tr>
<tr>
<th className='border border-focusColor bg-subfont px-2 py-2 text-center align-middle'>
제공 항목
</th>
<td className='border border-focusColor px-2 py-2'>
성명, 휴대폰 번호
</td>
</tr>
<tr>
<th className='border border-focusColor bg-subfont px-2 py-2 text-center align-middle'>
보유 및 이용기간
</th>
<td className='border border-focusColor px-2 py-2'>
탈퇴 시 또는 위 개인 정보 이용목적 달성 시까지 이용
<br />
<br />
단, 관련 법령에 따른 보관의무가 있는 경우에 그 기간동안 보관
</td>
</tr>
</tbody>
</table>
<p className='text-sm'>
필수적인 개인정보 제3자 제공에 동의하지 않을 권리가 있습니다. 다만,
동의하지 않을 경우 거래가 제한됩니다.
</p>
</div>
</div>
);
};

export default OfferModal;
14 changes: 13 additions & 1 deletion src/pages/PaymentPage/components/PaymentAgree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ interface PaymentAgreeProps {
const PaymentAgree = (props: PaymentAgreeProps) => {
const { checkState, onSetCheckState, errorMessage } = props;

const handlePrivacyPolicyClick = () => {
window.location.href = 'https://pages.tosspayments.com/terms/privacy';
};

const handleCheckItem = (checked: boolean, id: string) => {
if (checked) {
onSetCheckState({
Expand All @@ -36,7 +40,15 @@ const PaymentAgree = (props: PaymentAgreeProps) => {
isCheck={isChecked('payment1')}
description='결제 서비스 이용 약관'
onChangeChecked={handleCheckItem}
/>
>
<button
type='button'
className='text-subfont underline'
onClick={handlePrivacyPolicyClick}
>
보기
</button>
</CheckAgree>
<CheckAgree
checkId='payment2'
isCheck={isChecked('payment2')}
Expand Down
4 changes: 2 additions & 2 deletions src/pages/PaymentPage/components/PaymentRoomCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface PaymentRoomCardProps {

const PaymentRoomCard = (props: PaymentRoomCardProps) => {
const { studyRoomInfo } = props;
const { workplaceName, studyRoomTitle } = studyRoomInfo;
const { workplaceName, studyRoomTitle, studyRoomImage } = studyRoomInfo;
const { searchDate, formattedTime, searchPeople } = useSearchStore();

const formattedDate = getFormattedDateFunction(searchDate);
Expand All @@ -19,7 +19,7 @@ const PaymentRoomCard = (props: PaymentRoomCardProps) => {
<DetailTitle title='룸 상세 정보' />
<div className='flex h-[120px] w-custom items-center justify-center gap-[18px] rounded-[10px] shadow-custom'>
<img
src='https://modo-phinf.pstatic.net/20180304_61/1520159998510ED9Yt_JPEG/mosaSDaCsR.jpeg?type=w1100'
src={studyRoomImage}
className='h-[94px] w-[94px] object-cover'
alt='결제 스터디룸 사진'
/>
Expand Down
46 changes: 40 additions & 6 deletions src/pages/PaymentPage/components/ReservationGuide.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import CheckAgree from '@components/CheckAgree';
import DetailTitle from '@components/DetailTitle';
import { useCallback, useState } from 'react';
import type { CheckState, ErrorMessageType } from '..';
import CollectionModal from './CollectionModal';
import OfferModal from './OfferModal';

interface ReservationGuideProps {
checkState: CheckState;
onSetCheckState: (value: CheckState) => void;
errorMessage: ErrorMessageType;
workplaceName: string;
}

const ReservationGuide = (props: ReservationGuideProps) => {
const { checkState, onSetCheckState, errorMessage } = props;
const { checkState, onSetCheckState, errorMessage, workplaceName } = props;

const [isCollectionModalOpen, setIsCollectionModalOpen] =
useState<boolean>(false);
const [isOfferModalOpen, setIsOfferModalOpen] = useState<boolean>(false);

const handleCheckItem = (checked: boolean, id: string) => {
if (checked) {
Expand All @@ -25,6 +33,11 @@ const ReservationGuide = (props: ReservationGuideProps) => {
}
};

const handleCloseModal = useCallback(() => {
setIsCollectionModalOpen(false);
setIsOfferModalOpen(false);
}, []);

const isChecked = (id: string) => checkState.reservation.includes(id);

return (
Expand All @@ -34,17 +47,31 @@ const ReservationGuide = (props: ReservationGuideProps) => {
<CheckAgree
checkId='reservation1'
isCheck={isChecked('reservation1')}
description='개인정보 수집/이용
동의'
description='개인정보 수집/이용 동의'
onChangeChecked={handleCheckItem}
/>
>
<button
type='button'
className='text-subfont underline'
onClick={() => setIsCollectionModalOpen(true)}
>
보기
</button>
</CheckAgree>
<CheckAgree
checkId='reservation2'
isCheck={isChecked('reservation2')}
description='개인정보 제3자 제공 동의'
onChangeChecked={handleCheckItem}
/>

>
<button
type='button'
className='text-subfont underline'
onClick={() => setIsOfferModalOpen(true)}
>
보기
</button>
</CheckAgree>
<CheckAgree
checkId='reservation3'
isCheck={isChecked('reservation3')}
Expand All @@ -57,6 +84,13 @@ const ReservationGuide = (props: ReservationGuideProps) => {
{errorMessage.reservationCheckError}
</div>
)}
{isCollectionModalOpen && <CollectionModal onClose={handleCloseModal} />}
{isOfferModalOpen && (
<OfferModal
onClose={handleCloseModal}
workplaceName={workplaceName}
/>
)}
</div>
);
};
Expand Down
2 changes: 2 additions & 0 deletions src/pages/PaymentPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface StudyRoomInfo {
workplaceName: string;
studyRoomTitle: string;
studyRoomPrice: number;
studyRoomImage: string;
}

export interface ReservationFormData {
Expand Down Expand Up @@ -80,6 +81,7 @@ const PaymentPage = () => {
checkState={checkState}
onSetCheckState={setCheckState}
errorMessage={errorMessage}
workplaceName={studyRoomInfo.workplaceName}
/>
<ReservationPrice
studyRoomInfo={studyRoomInfo}
Expand Down
3 changes: 3 additions & 0 deletions src/pages/ReservationPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const ReservationPage = () => {
workplaceName: data.workplaceName,
studyRoomTitle: data.studyRoomName,
studyRoomPrice: data.price,
studyRoomImage: Array.isArray(data.imageUrl)
? data.imageUrl[0]
: data.imageUrl,
};

const handleClickReservation = () => {
Expand Down
11 changes: 8 additions & 3 deletions src/pages/SearchPage/components/PlaceSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ const PlaceSearch = () => {
const location = useLocation();
const isBack = location.state || false;

if (isBack) {
isClickRef.current = isBack;
}
useEffect(() => {
if (isBack) {
isClickRef.current = isBack;
} else {
setPlace('');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isBack]);

const handleSearchPlace = useCallback(() => {
if (!searchPlace) return;
Expand Down
12 changes: 12 additions & 0 deletions src/pages/SearchPage/components/SelectDate/SelectDate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Calendar from 'react-calendar';
import './SelectDate.css';
import moment from 'moment';
import useSearchStore from '@store/searchStore';
import { useLocation } from 'react-router-dom';
import { useEffect } from 'react';

type DatePiece = Date | null;

Expand All @@ -12,6 +14,16 @@ const SelectDate = () => {
const maxDate = new Date();
maxDate.setMonth(maxDate.getMonth() + 3);

const location = useLocation();
const isBack = location.state || false;

useEffect(() => {
if (!isBack) {
setDate(new Date());
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isBack]);

const handleChangeDate = (newDate: SelectedDate) => {
if (newDate instanceof Date) {
setDate(new Date(newDate));
Expand Down
Loading

0 comments on commit 49b8f66

Please sign in to comment.