Skip to content

Commit

Permalink
Merge pull request #45 from wafflestudio/feat/wishlist
Browse files Browse the repository at this point in the history
Feat/wishlist: api 연결
  • Loading branch information
SeohyunLilyChoi authored Jan 18, 2025
2 parents 78336f9 + 0f6729b commit a026d20
Show file tree
Hide file tree
Showing 13 changed files with 608 additions and 210 deletions.
8 changes: 4 additions & 4 deletions src/components/common/constants/icons/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { default as WifiIcon } from '@/assets/icons/amenities/wifi.svg';
export { default as CheckinIcon } from '@/assets/icons/amenities/checkin.svg';
export { default as LuggageIcon } from '@/assets/icons/amenities/luggage.svg';
export { default as TvIcon } from '@/assets/icons/amenities/tv.svg';
export { default as WifiIcon } from '@/assets/icons/roomdetail/wifi.svg';
export { default as CheckinIcon } from '@/assets/icons/roomdetail/checkin.svg';
export { default as LuggageIcon } from '@/assets/icons/roomdetail/luggage.svg';
export { default as TvIcon } from '@/assets/icons/roomdetail/tv.svg';
8 changes: 7 additions & 1 deletion src/components/home/context/SearchContext.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import type { ReactNode } from 'react';
import { createContext, useContext, useState } from 'react';

type ModalType = 'location' | 'calendar' | 'guests' | null;
type ModalType =
| 'location'
| 'calendar'
| 'guests'
| 'roomCalendar'
| 'roomGuests'
| null;

type Location = {
sido: string;
Expand Down
23 changes: 10 additions & 13 deletions src/components/roomdetail/HeartModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,34 @@ const ShareModal = ({ onClose }: HeartModalProps) => {
></div>

{/* 모달 내용 */}
<div className="relative bg-white rounded-lg shadow-lg w-[40%] z-60 overflow-y-auto h-[80%]">
<div className="grid grid-cols-3 items-center w-full border-b p-2">
<div className="relative bg-white rounded-lg shadow-lg w-[40%] z-60 h-[80%] overflow-y-auto">
<div className="sticky top-0 bg-white flex items-center w-full border-b p-2">
<button
onClick={onClose}
className="text-left ml-2 text-3xl text-black"
>
&times;
</button>
<div className="text-lg text-center font-bold">
<div className="text-base flex-1 text-center font-bold">
위시리스트에 저장하기
</div>
<div></div>
</div>
<div className="grid grid-cols-2 w-full">
<div className="grid grid-cols-2 gap-2 px-2">
{mockHeart.map((list) => (
<div
className="w-full flex flex-col items-start m-4"
key={list.name}
>
<PhotoSizeSelectActualIcon className="text-white bg-gray-300 w-full h-[200px] rounded-md" />
<p className="mt-2 text-lg font-bold">{list.name}</p>
<p className="text-gray-500">
<div className="flex flex-col items-start p-2" key={list.name}>
<PhotoSizeSelectActualIcon className="text-white bg-gray-300 w-full h-[200px] rounded-md shadow-md" />
<p className="mt-2 text-base font-bold">{list.name}</p>
<p className="text-gray-500 text-sm">
저장된 항목&nbsp;{list.itemsCount}
</p>
</div>
))}
</div>

{/* "새로운 위시리스트 만들기" 버튼, 위치 고정 */}
<div className="absolute bottom-4 left-0 right-0 text-center">
<button className="w-full bg-blue-500 text-white p-2 rounded-md">
<div className="sticky bottom-0 text-center bg-white border-t w-full">
<button className="w-full bg-gray-900 text-white text-base p-2 rounded-md m-3">
새로운 위시리스트 만들기
</button>
</div>
Expand Down
38 changes: 12 additions & 26 deletions src/components/roomdetail/Info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import PhotoSizeSelectActualIcon from '@mui/icons-material/PhotoSizeSelectActual
import StarIcon from '@mui/icons-material/Star';
import { useState } from 'react';

import crownleft from '@/assets/icons/roomdetail/crownleft.svg';
import crownright from '@/assets/icons/roomdetail/crownright.svg';
import superhost from '@/assets/icons/superhost.svg';
import { ACCOMMODATION_TYPES } from '@/components/common/constants/accommodationTypes';
import crownleft from '@/components/roomdetail/crownleft.svg';
import crownright from '@/components/roomdetail/crownright.svg';
import ReviewModal from '@/components/roomdetail/ReviewModal';
import superhost from '@/components/roomdetail/superhost.svg';
import type { roomType } from '@/types/roomType';

import {
Expand All @@ -22,7 +22,7 @@ interface InfoProps {

const Info = ({ data }: InfoProps) => {
const matchingItem = ACCOMMODATION_TYPES.find(
(item) => item.type === data.type,
(item) => item.type === data.roomType,
);
const issuperhost = data.isSuperhost;
const isluggage = data.roomDetails.luggage;
Expand Down Expand Up @@ -53,7 +53,7 @@ const Info = ({ data }: InfoProps) => {
<img src={crownright} className="basis-1/10" />
</div>
<div className="flex flex-col flex-1 items-center border-r border-r-gray-300">
<div>{data.rating}</div>
<div>{data.averageRating}</div>
<div className="flex">
<StarIcon className="" style={{ width: '10px', height: '10px' }} />
<StarIcon className="" style={{ width: '10px', height: '10px' }} />
Expand Down Expand Up @@ -81,7 +81,7 @@ const Info = ({ data }: InfoProps) => {
<img
src={matchingItem.imageUrl}
alt={matchingItem.label}
className="h-6 w-6 opacity-60 hover:opacity-100 transition-opacity"
className="h-6 w-6 opacity-60"
/>
<div className="opacity-60 text-sm">{matchingItem.label}</div>
</>
Expand All @@ -93,44 +93,29 @@ const Info = ({ data }: InfoProps) => {
)}
</div>
<div className="col-span-1 row-span-1 flex gap-2 items-center px-4">
<img
src={superhost}
className="h-6 w-6 opacity-60 hover:opacity-100 transition-opacity"
/>
<img src={superhost} className="h-6 w-6 opacity-60" />
<div className="opacity-60 text-sm">
{issuperhost ? '슈퍼호스트' : '훌륭한 호스트'}
</div>
</div>
<div className="col-span-1 row-span-1 flex gap-2 items-center px-4">
<img
src={LuggageIcon}
className="h-6 w-6 opacity-60 hover:opacity-100 transition-opacity"
/>
<img src={LuggageIcon} className="h-6 w-6 opacity-60" />
<div className="opacity-60 text-sm">
{isluggage ? '여행 가방 보관 가능' : '여행 가방 보관 풀가'}
</div>
</div>
<div className="col-span-1 row-span-1 flex gap-2 items-center px-4">
<img
src={CheckinIcon}
className="h-6 w-6 opacity-60 hover:opacity-100 transition-opacity"
/>
<img src={CheckinIcon} className="h-6 w-6 opacity-60" />
<div className="opacity-60 text-sm">
{ischeckin ? '셀프체크인' : '편의성이 뛰어난 체크인 절차'}
</div>
</div>
<div className="col-span-1 row-span-1 flex gap-2 items-center px-4">
<img
src={TvIcon}
className="h-6 w-6 opacity-60 hover:opacity-100 transition-opacity"
/>
<img src={TvIcon} className="h-6 w-6 opacity-60" />
<div className="opacity-60 text-sm">{istv ? 'TV' : 'TV 없음'}</div>
</div>
<div className="col-span-1 row-span-1 flex gap-2 items-center px-4">
<img
src={WifiIcon}
className="h-6 w-6 opacity-60 hover:opacity-100 transition-opacity"
/>
<img src={WifiIcon} className="h-6 w-6 opacity-60" />
<div className="opacity-60 text-sm">
{iswifi ? '와이파이' : '와이파이 없음'}
</div>
Expand All @@ -150,6 +135,7 @@ const Info = ({ data }: InfoProps) => {
<div className="w-full h-fit text-wrap px-4 py-8">{data.description}</div>
{isReviewOpen && (
<ReviewModal
data={data}
onClose={() => {
setIsReviewOpen(false);
}}
Expand Down
56 changes: 33 additions & 23 deletions src/components/roomdetail/Reservation.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import ErrorIcon from '@mui/icons-material/Error';
import FlagIcon from '@mui/icons-material/Flag';
import { useState } from 'react';

import clock from '@/assets/icons/reservation/clock.svg';
import BaseModal from '@/components/common/Modal/BaseModal';
import { useSearch } from '@/components/home/context/SearchContext';
import CalendarModal from '@/components/home/Topbar/Search/modals/CalendarModal';
import GuestsModal from '@/components/home/Topbar/Search/modals/GuestsModal';
import clock from '@/components/roomdetail/clock.svg';
import type { roomReservationType } from '@/types/roomReservationType';
import RoomGuestsModal from '@/components/roomdetail/RoomGuestsModal';
import type { roomType } from '@/types/roomType';

import RoomCalendarModal from './roomCalendarModal';

interface InfoProps {
data: roomType;
}

type roomReservationResponseType = {
reservationId: number;
};

const Reservation = ({ data }: InfoProps) => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
Expand All @@ -29,13 +32,18 @@ const Reservation = ({ data }: InfoProps) => {
if (token == null) {
throw new Error('로그인이 필요합니다.');
}

if (data.id === 0 || checkIn == null || checkOut == null || guests <= 0) {
console.debug(data);
if (
data.roomId === 0 ||
checkIn == null ||
checkOut == null ||
guests <= 0
) {
throw new Error('모든 필드를 입력해주세요.');
}

const sendData = {
roomId: data.id,
roomId: data.roomId,
startDate: checkIn.toISOString().split('T')[0],
endDate: checkOut.toISOString().split('T')[0],
numberOfGuests: guests,
Expand All @@ -53,10 +61,13 @@ const Reservation = ({ data }: InfoProps) => {
console.debug(sendData);

if (!response.ok) {
throw new Error('숙소 등록에 실패했습니다.');
throw new Error('숙소 예약에 실패했습니다.');
}
const responseData = (await response.json()) as roomReservationType;
alert(`숙소가 성공적으로 등록되었습니다! ID: ${responseData.roomId}`);
const responseData =
(await response.json()) as roomReservationResponseType;
alert(
`숙소가 성공적으로 예약되었습니다! ID: ${responseData.reservationId}`,
);
} catch (err) {
const errorMessage =
err instanceof Error ? err.message : '오류가 발생했습니다.';
Expand All @@ -75,7 +86,7 @@ const Reservation = ({ data }: InfoProps) => {
<div className="w-full">
<button
onClick={() => {
openModal('calendar');
openModal('roomCalendar');
}}
className="flex flex-col items-start mt-1 w-full border border-red-700 rounded-md py-2 px-3 text-gray-700 bg-white cursor-pointer"
>
Expand All @@ -90,7 +101,7 @@ const Reservation = ({ data }: InfoProps) => {
<div className="w-full">
<button
onClick={() => {
openModal('calendar');
openModal('roomCalendar');
}}
className="flex flex-col items-start mt-1 w-full border border-red-700 rounded-md py-2 px-3 text-gray-700 bg-white cursor-pointer"
>
Expand All @@ -108,7 +119,7 @@ const Reservation = ({ data }: InfoProps) => {
<div className="my-4 w-full">
<button
onClick={() => {
openModal('guests');
openModal('roomGuests');
}}
className="flex flex-col items-start mt-1 w-full border border-gray-300 rounded-md py-2 px-3 bg-white cursor-pointer text-gray-700"
>
Expand All @@ -120,14 +131,10 @@ const Reservation = ({ data }: InfoProps) => {
</span>
</button>
</div>
<div className="flex items-center text-red-600 text-xs mb-4">
<ErrorIcon className="mr-2" />
선택하신 날짜는 이용이 불가능합니다.
</div>

{/* 에러 메시지 표시 */}
{error != null && (
<div className="mb-4 p-4 bg-red-50 text-red-600 rounded-lg">
<div className="mb-4 p-2 bg-red-50 text-red-700 rounded-sm text-sm">
{error}
</div>
)}
Expand Down Expand Up @@ -167,18 +174,21 @@ const Reservation = ({ data }: InfoProps) => {
</button>
</div>
<BaseModal
isOpen={currentModal === 'calendar'}
isOpen={currentModal === 'roomCalendar'}
onClose={closeModal}
title="날짜 선택"
>
<CalendarModal onClose={closeModal} />
<RoomCalendarModal id={data.roomId} onClose={closeModal} />
</BaseModal>
<BaseModal
isOpen={currentModal === 'guests'}
isOpen={currentModal === 'roomGuests'}
onClose={closeModal}
title="인원 선택"
>
<GuestsModal onClose={closeModal} />
<RoomGuestsModal
maxOccupancy={data.maxOccupancy}
onClose={closeModal}
/>
</BaseModal>
</>
);
Expand Down
Loading

0 comments on commit a026d20

Please sign in to comment.