From 4e993d90a4325b15a6fe5b8c4009e029a7bda631 Mon Sep 17 00:00:00 2001 From: hayoung123 <67357426+hayoung123@users.noreply.github.com> Date: Tue, 1 Jun 2021 18:31:38 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[#44]=EC=98=88=EC=95=BD=20=ED=8F=BC=20check?= =?UTF-8?q?in,out=20=EA=B5=AC=ED=98=84=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reserveForm/ReserveForm.tsx | 29 +++++++++- .../reserveForm/ReserveFormHeader.tsx | 39 ++++++++++++++ .../reserveForm/ReserveFormInfo.tsx | 53 +++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormHeader.tsx create mode 100644 FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormInfo.tsx diff --git a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx index 96804639b..c837076e5 100644 --- a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx +++ b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx @@ -1,13 +1,35 @@ +import { useRecoilValue } from 'recoil'; import styled from 'styled-components'; +import { selectDateState } from '../../../recoil/calendarAtom'; +import { getBetweenDays } from '../../header/form/calendar/calendarDateFn'; import { roomType } from '../roomType'; +import ReserveFormHeader from './ReserveFormHeader'; +import ReserveFormInfo from './ReserveFormInfo'; interface Props { roomData: roomType; } const ReserveForm = ({ roomData }: Props) => { + const selectDate = useRecoilValue(selectDateState); + const { chargePerNight } = roomData; + + const getCleanCharge = (totalPrice: number): number => Math.floor(totalPrice * 0.03); + const getServiceCharge = (totalPrice: number): number => Math.floor(totalPrice * 0.15); + const getTaxCharge = (totalPrice: number): number => Math.floor(totalPrice * 0.01); + + const betweenDays = getBetweenDays(selectDate.checkIn, selectDate.checkOut); + const totalPrice = chargePerNight * betweenDays; + + const cleanCharge = getCleanCharge(totalPrice); + const serviceCharge = getServiceCharge(totalPrice); + const taxCharge = getTaxCharge(totalPrice); + return ( - 123; + + + + ); }; @@ -23,7 +45,10 @@ const StyledReserveFormWrapper = styled.div` `; const StyledReserveForm = styled.div` + padding: 24px; width: 400px; height: 500px; - background-color: green; + background-color: ${({ theme }) => theme.colors.white}; + border-radius: 10px; + box-shadow: 0px 4px 10px rgba(51, 51, 51, 0.1), 0px 0px 4px rgba(51, 51, 51, 0.05); `; diff --git a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormHeader.tsx b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormHeader.tsx new file mode 100644 index 000000000..b029f5aff --- /dev/null +++ b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormHeader.tsx @@ -0,0 +1,39 @@ +import styled from 'styled-components'; + +interface Props { + className?: string; + chargePerNight: number; + review: number; +} + +const ReserveFormHeader = ({ className, chargePerNight, review }: Props) => { + return ( + +
+ ₩{chargePerNight.toLocaleString()} + / 박 +
+
+ 후기 {review}개 +
+
+ ); +}; + +export default ReserveFormHeader; + +const StyledReserveFormHeader = styled.div` + display: flex; + align-items: flex-end; + justify-content: space-between; + + .price { + font-size: ${({ theme }) => theme.fontSize.large}; + font-weight: bold; + } + .review { + font-size: ${({ theme }) => theme.fontSize.small}; + color: ${({ theme }) => theme.colors.gray3}; + text-decoration: underline; + } +`; diff --git a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormInfo.tsx b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormInfo.tsx new file mode 100644 index 000000000..586693427 --- /dev/null +++ b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormInfo.tsx @@ -0,0 +1,53 @@ +import { useRecoilValue } from 'recoil'; +import styled from 'styled-components'; +import { selectDateState } from '../../../recoil/calendarAtom'; +import { guestState } from '../../../recoil/headerAtom'; +import { getDateByTime } from '../../header/form/calendar/calendarDateFn'; + +interface Props {} + +const ReserveFormInfo = (props: Props) => { + const selectDate = useRecoilValue(selectDateState); + const guestDate = useRecoilValue(guestState); + + const timeToReserveFormdate = (time: number | null): string => { + const date = getDateByTime(time); + if (!date) return ''; + return `${date.year}. ${date.month}. ${date.day}.`; + }; + + const checkInDate = timeToReserveFormdate(selectDate.checkIn); + const checkOutDate = timeToReserveFormdate(selectDate.checkOut); + const totalGuest = Object.values(guestDate).reduce((acc, cur) => acc + cur); + + return ( + +
+
+
체크인
+
{checkInDate}
+
+
+
체크아웃
+
{checkOutDate}
+
+
+
+
인원
+
게스트 {totalGuest}명
+
+
+ ); +}; + +export default ReserveFormInfo; + +const StyledReserveFormInfo = styled.div` + .reserve-form__date, + .reserve-form__column { + padding: 1rem; + } + .reserve-form__column:first-child { + display: flex; + } +`; From d4ddc9afe3e4b30f1bfae0855467e598ab12f1dc Mon Sep 17 00:00:00 2001 From: hayoung123 <67357426+hayoung123@users.noreply.github.com> Date: Wed, 2 Jun 2021 01:55:42 +0900 Subject: [PATCH 2/5] =?UTF-8?q?[#42]=20=EC=B0=A8=ED=8A=B8=20fetch=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/header/form/FormPrice.tsx | 8 ++++++-- .../header/form/priceBar/PriceBar.tsx | 5 ++++- .../header/form/priceBar/PriceChart.tsx | 6 ++---- FE/airbnb/src/recoil/headerAtom.ts | 17 +++++++++++++++++ FE/airbnb/src/util/api.ts | 13 +++++++++++++ 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/FE/airbnb/src/components/header/form/FormPrice.tsx b/FE/airbnb/src/components/header/form/FormPrice.tsx index ebfa21998..8e340d357 100644 --- a/FE/airbnb/src/components/header/form/FormPrice.tsx +++ b/FE/airbnb/src/components/header/form/FormPrice.tsx @@ -1,4 +1,4 @@ -import { MouseEvent, useEffect, useRef } from 'react'; +import { MouseEvent, Suspense, useEffect, useRef } from 'react'; import { useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'; import styled from 'styled-components'; import useToggle from '../../../hooks/useToggle'; @@ -54,7 +54,11 @@ const FormPrice = () => { {isShowDeleteBtn && open && } - {open && } + {open && ( + + + + )} ); }; diff --git a/FE/airbnb/src/components/header/form/priceBar/PriceBar.tsx b/FE/airbnb/src/components/header/form/priceBar/PriceBar.tsx index 2b25326b7..ab1b307a0 100644 --- a/FE/airbnb/src/components/header/form/priceBar/PriceBar.tsx +++ b/FE/airbnb/src/components/header/form/priceBar/PriceBar.tsx @@ -5,8 +5,9 @@ import PriceChart from './PriceChart'; import { btnPositionType, priceSectionType } from './priceType'; import { ReactComponent as PauseBtn } from '../../../../assets/svg/Property 1=pause-circle.svg'; import { priceData as sampleData } from './sampleData'; -import { useRecoilState } from 'recoil'; +import { useRecoilState, useRecoilValue } from 'recoil'; import { + fetchPrice, pauseBtnLastPositionState, pauseBtnPositionState, priceState, @@ -32,7 +33,9 @@ const PriceBar = ({ toggleRef }: Props) => { const [btnLastPosition, setBtnLastPosition] = useRecoilState(pauseBtnLastPositionState); const [priceRange, setPriceRange] = useRecoilState(priceState); const [priceData, setPriceData] = useState(sampleData); + // const priceData = useRecoilValue(fetchPrice); + console.log(priceData); const minPrice = getNumberWithComma(priceRange.min); const maxPrice = getNumberWithComma(priceRange.max); const priceAverage = getNumberWithComma(getPriceAverage(priceData)); diff --git a/FE/airbnb/src/components/header/form/priceBar/PriceChart.tsx b/FE/airbnb/src/components/header/form/priceBar/PriceChart.tsx index d4f5d8dda..3004d4359 100644 --- a/FE/airbnb/src/components/header/form/priceBar/PriceChart.tsx +++ b/FE/airbnb/src/components/header/form/priceBar/PriceChart.tsx @@ -34,8 +34,6 @@ const PriceChart = ({ priceSection }: Props) => { const drawDotsLine = (dots: dotType[]): void => { if (!canvas || !ctx) return; - const canvasWidth = canvas.width; - const canvasHeight = canvas.height; ctx.beginPath(); ctx.fillStyle = 'rgba(0,0,0,0.7)'; @@ -53,9 +51,9 @@ const PriceChart = ({ priceSection }: Props) => { } ctx.lineTo(prevX, prevY); - ctx.lineTo(canvasWidth, canvasHeight); - ctx.lineTo(0, canvasHeight); ctx.fill(); + ctx.strokeStyle = 'rgba(0,0,0,0.3)'; + ctx.stroke(); ctx.closePath(); }; diff --git a/FE/airbnb/src/recoil/headerAtom.ts b/FE/airbnb/src/recoil/headerAtom.ts index a5c11d261..b5021cda0 100644 --- a/FE/airbnb/src/recoil/headerAtom.ts +++ b/FE/airbnb/src/recoil/headerAtom.ts @@ -1,5 +1,7 @@ import { atom, selector } from 'recoil'; +import { timeToDate } from '../components/header/form/calendar/calendarDateFn'; import { guestStateType } from '../components/header/form/guestToggle/guestType'; +import { serverAPI } from '../util/api'; import { selectDateState } from './calendarAtom'; export const tabSelectedState = atom({ @@ -61,6 +63,21 @@ export interface reserveQueryType { guests: guestStateType; } +export const fetchPrice = selector({ + key: 'get/price', + get: async ({ get }) => { + const city = get(locationState); + const date = get(selectDateState); + if (!city || !date.checkIn || !date.checkOut) + return '도시, 체크인, 체크아웃 날짜를 입력해주세요'; + const checkIn = date.checkIn; + const checkOut = date.checkOut; + const response = await fetch(serverAPI.getPrice({ city, checkIn, checkOut })); + const data = await response.json(); + return data.data.charges; + }, +}); + export const reserveInfoSelector = selector({ key: 'reserveInformation', get: ({ get }): reserveQueryType => { diff --git a/FE/airbnb/src/util/api.ts b/FE/airbnb/src/util/api.ts index bb00ced6b..f875b91e9 100644 --- a/FE/airbnb/src/util/api.ts +++ b/FE/airbnb/src/util/api.ts @@ -9,6 +9,11 @@ export interface reserveInfoType { maxCharge: number; guests: guestStateType; } +interface priceArgType { + city: string; + checkIn: number; + checkOut: number; +} interface apiType { url: string; @@ -20,7 +25,9 @@ interface apiType { maxCharge, guests, }: reserveInfoType) => string; + getPrice: ({ city, checkIn, checkOut }: priceArgType) => string; } + export const serverAPI: apiType = { url: 'http://13.125.35.62', getRooms: ({ address, checkIn, checkOut, minCharge, maxCharge, guests }) => { @@ -30,6 +37,12 @@ export const serverAPI: apiType = { const query = `city=${address}&check_in=${checkInDate}&check_out=${checkOutDate}&min_charge=${minCharge}&max_charge=${maxCharge}&guests=${guestNumber}`; return serverAPI.url + '/accommodations?' + query; }, + getPrice: ({ city, checkIn, checkOut }) => { + const checkInDate = timeToDate(checkIn); + const checkOutDate = timeToDate(checkOut); + const query = `city=${city}&check_in=${checkInDate}&check_out=${checkOutDate}`; + return serverAPI.url + '/accommodations/charges?' + query; + }, }; export const clientReserveAPI = ({ From 40721e1bf6d9499102e323d3356d38f89ffcfd4a Mon Sep 17 00:00:00 2001 From: hayoung123 <67357426+hayoung123@users.noreply.github.com> Date: Wed, 2 Jun 2021 12:59:03 +0900 Subject: [PATCH 3/5] =?UTF-8?q?[#44]=20=EC=98=88=EC=95=BD=20=ED=8F=BC=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reserveForm/ReserveBtn.tsx | 24 +++++ .../reserveForm/ReserveForm.tsx | 45 ++++++---- .../reserveForm/ReserveFormInfo.tsx | 44 +++++++--- .../reserveForm/ReserveFromPrice.tsx | 87 +++++++++++++++++++ 4 files changed, 171 insertions(+), 29 deletions(-) create mode 100644 FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveBtn.tsx create mode 100644 FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFromPrice.tsx diff --git a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveBtn.tsx b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveBtn.tsx new file mode 100644 index 000000000..a0e8d4481 --- /dev/null +++ b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveBtn.tsx @@ -0,0 +1,24 @@ +import styled from 'styled-components'; + +interface Props { + className: string; +} + +const ReserveBtn = ({ className }: Props) => { + return 예약하기; +}; + +export default ReserveBtn; + +const StyledReserveBtn = styled.button` + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 55px; + border: none; + border-radius: 10px; + background-color: ${({ theme }) => theme.colors.black}; + color: ${({ theme }) => theme.colors.white}; + font-weight: 700; +`; diff --git a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx index c837076e5..b57c66cb2 100644 --- a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx +++ b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx @@ -1,34 +1,28 @@ -import { useRecoilValue } from 'recoil'; import styled from 'styled-components'; -import { selectDateState } from '../../../recoil/calendarAtom'; -import { getBetweenDays } from '../../header/form/calendar/calendarDateFn'; import { roomType } from '../roomType'; +import ReserveBtn from './ReserveBtn'; import ReserveFormHeader from './ReserveFormHeader'; import ReserveFormInfo from './ReserveFormInfo'; +import ReserveFromPrice from './ReserveFromPrice'; interface Props { roomData: roomType; } const ReserveForm = ({ roomData }: Props) => { - const selectDate = useRecoilValue(selectDateState); const { chargePerNight } = roomData; - const getCleanCharge = (totalPrice: number): number => Math.floor(totalPrice * 0.03); - const getServiceCharge = (totalPrice: number): number => Math.floor(totalPrice * 0.15); - const getTaxCharge = (totalPrice: number): number => Math.floor(totalPrice * 0.01); - - const betweenDays = getBetweenDays(selectDate.checkIn, selectDate.checkOut); - const totalPrice = chargePerNight * betweenDays; - - const cleanCharge = getCleanCharge(totalPrice); - const serviceCharge = getServiceCharge(totalPrice); - const taxCharge = getTaxCharge(totalPrice); - return ( - - + + + +
예약 확정 전에는 요금이 청구되지 않습니다.
+
); @@ -45,10 +39,23 @@ const StyledReserveFormWrapper = styled.div` `; const StyledReserveForm = styled.div` - padding: 24px; + padding: 36px 24px; width: 400px; - height: 500px; + height: 525px; background-color: ${({ theme }) => theme.colors.white}; border-radius: 10px; box-shadow: 0px 4px 10px rgba(51, 51, 51, 0.1), 0px 0px 4px rgba(51, 51, 51, 0.05); + .reserve__header { + margin-bottom: 1.5rem; + } + .reserve__info, + .reserve__btn, + .reserve__warn { + margin-bottom: 1rem; + } + .reserve__warn { + text-align: center; + font-size: ${({ theme }) => theme.fontSize.small}; + color: ${({ theme }) => theme.colors.gray3}; + } `; diff --git a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormInfo.tsx b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormInfo.tsx index 586693427..168865e6e 100644 --- a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormInfo.tsx +++ b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFormInfo.tsx @@ -4,9 +4,11 @@ import { selectDateState } from '../../../recoil/calendarAtom'; import { guestState } from '../../../recoil/headerAtom'; import { getDateByTime } from '../../header/form/calendar/calendarDateFn'; -interface Props {} +interface Props { + className?: string; +} -const ReserveFormInfo = (props: Props) => { +const ReserveFormInfo = ({ className }: Props) => { const selectDate = useRecoilValue(selectDateState); const guestDate = useRecoilValue(guestState); @@ -21,20 +23,22 @@ const ReserveFormInfo = (props: Props) => { const totalGuest = Object.values(guestDate).reduce((acc, cur) => acc + cur); return ( - +
-
+
체크인
{checkInDate}
-
+
체크아웃
{checkOutDate}
-
인원
-
게스트 {totalGuest}명
+
+
인원
+
게스트 {totalGuest}명
+
); @@ -43,11 +47,31 @@ const ReserveFormInfo = (props: Props) => { export default ReserveFormInfo; const StyledReserveFormInfo = styled.div` - .reserve-form__date, + border-radius: 10px; .reserve-form__column { - padding: 1rem; + display: flex; + align-items: center; } + .reserve-form__item { + padding: 8px; + .reserve-form__title { + font-size: ${({ theme }) => theme.fontSize.small}; + font-weight: 700; + } + .reserve-form__info { + color: ${({ theme }) => theme.colors.gray2}; + } + } + border: ${({ theme }) => `1px solid ${theme.colors.gray4}`}; .reserve-form__column:first-child { - display: flex; + } + .reserve-form__date { + flex: 1; + } + .reserve-form__date:first-child { + border-right: ${({ theme }) => `1px solid ${theme.colors.gray4}`}; + } + .reserve-form__column:last-child { + border-top: ${({ theme }) => `1px solid ${theme.colors.gray4}`}; } `; diff --git a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFromPrice.tsx b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFromPrice.tsx new file mode 100644 index 000000000..1b354f7e5 --- /dev/null +++ b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveFromPrice.tsx @@ -0,0 +1,87 @@ +import { useRecoilValue } from 'recoil'; +import styled from 'styled-components'; +import { selectDateState } from '../../../recoil/calendarAtom'; +import { getBetweenDays } from '../../header/form/calendar/calendarDateFn'; + +interface Props { + chargePerNight: number; +} + +const ReserveFromPrice = ({ chargePerNight }: Props) => { + const selectDate = useRecoilValue(selectDateState); + + const getCleanCharge = (totalPrice: number): number => Math.floor(totalPrice * 0.03); + const getServiceCharge = (totalPrice: number): number => Math.floor(totalPrice * 0.15); + const getTaxCharge = (totalPrice: number): number => Math.floor(totalPrice * 0.01); + + const betweenDays = getBetweenDays(selectDate.checkIn, selectDate.checkOut); + const totalPrice = chargePerNight * betweenDays; + + const cleanCharge = getCleanCharge(totalPrice); + const serviceCharge = getServiceCharge(totalPrice); + const taxCharge = getTaxCharge(totalPrice); + + const totalCharge = totalPrice + cleanCharge + serviceCharge + taxCharge; + + return ( + + +
+
+ ₩{chargePerNight.toLocaleString()} x {betweenDays}박 +
+
₩{totalPrice.toLocaleString()}
+
+
+
청소비
+
₩{cleanCharge.toLocaleString()}
+
+
+
서비스 수수료
+
₩{serviceCharge.toLocaleString()}
+
+
+
숙박세와 수수료
+
₩{taxCharge.toLocaleString()}
+
+
+ +
+
총 합계
+
₩{totalCharge.toLocaleString()}
+
+
+
+ ); +}; + +export default ReserveFromPrice; + +const StyledReservePriceWrapper = styled.div` + .reserve-price__column { + display: flex; + justify-content: space-between; + margin-bottom: 8px; + } + .reserve-price__title { + text-decoration: underline; + } +`; + +const StyledReserveFormPrice = styled.div` + padding-bottom: 1rem; + border-bottom: ${({ theme }) => `2px solid ${theme.colors.gray5}`}; + margin-bottom: 1rem; +`; + +const StyledReserveCharge = styled.div` + font-weight: 700; + .reserve-price__column { + display: flex; + justify-content: space-between; + margin-bottom: 8px; + } + .reserve-price__title { + text-decoration: underline; + } +`; From fcd45796b6c85eafea54b9f37fcaca51454a0b21 Mon Sep 17 00:00:00 2001 From: hayoung123 <67357426+hayoung123@users.noreply.github.com> Date: Thu, 3 Jun 2021 00:48:49 +0900 Subject: [PATCH 4/5] =?UTF-8?q?[#42]=20map=20=EC=8A=A4=EC=BC=88=EB=A0=88?= =?UTF-8?q?=ED=86=A4=20UI=20css=20=EC=8B=9C=EB=8F=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FE/airbnb/src/App.tsx | 4 +- .../src/components/header/form/FormGuest.tsx | 2 - .../reservePageSkeleton/MapSkeleton.tsx | 38 +++++++++++++++++++ .../reservePageSkeleton/ReserveSkeleton.tsx | 25 ++++++++++++ .../reserveRoomList/ReserveRoomList.tsx | 1 + .../src/components/util/ConditionalLink.tsx | 2 +- FE/airbnb/src/pages/ReservePage.tsx | 13 ++++--- FE/airbnb/src/recoil/reserveRoomAtom.ts | 4 +- FE/airbnb/src/util/util.js | 3 ++ 9 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 FE/airbnb/src/components/reservePageSkeleton/MapSkeleton.tsx create mode 100644 FE/airbnb/src/components/reservePageSkeleton/ReserveSkeleton.tsx diff --git a/FE/airbnb/src/App.tsx b/FE/airbnb/src/App.tsx index 048beee13..8c153c63b 100644 --- a/FE/airbnb/src/App.tsx +++ b/FE/airbnb/src/App.tsx @@ -21,9 +21,7 @@ function App() { - - - + diff --git a/FE/airbnb/src/components/header/form/FormGuest.tsx b/FE/airbnb/src/components/header/form/FormGuest.tsx index 9383b3307..5100c60d4 100644 --- a/FE/airbnb/src/components/header/form/FormGuest.tsx +++ b/FE/airbnb/src/components/header/form/FormGuest.tsx @@ -8,7 +8,6 @@ import FormGuestToggle from './guestToggle/FormGuestToggle'; import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'; import { guestState, isFormOpenedState, reserveInfoSelector } from '../../../recoil/headerAtom'; import { ReactComponent as DeleteBtn } from '../../../assets/svg/Property 1=x-circle.svg'; -import { Link } from 'react-router-dom'; import ConditionalLink from '../../util/ConditionalLink'; import { reserveInfoType, clientReserveAPI } from '../../../util/api'; @@ -45,7 +44,6 @@ const FormGuest = () => { }; const handleSubmitClick = (e: MouseEvent): void => { - console.log(reserveInfo); e.stopPropagation(); }; diff --git a/FE/airbnb/src/components/reservePageSkeleton/MapSkeleton.tsx b/FE/airbnb/src/components/reservePageSkeleton/MapSkeleton.tsx new file mode 100644 index 000000000..36eac57b7 --- /dev/null +++ b/FE/airbnb/src/components/reservePageSkeleton/MapSkeleton.tsx @@ -0,0 +1,38 @@ +import styled from 'styled-components'; + +interface Props {} + +const MapSkeleton = (props: Props) => { + return loading; +}; + +export default MapSkeleton; + +const StyledMapSkeleton = styled.div` + background-color: #f2f2f2; + position: absolute; + right: 0; + width: 50%; + height: 100%; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(to right, #f2f2f2, #ddd, #f2f2f2); + animation: loading 1s infinite linear; + } + + @keyframes loading { + 0% { + transform: translateX(0); + } + 50%, + 100% { + transform: translateX(460px); + } + } +`; diff --git a/FE/airbnb/src/components/reservePageSkeleton/ReserveSkeleton.tsx b/FE/airbnb/src/components/reservePageSkeleton/ReserveSkeleton.tsx new file mode 100644 index 000000000..33e1ed333 --- /dev/null +++ b/FE/airbnb/src/components/reservePageSkeleton/ReserveSkeleton.tsx @@ -0,0 +1,25 @@ +import styled from 'styled-components'; + +interface Props {} + +const ReserveSkeleton = (props: Props) => { + return ( + +
+
+
+
+
+
+ ); +}; + +export default ReserveSkeleton; + +const StyledReserveSkeleton = styled.div` + .skeleton__img, + .skeleton__info, + .skeleton__price { + background-color: f2f2f2; + } +`; diff --git a/FE/airbnb/src/components/reserveRoomList/ReserveRoomList.tsx b/FE/airbnb/src/components/reserveRoomList/ReserveRoomList.tsx index bcef97be3..9c66cb14b 100644 --- a/FE/airbnb/src/components/reserveRoomList/ReserveRoomList.tsx +++ b/FE/airbnb/src/components/reserveRoomList/ReserveRoomList.tsx @@ -14,6 +14,7 @@ const ReserveRoomList = ({ className }: Props) => { const reserveRoomList = roomsData && roomsData.map((roomData, idx) => ); + // const reserveRoomList = roomsData && roomsData.map((roomData, idx) => ); return (
diff --git a/FE/airbnb/src/components/util/ConditionalLink.tsx b/FE/airbnb/src/components/util/ConditionalLink.tsx index 080b1cd3e..70cf17561 100644 --- a/FE/airbnb/src/components/util/ConditionalLink.tsx +++ b/FE/airbnb/src/components/util/ConditionalLink.tsx @@ -7,6 +7,6 @@ interface Props { } const ConditionalLink = ({ children, to, condition }: Props) => - !!condition && to ? {children} : <>{children}; + condition && to ? {children} : <>{children}; export default ConditionalLink; diff --git a/FE/airbnb/src/pages/ReservePage.tsx b/FE/airbnb/src/pages/ReservePage.tsx index 3cf4593f7..178ea7f0a 100644 --- a/FE/airbnb/src/pages/ReservePage.tsx +++ b/FE/airbnb/src/pages/ReservePage.tsx @@ -1,8 +1,9 @@ -import { useEffect } from 'react'; +import { Suspense, useEffect } from 'react'; import { useRecoilValue, useRecoilState } from 'recoil'; import styled from 'styled-components'; import Map from '../components/map/Map'; import ReserveHeader from '../components/reserveHeader/ReserveHeader'; +import MapSkeleton from '../components/reservePageSkeleton/MapSkeleton'; import ReserveRoomList from '../components/reserveRoomList/ReserveRoomList'; import { reserveInfoSelector } from '../recoil/headerAtom'; import { getRoomsSelector } from '../recoil/reserveRoomAtom'; @@ -11,8 +12,6 @@ interface Props {} const ReservePage = ({}: Props) => { const [reserveInfo, setReserveInfo] = useRecoilState(reserveInfoSelector); - const roomsData = useRecoilValue(getRoomsSelector); - console.log(roomsData); useEffect(() => { const [encodedAddress, checkIn, checkOut, minCharge, maxCharge, adult, child, infants] = getQueryValue(window.location.search); @@ -35,8 +34,12 @@ const ReservePage = ({}: Props) => { return ( - - + + + + }> + + ); }; diff --git a/FE/airbnb/src/recoil/reserveRoomAtom.ts b/FE/airbnb/src/recoil/reserveRoomAtom.ts index 3e47249d5..4a4c144e6 100644 --- a/FE/airbnb/src/recoil/reserveRoomAtom.ts +++ b/FE/airbnb/src/recoil/reserveRoomAtom.ts @@ -1,6 +1,7 @@ import { atom, selector } from 'recoil'; import { roomType } from '../components/reserveRoomList/roomType'; import { serverAPI } from '../util/api'; +import { delay } from '../util/util'; import { reserveInfoSelector, reserveQueryType } from './headerAtom'; import { roomData } from './roomSampleData'; @@ -20,7 +21,8 @@ export const getRoomsSelector = selector({ if (isUndefined(reserveInfo)) return null; const response = await fetch(serverAPI.getRooms(reserveInfo)); const data = await response.json(); - return data; + + return delay(1000, data); }, }); diff --git a/FE/airbnb/src/util/util.js b/FE/airbnb/src/util/util.js index d1c77545e..58cbf9575 100644 --- a/FE/airbnb/src/util/util.js +++ b/FE/airbnb/src/util/util.js @@ -14,3 +14,6 @@ export const getUrlParams = () => { return params; }; + +export const delay = (time, value = '') => + new Promise((resolve) => setTimeout(() => resolve(value), time)); From b8d0dd49a507b8559cd7c20d98149641c771be1f Mon Sep 17 00:00:00 2001 From: hayoung123 <67357426+hayoung123@users.noreply.github.com> Date: Thu, 3 Jun 2021 01:46:05 +0900 Subject: [PATCH 5/5] =?UTF-8?q?[#42]=20mordal=20=ED=8F=AC=ED=83=88=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FE/airbnb/public/index.html | 1 + .../reserveRoomList/ReserveRoom.tsx | 15 +++---- .../reserveForm/ReserveForm.tsx | 45 ++++++++++++------- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/FE/airbnb/public/index.html b/FE/airbnb/public/index.html index d16d1a6f2..0f2f85fde 100644 --- a/FE/airbnb/public/index.html +++ b/FE/airbnb/public/index.html @@ -13,5 +13,6 @@
+ diff --git a/FE/airbnb/src/components/reserveRoomList/ReserveRoom.tsx b/FE/airbnb/src/components/reserveRoomList/ReserveRoom.tsx index 6481f2db4..cd47f08bc 100644 --- a/FE/airbnb/src/components/reserveRoomList/ReserveRoom.tsx +++ b/FE/airbnb/src/components/reserveRoomList/ReserveRoom.tsx @@ -5,22 +5,21 @@ import { roomType } from './roomType'; import ReserveRoomGrade from './ReserveRoomGrade'; import ReserveRoomPrice from './ReserveRoomPrice'; import ReserveForm from './reserveForm/ReserveForm'; -import { useState } from 'react'; +import { useRef } from 'react'; +import useToggle from '../../hooks/useToggle'; interface Props { roomData: roomType; } const ReserveRoom = ({ roomData }: Props) => { - const [open, setOpen] = useState(false); const { photo } = roomData; - - const handleClick = () => { - setOpen(true); - }; + const clickRef = useRef(null); + const toggleRef = useRef(null); + const { open } = useToggle({ clickRef, toggleRef }); return ( - +
@@ -34,7 +33,7 @@ const ReserveRoom = ({ roomData }: Props) => {
- {open && } + {open && } ); }; diff --git a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx index b57c66cb2..612227160 100644 --- a/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx +++ b/FE/airbnb/src/components/reserveRoomList/reserveForm/ReserveForm.tsx @@ -1,30 +1,39 @@ +import { RefObject } from 'react'; import styled from 'styled-components'; import { roomType } from '../roomType'; import ReserveBtn from './ReserveBtn'; import ReserveFormHeader from './ReserveFormHeader'; import ReserveFormInfo from './ReserveFormInfo'; import ReserveFromPrice from './ReserveFromPrice'; +import { createPortal } from 'react-dom'; +import usePortal from '../../../hooks/usePortal'; + interface Props { + toggleRef: RefObject; roomData: roomType; } -const ReserveForm = ({ roomData }: Props) => { +const ReserveForm = ({ toggleRef, roomData }: Props) => { const { chargePerNight } = roomData; - + const portalElement: HTMLDivElement | null = document.querySelector('#modal'); return ( - - - - - -
예약 확정 전에는 요금이 청구되지 않습니다.
- -
-
+ portalElement && + createPortal( + + + + + +
예약 확정 전에는 요금이 청구되지 않습니다.
+ +
+
, + portalElement + ) ); }; @@ -32,9 +41,13 @@ export default ReserveForm; const StyledReserveFormWrapper = styled.div` z-index: 10; - position: absolute; + position: fixed; + top: 0; width: 100%; height: 100%; + display: flex; + align-items: center; + justify-content: center; background-color: rgba(0, 0, 0, 0.3); `;