From f5011729f34bd79e7e10027dd3533a4eb1109f8b Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Fri, 25 Oct 2024 10:26:58 +0900 Subject: [PATCH 01/11] =?UTF-8?q?fix:=20=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChecklistTab/EditChecklistTab.tsx | 11 ++++---- frontend/src/pages/EditChecklistPage.tsx | 28 +++++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/EditChecklist/ChecklistTab/EditChecklistTab.tsx b/frontend/src/components/EditChecklist/ChecklistTab/EditChecklistTab.tsx index 4af39950b..f0b5b77fc 100644 --- a/frontend/src/components/EditChecklist/ChecklistTab/EditChecklistTab.tsx +++ b/frontend/src/components/EditChecklist/ChecklistTab/EditChecklistTab.tsx @@ -1,29 +1,28 @@ import { useMemo } from 'react'; -import ChecklistTabSuspense from '@/components/_common/errorBoundary/ChecklistTabSuspense'; +import ChecklistTabFallback from '@/components/_common/errorBoundary/ChecklistTabFallback'; import Tabs from '@/components/_common/Tabs/Tabs'; import useGetChecklistDetailQuery from '@/hooks/query/useGetChecklistDetailQuery'; import useTabs from '@/hooks/useTabs'; import useChecklistStore from '@/store/useChecklistStore'; -import isSameCategory from '@/utils/isSameCategory'; interface Props { checklistId: string; } const EditChecklistTab = ({ checklistId }: Props) => { - const { data: checklist, isSuccess, isLoading } = useGetChecklistDetailQuery(checklistId); + const { data: checklist, isFetched, isLoading } = useGetChecklistDetailQuery(checklistId); const checklistStore = useChecklistStore(state => state.checklistCategoryQnA); const { getTabsForChecklist } = useTabs(); const categoryTabs = useMemo(() => { - if (isSuccess && isSameCategory(checklist.categories, checklistStore)) { + if (isFetched && checklist && checklistStore.length) { return getTabsForChecklist(checklist.categories); } return []; - }, [isSuccess, checklistStore]); + }, [isFetched, getTabsForChecklist, checklistStore]); - if (isLoading) return ; + if (isLoading) return ; return ; }; diff --git a/frontend/src/pages/EditChecklistPage.tsx b/frontend/src/pages/EditChecklistPage.tsx index a433b6a4c..25c927d06 100644 --- a/frontend/src/pages/EditChecklistPage.tsx +++ b/frontend/src/pages/EditChecklistPage.tsx @@ -1,4 +1,3 @@ -import { useEffect } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { useNavigate, useParams } from 'react-router-dom'; import { useStore } from 'zustand'; @@ -21,7 +20,6 @@ import roomInfoNonValidatedStore from '@/store/roomInfoNonValidatedStore'; import roomInfoStore from '@/store/roomInfoStore'; import useChecklistStore from '@/store/useChecklistStore'; import useSelectedOptionStore from '@/store/useSelectedOptionStore'; -import loadExternalScriptWithCallback from '@/utils/loadScript'; type RouteParams = { checklistId: string; @@ -55,23 +53,23 @@ const EditChecklistPage = () => { navigate(ROUTE_PATH.checklistOne(Number(checklistId))); }; - useEffect(() => { - const setChecklistDataToStore = async () => { - if (!isSuccess) return; + // useEffect(() => { + // const setChecklistDataToStore = async () => { + // if (!isSuccess) return; - roomInfoActions.setRawValues(checklist.room); - set('address', checklist.room.address!); - set('buildingName', checklist.room.buildingName!); - //TODO: 가까운 지하철은 나중에 api 수정되면 저장 + // roomInfoActions.setRawValues(checklist.room); + // set('address', checklist.room.address!); + // set('buildingName', checklist.room.buildingName!); + // //TODO: 가까운 지하철은 나중에 api 수정되면 저장 - loadExternalScriptWithCallback('kakaoMap', () => searchSubwayStationsByAddress(checklist.room.address!)); + // loadExternalScriptWithCallback('kakaoMap', () => searchSubwayStationsByAddress(checklist.room.address!)); - selectedOptionActions.set(checklist.options.map(option => option.optionId)); - checklistQuestionActions.set(checklist.categories); - }; + // selectedOptionActions.set(checklist.options.map(option => option.optionId)); + // checklistQuestionActions.set(checklist.categories); + // }; - setChecklistDataToStore(); - }, [checklistId, checklist, isSuccess]); + // setChecklistDataToStore(); + // }, [checklistId, checklist, isSuccess]); return ( <> From 67a544b5a9eacc6f92c32669ec01183de17af9fc Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Sun, 10 Nov 2024 09:09:42 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20=EC=B2=B4=ED=81=AC=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=B0=A9=20=EB=B9=84=EA=B5=90=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EB=B0=8F=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/routePath.ts | 2 + frontend/src/mocks/fixtures/roomCompare.ts | 94 ++++++++++++++++++++++ frontend/src/pages/RoomComparePage.tsx | 43 ++++++++++ frontend/src/routers/router.tsx | 5 ++ frontend/src/types/checklistCompare.ts | 15 ++++ 5 files changed, 159 insertions(+) create mode 100644 frontend/src/mocks/fixtures/roomCompare.ts create mode 100644 frontend/src/pages/RoomComparePage.tsx create mode 100644 frontend/src/types/checklistCompare.ts diff --git a/frontend/src/constants/routePath.ts b/frontend/src/constants/routePath.ts index cd7c2539d..3184e5b08 100644 --- a/frontend/src/constants/routePath.ts +++ b/frontend/src/constants/routePath.ts @@ -11,6 +11,8 @@ export const ROUTE_PATH = { checklistQuestionSelect: `/checklist/question-select`, checklistId: '/checklist/:checklistId', checklistOne: (id: number) => `/checklist/${id}`, + /*compare*/ + roomCompare: '/room/compare', /* article */ articleList: '/article', articleId: '/article/:articleId', diff --git a/frontend/src/mocks/fixtures/roomCompare.ts b/frontend/src/mocks/fixtures/roomCompare.ts new file mode 100644 index 000000000..8a45d3669 --- /dev/null +++ b/frontend/src/mocks/fixtures/roomCompare.ts @@ -0,0 +1,94 @@ +import { ChecklistCompare } from '@/types/checklistCompare'; + +export const threeRoomsForCompare: ChecklistCompare[] = [ + { + checklistId: 1, + roomName: '서울대입구 B방', + deposit: 1000, + rent: 30, + options: [1, 2, 3], + categories: [ + { + categoryId: 1, + categoryName: '청결', + score: 1, + }, + { + categoryId: 2, + categoryName: '편의시설', + + score: 2, + }, + ], + address: '서울시 관악구 봉천동', + contractTerm: 12, + floor: 2, + station: '서울대입구역', + walkingTime: 5, + realEstate: '강남 부동산', + geolocation: { + latitude: 37.5061912, + longitude: 127.0508228, + }, + }, + { + checklistId: 2, + roomName: '잠실 A방', + deposit: 1000, + rent: 30, + options: [1, 2, 3], + categories: [ + { + categoryId: 1, + categoryName: '청결도', + score: 9, + }, + { + categoryId: 2, + categoryName: '편의시설', + + score: 5, + }, + ], + address: '서울시 송파구 잠실동', + contractTerm: 12, + floor: 3, + station: '잠실역', + walkingTime: 7, + realEstate: '송파 부동산', + geolocation: { + latitude: 37.5061912, + longitude: 127.0508228, + }, + }, + { + checklistId: 3, + roomName: '구의역 C방', + deposit: 1000, + rent: 30, + options: [1, 2, 3], + categories: [ + { + categoryId: 1, + categoryName: '청결도', + score: 3, + }, + { + categoryId: 2, + categoryName: '편의시설', + + score: 6, + }, + ], + address: '서울시 광진구 구의동', + contractTerm: 12, + floor: 1, + station: '구의역', + walkingTime: 3, + realEstate: '광진 부동산', + geolocation: { + latitude: 37.5061912, + longitude: 127.0508228, + }, + }, +]; diff --git a/frontend/src/pages/RoomComparePage.tsx b/frontend/src/pages/RoomComparePage.tsx new file mode 100644 index 000000000..69054810b --- /dev/null +++ b/frontend/src/pages/RoomComparePage.tsx @@ -0,0 +1,43 @@ +import styled from '@emotion/styled'; +import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import Header from '@/components/_common/Header/Header'; +import Layout from '@/components/_common/layout/Layout'; +import { ROUTE_PATH } from '@/constants/routePath'; +// import { getCompareRooms } from '@/apis/checklist'; +// import Header from '@/components/common/Header/Header'; +// import Layout from '@/components/common/layout/Layout'; +// import CompareCard from '@/components/RoomCompare/CompareCard'; +import { threeRoomsForCompare } from '@/mocks/fixtures/roomCompare'; +import { flexRow } from '@/styles/common'; +import theme from '@/styles/theme'; +import { ChecklistCompare } from '@/types/checklistCompare'; + +const RoomComparePage = () => { + const navigate = useNavigate(); + // const roomsId = { ...location.state }; + + const [roomList, setRoomList] = useState(threeRoomsForCompare); + + const handleClickBackward = () => { + navigate(ROUTE_PATH.checklistList); + }; + + return ( + <> +
} /> + + {/* {roomList?.map(room => )} */} + + + ); +}; + +export default RoomComparePage; + +const S = { + RoomGrid: styled.div` + ${flexRow} + `, +}; diff --git a/frontend/src/routers/router.tsx b/frontend/src/routers/router.tsx index e69ba7b22..04dfca18b 100644 --- a/frontend/src/routers/router.tsx +++ b/frontend/src/routers/router.tsx @@ -3,6 +3,7 @@ import { createBrowserRouter, Outlet } from 'react-router-dom'; import FooterLayout from '@/components/_common/layout/FooterLayout'; import { ROUTE_PATH } from '@/constants/routePath'; +import RoomComparePage from '@/pages/RoomComparePage'; import SignInPage from '@/pages/SignInPage'; import SignUpPage from '@/pages/SignUpPage'; @@ -81,6 +82,10 @@ const router = createBrowserRouter([ element: , path: ROUTE_PATH.signIn, }, + { + element: , + path: ROUTE_PATH.roomCompare, + }, { element: , path: '*', diff --git a/frontend/src/types/checklistCompare.ts b/frontend/src/types/checklistCompare.ts new file mode 100644 index 000000000..9e46269e2 --- /dev/null +++ b/frontend/src/types/checklistCompare.ts @@ -0,0 +1,15 @@ +import { Position } from '@/types/address'; +import { RoomInfo } from '@/types/room'; + +export interface CategoryScore { + categoryId: number; + categoryName: string; + score: number; +} + +export interface ChecklistCompare extends RoomInfo { + checklistId: number; + options: number[]; + categories: CategoryScore[]; + geolocation: Position; +} From ee18d85160bddfa472f91ead851a6c62c0eb7ff4 Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Sun, 10 Nov 2024 10:36:00 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20compare=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=201=EC=B0=A8=20=ED=8D=BC=EB=B8=94=EB=A6=AC=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/assets/assets.tsx | 11 ++ .../assets/icons/faceIcon/face-icon-bad.svg | 9 ++ .../assets/icons/faceIcon/face-icon.good.svg | 6 ++ .../assets/icons/faceIcon/face-icon.none.svg | 6 ++ .../assets/icons/faceIcon/face-icon.soso.svg | 6 ++ .../ChecklistCompare/CompareCard.tsx | 101 ++++++++++++++++++ .../ChecklistCompare/CompareCardItem.tsx | 43 ++++++++ .../components/_common/FaceIcon/FaceIcon.tsx | 23 ++++ frontend/src/mocks/fixtures/roomCompare.ts | 60 ++++------- frontend/src/pages/RoomComparePage.tsx | 3 +- frontend/src/types/checklistCompare.ts | 2 + 11 files changed, 228 insertions(+), 42 deletions(-) create mode 100644 frontend/src/assets/icons/faceIcon/face-icon-bad.svg create mode 100644 frontend/src/assets/icons/faceIcon/face-icon.good.svg create mode 100644 frontend/src/assets/icons/faceIcon/face-icon.none.svg create mode 100644 frontend/src/assets/icons/faceIcon/face-icon.soso.svg create mode 100644 frontend/src/components/ChecklistCompare/CompareCard.tsx create mode 100644 frontend/src/components/ChecklistCompare/CompareCardItem.tsx create mode 100644 frontend/src/components/_common/FaceIcon/FaceIcon.tsx diff --git a/frontend/src/assets/assets.tsx b/frontend/src/assets/assets.tsx index 60cdffe81..be699ace6 100644 --- a/frontend/src/assets/assets.tsx +++ b/frontend/src/assets/assets.tsx @@ -16,6 +16,13 @@ import Retry from '@/assets/icons/common/retry.svg'; import SmallCheck from '@/assets/icons/common/small-check.svg'; import PlusBlack from '@/assets/icons/plusMinus/plus-black.svg'; import PlusWhite from '@/assets/icons/plusMinus/plus-white.svg'; + +//face-icon +import FaceBadIcon from '@/assets/icons/faceIcon/face-icon-bad.svg'; +import FaceGoodIcon from '@/assets/icons/faceIcon/face-icon.good.svg'; +import FaceNoneIcon from '@/assets/icons/faceIcon/face-icon.none.svg'; +import FaceSosoIcon from '@/assets/icons/faceIcon/face-icon.soso.svg'; + // room import Building from '@/assets/icons/room/building.svg'; import Calendar from '@/assets/icons/room/calendar.svg'; @@ -77,6 +84,10 @@ export { DropdownMark, Error404, Error500, + FaceBadIcon, + FaceGoodIcon, + FaceNoneIcon, + FaceSosoIcon, InputRequiredDot, KakaoLogo, LampIcon, diff --git a/frontend/src/assets/icons/faceIcon/face-icon-bad.svg b/frontend/src/assets/icons/faceIcon/face-icon-bad.svg new file mode 100644 index 000000000..87b1728ee --- /dev/null +++ b/frontend/src/assets/icons/faceIcon/face-icon-bad.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/icons/faceIcon/face-icon.good.svg b/frontend/src/assets/icons/faceIcon/face-icon.good.svg new file mode 100644 index 000000000..5ae9767ff --- /dev/null +++ b/frontend/src/assets/icons/faceIcon/face-icon.good.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/icons/faceIcon/face-icon.none.svg b/frontend/src/assets/icons/faceIcon/face-icon.none.svg new file mode 100644 index 000000000..c2641728c --- /dev/null +++ b/frontend/src/assets/icons/faceIcon/face-icon.none.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/icons/faceIcon/face-icon.soso.svg b/frontend/src/assets/icons/faceIcon/face-icon.soso.svg new file mode 100644 index 000000000..5ae9767ff --- /dev/null +++ b/frontend/src/assets/icons/faceIcon/face-icon.soso.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/components/ChecklistCompare/CompareCard.tsx b/frontend/src/components/ChecklistCompare/CompareCard.tsx new file mode 100644 index 000000000..81f79b35e --- /dev/null +++ b/frontend/src/components/ChecklistCompare/CompareCard.tsx @@ -0,0 +1,101 @@ +import styled from '@emotion/styled'; + +import FaceIcon from '@/components/_common/FaceIcon/FaceIcon'; +import SubwayStations from '@/components/_common/Subway/SubwayStations'; +import CompareItem from '@/components/ChecklistCompare/CompareCardItem'; +import { boxShadow, flexColumn, title1, title2, title3 } from '@/styles/common'; +import { ChecklistCompare } from '@/types/checklistCompare'; +// import calcEmotions from '@/utils/calcEmotions'; + +interface Props { + room: ChecklistCompare; +} + +const CompareCard = ({ room }: Props) => { + return ( + + {room.roomName} + {room.address}} /> + {room.floor}층} /> + + {room.deposit}/{room.rent} + + } + /> + {room.contractTerm}개월} /> + + {room.station}/ +
+ 도보 {room.walkingTime}분 + + } + /> + + {/* {room.options.length}개} /> */} + {/* TODO: 모든 카테고리를 다 보여주고 없으면 - 표시로 변경 */} + {room.categories.map(category => ( + + // + // {/* */} + // {/* {category.score}점 + // */} + } + /> + ))} +
+ ); +}; + +export default CompareCard; + +const S = { + Container: styled.div` + width: 100%; + padding: 20px 4px; + box-sizing: border-box; + ${flexColumn}; + align-items: center; + gap: 30px; + `, + Title: styled.div` + ${title2} + `, + RankWrapper: styled.div` + ${flexColumn} + gap: 5px; + `, + Rank: styled.div` + ${title1} + `, + Score: styled.span` + font-size: ${({ theme }) => theme.text.size.small}; + `, + Item: styled.div` + display: flex; + width: 100%; + + font-size: ${({ theme }) => theme.text.size.medium}; + line-height: 1.5; + letter-spacing: 0.05rem; + text-align: center; + justify-content: center; + word-break: keep-all; + `, + OptionButton: styled.button` + ${title3} + padding: 12px 24px; + border: 1px solid ${({ theme }) => theme.palette.grey300}; + border-radius: 8px; + ${boxShadow} + `, +}; diff --git a/frontend/src/components/ChecklistCompare/CompareCardItem.tsx b/frontend/src/components/ChecklistCompare/CompareCardItem.tsx new file mode 100644 index 000000000..5c563cf63 --- /dev/null +++ b/frontend/src/components/ChecklistCompare/CompareCardItem.tsx @@ -0,0 +1,43 @@ +import styled from '@emotion/styled'; + +import { flexCenter, flexColumn } from '@/styles/common'; + +interface Props { + label?: string; + isLabeled?: boolean; + item: React.ReactNode; + height?: number; +} + +const CompareItem = ({ label, isLabeled = false, item, height }: Props) => { + return ( + + {label} + {item} + + ); +}; + +export default CompareItem; + +const S = { + ItemContainer: styled.div<{ height?: number }>` + width: 100%; + height: ${({ height }) => height && height}rem; + ${flexColumn}; + align-items: center; + `, + ItemText: styled.div` + height: 100%; + ${flexCenter}; + + line-height: 1.5rem; + `, + Label: styled.div<{ isLabeled: boolean }>` + height: 1.5rem; + margin-bottom: 0.5rem; + + color: ${({ theme }) => theme.palette.grey500}; + font-size: ${({ theme }) => theme.text.size.xSmall}; + `, +}; diff --git a/frontend/src/components/_common/FaceIcon/FaceIcon.tsx b/frontend/src/components/_common/FaceIcon/FaceIcon.tsx new file mode 100644 index 000000000..614db0973 --- /dev/null +++ b/frontend/src/components/_common/FaceIcon/FaceIcon.tsx @@ -0,0 +1,23 @@ +import { SVGProps } from 'react'; + +import { FaceBadIcon, FaceGoodIcon, FaceNoneIcon, FaceSosoIcon } from '@/assets/assets'; + +type EmotionNameWithNone = 'GOOD' | 'SOSO' | 'BAD' | 'NONE'; + +interface FaceIconProps extends SVGProps { + emotion: EmotionNameWithNone; + isFilled?: boolean; +} + +const FaceIcon = ({ emotion, ...rest }: FaceIconProps) => { + return ( + <> + {emotion === 'GOOD' && } + {emotion === 'SOSO' && } + {emotion === 'BAD' && } + {emotion === 'NONE' && } + + ); +}; + +export default FaceIcon; diff --git a/frontend/src/mocks/fixtures/roomCompare.ts b/frontend/src/mocks/fixtures/roomCompare.ts index 8a45d3669..10e5f9549 100644 --- a/frontend/src/mocks/fixtures/roomCompare.ts +++ b/frontend/src/mocks/fixtures/roomCompare.ts @@ -1,12 +1,27 @@ +import { nearSubway } from '@/mocks/fixtures/subway'; import { ChecklistCompare } from '@/types/checklistCompare'; export const threeRoomsForCompare: ChecklistCompare[] = [ { checklistId: 1, - roomName: '서울대입구 B방', - deposit: 1000, - rent: 30, + roomName: '아름다운 방', + address: '서울 송파구 올림픽로35다길 42', + buildingName: '한국루터회관', + deposit: undefined, + rent: 50, + maintenanceFee: 5, + contractTerm: 12, + floor: 5, + realEstate: undefined, + structure: '오픈형 원룸', + size: 25, + floorLevel: '지상', + occupancyMonth: 9, + occupancyPeriod: '중순', + includedMaintenances: [2], + createdAt: '2024-02-01T10:00:00Z', options: [1, 2, 3], + nearSubwayStations: nearSubway, categories: [ { categoryId: 1, @@ -20,12 +35,6 @@ export const threeRoomsForCompare: ChecklistCompare[] = [ score: 2, }, ], - address: '서울시 관악구 봉천동', - contractTerm: 12, - floor: 2, - station: '서울대입구역', - walkingTime: 5, - realEstate: '강남 부동산', geolocation: { latitude: 37.5061912, longitude: 127.0508228, @@ -37,6 +46,7 @@ export const threeRoomsForCompare: ChecklistCompare[] = [ deposit: 1000, rent: 30, options: [1, 2, 3], + nearSubwayStations: nearSubway, categories: [ { categoryId: 1, @@ -53,42 +63,10 @@ export const threeRoomsForCompare: ChecklistCompare[] = [ address: '서울시 송파구 잠실동', contractTerm: 12, floor: 3, - station: '잠실역', - walkingTime: 7, realEstate: '송파 부동산', geolocation: { latitude: 37.5061912, longitude: 127.0508228, }, }, - { - checklistId: 3, - roomName: '구의역 C방', - deposit: 1000, - rent: 30, - options: [1, 2, 3], - categories: [ - { - categoryId: 1, - categoryName: '청결도', - score: 3, - }, - { - categoryId: 2, - categoryName: '편의시설', - - score: 6, - }, - ], - address: '서울시 광진구 구의동', - contractTerm: 12, - floor: 1, - station: '구의역', - walkingTime: 3, - realEstate: '광진 부동산', - geolocation: { - latitude: 37.5061912, - longitude: 127.0508228, - }, - }, ]; diff --git a/frontend/src/pages/RoomComparePage.tsx b/frontend/src/pages/RoomComparePage.tsx index 69054810b..72d876a4e 100644 --- a/frontend/src/pages/RoomComparePage.tsx +++ b/frontend/src/pages/RoomComparePage.tsx @@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom'; import Header from '@/components/_common/Header/Header'; import Layout from '@/components/_common/layout/Layout'; +import CompareCard from '@/components/ChecklistCompare/CompareCard'; import { ROUTE_PATH } from '@/constants/routePath'; // import { getCompareRooms } from '@/apis/checklist'; // import Header from '@/components/common/Header/Header'; @@ -28,7 +29,7 @@ const RoomComparePage = () => { <>
} /> - {/* {roomList?.map(room => )} */} + {roomList?.map(room => )} ); diff --git a/frontend/src/types/checklistCompare.ts b/frontend/src/types/checklistCompare.ts index 9e46269e2..6664a718f 100644 --- a/frontend/src/types/checklistCompare.ts +++ b/frontend/src/types/checklistCompare.ts @@ -1,5 +1,6 @@ import { Position } from '@/types/address'; import { RoomInfo } from '@/types/room'; +import { SubwayStation } from '@/types/subway'; export interface CategoryScore { categoryId: number; @@ -11,5 +12,6 @@ export interface ChecklistCompare extends RoomInfo { checklistId: number; options: number[]; categories: CategoryScore[]; + nearSubwayStations: SubwayStation[]; geolocation: Position; } From e9a625a03eaca4b192115b0fb788e4b36c56334a Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Sun, 10 Nov 2024 11:49:57 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=EB=B0=A9=202=EA=B0=9C=20?= =?UTF-8?q?=EB=A7=88=EC=BB=A4=20=EC=9E=88=EB=8A=94=20=EC=A7=80=EB=8F=84=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChecklistCompare/CompareCard.tsx | 24 +-- .../ChecklistCompare/CompareCardItem.tsx | 4 +- .../src/components/_common/Map/AddressMap.tsx | 2 +- .../src/components/_common/Map/CompareMap.tsx | 139 ++++++++++++++++++ .../components/_common/Map/RealTimeMap.tsx | 2 +- frontend/src/pages/RoomComparePage.tsx | 13 +- frontend/src/utils/createKakaoMapElements.ts | 11 +- 7 files changed, 175 insertions(+), 20 deletions(-) create mode 100644 frontend/src/components/_common/Map/CompareMap.tsx diff --git a/frontend/src/components/ChecklistCompare/CompareCard.tsx b/frontend/src/components/ChecklistCompare/CompareCard.tsx index 81f79b35e..bf9d8d63a 100644 --- a/frontend/src/components/ChecklistCompare/CompareCard.tsx +++ b/frontend/src/components/ChecklistCompare/CompareCard.tsx @@ -2,22 +2,23 @@ import styled from '@emotion/styled'; import FaceIcon from '@/components/_common/FaceIcon/FaceIcon'; import SubwayStations from '@/components/_common/Subway/SubwayStations'; -import CompareItem from '@/components/ChecklistCompare/CompareCardItem'; +import CompareCardItem from '@/components/ChecklistCompare/CompareCardItem'; import { boxShadow, flexColumn, title1, title2, title3 } from '@/styles/common'; import { ChecklistCompare } from '@/types/checklistCompare'; // import calcEmotions from '@/utils/calcEmotions'; interface Props { room: ChecklistCompare; + index: number; } -const CompareCard = ({ room }: Props) => { +const CompareCard = ({ room, index }: Props) => { return ( - {room.roomName} - {room.address}} /> - {room.floor}층} /> - {room.roomName} + {room.address}} /> + {room.floor}층} /> + @@ -25,8 +26,8 @@ const CompareCard = ({ room }: Props) => { } /> - {room.contractTerm}개월} /> - {room.contractTerm}개월} /> + @@ -37,10 +38,10 @@ const CompareCard = ({ room }: Props) => { } /> - {/* {room.options.length}개} /> */} + {/* {room.options.length}개} /> */} {/* TODO: 모든 카테고리를 다 보여주고 없으면 - 표시로 변경 */} {room.categories.map(category => ( - ` ${title2} + color:${({ index, theme }) => (index === 0 ? theme.palette.yellow600 : theme.palette.green600)} `, RankWrapper: styled.div` ${flexColumn} diff --git a/frontend/src/components/ChecklistCompare/CompareCardItem.tsx b/frontend/src/components/ChecklistCompare/CompareCardItem.tsx index 5c563cf63..a02c2b3fe 100644 --- a/frontend/src/components/ChecklistCompare/CompareCardItem.tsx +++ b/frontend/src/components/ChecklistCompare/CompareCardItem.tsx @@ -9,7 +9,7 @@ interface Props { height?: number; } -const CompareItem = ({ label, isLabeled = false, item, height }: Props) => { +const CompareCardItem = ({ label, isLabeled = false, item, height }: Props) => { return ( {label} @@ -18,7 +18,7 @@ const CompareItem = ({ label, isLabeled = false, item, height }: Props) => { ); }; -export default CompareItem; +export default CompareCardItem; const S = { ItemContainer: styled.div<{ height?: number }>` diff --git a/frontend/src/components/_common/Map/AddressMap.tsx b/frontend/src/components/_common/Map/AddressMap.tsx index 0ecb18bed..4cb1931d6 100644 --- a/frontend/src/components/_common/Map/AddressMap.tsx +++ b/frontend/src/components/_common/Map/AddressMap.tsx @@ -34,7 +34,7 @@ const AddressMap = ({ location }: { location: string }) => { geocoder.addressSearch(location, (result: any, status: any) => { if (status === kakao.maps.services.Status.OK) { const coords = new kakao.maps.LatLng(result[0].y, result[0].x); - const marker = createMarker(kakao, map, coords); + const marker = createMarker(kakao, map, coords, 'primary'); markerRef.current = marker; map.setCenter(coords); } diff --git a/frontend/src/components/_common/Map/CompareMap.tsx b/frontend/src/components/_common/Map/CompareMap.tsx new file mode 100644 index 000000000..2bf8bd55e --- /dev/null +++ b/frontend/src/components/_common/Map/CompareMap.tsx @@ -0,0 +1,139 @@ +import styled from '@emotion/styled'; +import { useEffect, useRef } from 'react'; + +import { Position } from '@/types/address'; +import createKakaoMapElements from '@/utils/createKakaoMapElements'; + +import loadExternalScriptWithCallback from '../../../utils/loadScript'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +const CompareMap = ({ positions }: { positions: Position[] }) => { + const mapContainerRef = useRef(null); + + useEffect(() => { + const initializeMap = () => { + const { kakao } = window as any; + + const centerOfPosition = { + latitude: (positions[0].latitude + positions[1].latitude) / 2, + longitude: (positions[0].longitude + positions[1].longitude) / 2, + }; + + function getDistanceFromLatLonInKm(lat1: number, lng1: number, lat2: number, lng2: number) { + function deg2rad(deg: any) { + return deg * (Math.PI / 180); + } + const R = 6371; + const dLat = deg2rad(lat2 - lat1); + const dLon = deg2rad(lng2 - lng1); + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + const d = R * c; + return d; + } + + const diff = getDistanceFromLatLonInKm( + positions[0].latitude, + positions[0].longitude, + positions[1].latitude, + positions[1].longitude, + ); + + // 거리에 따른 적절한 지도 level 설정 + const getMapLevel = (distance: number) => { + if (distance < 0.5) return 3; + if (distance < 0.7) return 4; + if (distance < 1) return 5; + if (distance < 3) return 6; + if (distance < 5) return 7; + if (distance < 12) return 9; + return 10; + }; + + const mapLevel = getMapLevel(diff); + + kakao.maps.load(() => { + if (!mapContainerRef.current) return; + const mapOption = { + center: new kakao.maps.LatLng(centerOfPosition.latitude, centerOfPosition.longitude), + level: mapLevel, + }; + const map = new kakao.maps.Map(mapContainerRef.current, mapOption); + + const { createMarker } = createKakaoMapElements(); + + const marker1 = createMarker( + kakao, + map, + new kakao.maps.LatLng(positions[0].latitude, positions[0].longitude), + 'primary', + 'first', + ); + + const marker2 = createMarker( + kakao, + map, + new kakao.maps.LatLng(positions[1].latitude, positions[1].longitude), + 'secondary', + 'second', + ); + + marker1.setMap(map); + marker2.setMap(map); + }); + }; + + if (location) { + loadExternalScriptWithCallback('kakaoMap', initializeMap); + } + }, [location]); + + return ( + <> + {location && ( + + + + )} + + ); +}; + +const S = { + Box: styled.div` + width: 100%; + height: 30rem; + + background-color: ${({ theme }) => theme.palette.background}; + `, + Map: styled.div` + position: relative; + width: 100%; + height: 100%; + `, + LinkButtonBox: styled.div` + display: flex; + position: absolute; + right: 0; + bottom: 0; + z-index: 10; + + padding: 0.5rem; + + color: ${({ theme }) => theme.palette.white}; + gap: 1rem; + border-radius: 0.3rem; + `, + LinkButton: styled.img` + z-index: 10; + box-shadow: 0 0.4rem 1.5rem rgb(0 0 0 / 30%); + width: 3.5rem; + border-radius: 50%; + height: 3.5rem; + `, +}; + +export default CompareMap; diff --git a/frontend/src/components/_common/Map/RealTimeMap.tsx b/frontend/src/components/_common/Map/RealTimeMap.tsx index 87b33dff8..4928199ca 100644 --- a/frontend/src/components/_common/Map/RealTimeMap.tsx +++ b/frontend/src/components/_common/Map/RealTimeMap.tsx @@ -44,7 +44,7 @@ const RealTimeMap = ({ mapRef.current = map; /*마커 생성*/ - const marker = createMarker(kakao, map, new kakao.maps.LatLng(position.latitude, position.longitude)); + const marker = createMarker(kakao, map, new kakao.maps.LatLng(position.latitude, position.longitude), 'primary'); markerRef.current = marker; /*인포윈도우 생성*/ diff --git a/frontend/src/pages/RoomComparePage.tsx b/frontend/src/pages/RoomComparePage.tsx index 72d876a4e..fac6b7c23 100644 --- a/frontend/src/pages/RoomComparePage.tsx +++ b/frontend/src/pages/RoomComparePage.tsx @@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom'; import Header from '@/components/_common/Header/Header'; import Layout from '@/components/_common/layout/Layout'; +import CompareMap from '@/components/_common/Map/CompareMap'; import CompareCard from '@/components/ChecklistCompare/CompareCard'; import { ROUTE_PATH } from '@/constants/routePath'; // import { getCompareRooms } from '@/apis/checklist'; @@ -13,6 +14,7 @@ import { ROUTE_PATH } from '@/constants/routePath'; import { threeRoomsForCompare } from '@/mocks/fixtures/roomCompare'; import { flexRow } from '@/styles/common'; import theme from '@/styles/theme'; +import { Position } from '@/types/address'; import { ChecklistCompare } from '@/types/checklistCompare'; const RoomComparePage = () => { @@ -24,12 +26,19 @@ const RoomComparePage = () => { const handleClickBackward = () => { navigate(ROUTE_PATH.checklistList); }; + const positions: Position[] = [ + { latitude: 37.5061912, longitude: 127.0019228 }, + { latitude: 37.5061912, longitude: 127.1266228 }, + ]; return ( <>
} /> - - {roomList?.map(room => )} + + + + {roomList?.map((room, index) => )} + ); diff --git a/frontend/src/utils/createKakaoMapElements.ts b/frontend/src/utils/createKakaoMapElements.ts index 068af9982..9e02847f6 100644 --- a/frontend/src/utils/createKakaoMapElements.ts +++ b/frontend/src/utils/createKakaoMapElements.ts @@ -17,16 +17,21 @@ const createKakaoMapElements = () => { return new kakao.maps.Map(container, options); }; - const createMarker = (kakao: any, map: any, position: any) => { - const imageSrc = 'https://github.com/user-attachments/assets/cdd2825b-407f-485a-8cc9-5d261acf815d'; + const createMarker = (kakao: any, map: any, position: any, color: 'primary' | 'secondary', title?: string) => { + const imageSrc = { + primary: 'https://github.com/user-attachments/assets/cd52185e-f22f-4d8c-9528-cf9f0593bfaf', + secondary: 'https://github.com/user-attachments/assets/2f19b10b-790c-4d0a-88c4-36eb9b118e8d', + }; + const imageSize = new kakao.maps.Size(32, 40); const imageOption = { offset: new kakao.maps.Point(15, 45) }; - const markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption); + const markerImage = new kakao.maps.MarkerImage(imageSrc[color], imageSize, imageOption); return new kakao.maps.Marker({ map: map, position: position, image: markerImage, + title: title, }); }; From 42a40f7b72442bd5579fe548fcb2f60246e24ecb Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Mon, 11 Nov 2024 20:52:34 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=EC=A7=80=EB=8F=84=20roomMarker?= =?UTF-8?q?=20=ED=95=B4=EB=8B=B9=20=EC=9C=84=EC=B9=98=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CompareCard.tsx | 38 +++------------ .../CompareCardItem.tsx | 0 .../src/components/RoomCompare/RoomMarker.tsx | 30 ++++++++++++ .../src/components/_common/Header/Header.tsx | 7 +-- .../{CompareMap.tsx => RoomCompareMap.tsx} | 35 ++++++++++---- frontend/src/mocks/fixtures/roomCompare.ts | 2 +- frontend/src/pages/RoomComparePage.tsx | 47 +++++++++++++++---- 7 files changed, 106 insertions(+), 53 deletions(-) rename frontend/src/components/{ChecklistCompare => RoomCompare}/CompareCard.tsx (59%) rename frontend/src/components/{ChecklistCompare => RoomCompare}/CompareCardItem.tsx (100%) create mode 100644 frontend/src/components/RoomCompare/RoomMarker.tsx rename frontend/src/components/_common/Map/{CompareMap.tsx => RoomCompareMap.tsx} (79%) diff --git a/frontend/src/components/ChecklistCompare/CompareCard.tsx b/frontend/src/components/RoomCompare/CompareCard.tsx similarity index 59% rename from frontend/src/components/ChecklistCompare/CompareCard.tsx rename to frontend/src/components/RoomCompare/CompareCard.tsx index bf9d8d63a..65cc2092f 100644 --- a/frontend/src/components/ChecklistCompare/CompareCard.tsx +++ b/frontend/src/components/RoomCompare/CompareCard.tsx @@ -2,8 +2,8 @@ import styled from '@emotion/styled'; import FaceIcon from '@/components/_common/FaceIcon/FaceIcon'; import SubwayStations from '@/components/_common/Subway/SubwayStations'; -import CompareCardItem from '@/components/ChecklistCompare/CompareCardItem'; -import { boxShadow, flexColumn, title1, title2, title3 } from '@/styles/common'; +import CompareCardItem from '@/components/RoomCompare/CompareCardItem'; +import { boxShadow, flexColumn, title1, title3 } from '@/styles/common'; import { ChecklistCompare } from '@/types/checklistCompare'; // import calcEmotions from '@/utils/calcEmotions'; @@ -12,10 +12,9 @@ interface Props { index: number; } -const CompareCard = ({ room, index }: Props) => { +const CompareCard = ({ room }: Props) => { return ( - {room.roomName} {room.address}} /> {room.floor}층} /> { } /> {room.contractTerm}개월} /> - - {room.station}/ -
- 도보 {room.walkingTime}분 - - } - /> - - {/* {room.options.length}개} /> */} + } /> + {room.options.length}개} /> {/* TODO: 모든 카테고리를 다 보여주고 없으면 - 표시로 변경 */} {room.categories.map(category => ( - - // - // {/* */} - // {/* {category.score}점 - // */} - } - /> + } /> ))}
); @@ -68,10 +47,7 @@ const S = { align-items: center; gap: 30px; `, - Title: styled.div<{ index: number }>` - ${title2} - color:${({ index, theme }) => (index === 0 ? theme.palette.yellow600 : theme.palette.green600)} - `, + RankWrapper: styled.div` ${flexColumn} gap: 5px; diff --git a/frontend/src/components/ChecklistCompare/CompareCardItem.tsx b/frontend/src/components/RoomCompare/CompareCardItem.tsx similarity index 100% rename from frontend/src/components/ChecklistCompare/CompareCardItem.tsx rename to frontend/src/components/RoomCompare/CompareCardItem.tsx diff --git a/frontend/src/components/RoomCompare/RoomMarker.tsx b/frontend/src/components/RoomCompare/RoomMarker.tsx new file mode 100644 index 000000000..82793fcb9 --- /dev/null +++ b/frontend/src/components/RoomCompare/RoomMarker.tsx @@ -0,0 +1,30 @@ +import styled from '@emotion/styled'; + +import { flexCenter, title2 } from '@/styles/common'; + +const RoomMarker = ({ type, onClick }: { type: 'A' | 'B'; onClick?: () => void }) => { + return ( + + {type} + + ); +}; + +const S = { + RoomMarker: styled.span<{ type: string }>` + display: inline; + width: 3rem; + height: 3rem; + + ${flexCenter}; + flex-shrink: 0; + + background-color: ${({ type, theme }) => (type === 'A' ? theme.palette.yellow600 : theme.palette.green600)}; + border-radius: 50%; + + ${title2} + color: white; + `, +}; + +export default RoomMarker; diff --git a/frontend/src/components/_common/Header/Header.tsx b/frontend/src/components/_common/Header/Header.tsx index 357990235..81e364876 100644 --- a/frontend/src/components/_common/Header/Header.tsx +++ b/frontend/src/components/_common/Header/Header.tsx @@ -19,9 +19,9 @@ const HeaderWrapper = ({ left, right, center, isTransparent = false, ...rest }: <> - {left && {left}} + {left} {center &&
{center}
}
- {right && {right}} + {right}
{!isTransparent && } @@ -58,7 +58,7 @@ const S = { display: flex; justify-content: flex-start; align-items: center; - min-width: 70px; + min-width: 5rem; `, Center: styled.div` ${flexCenter} @@ -67,6 +67,7 @@ const S = { Right: styled.div` display: flex; justify-content: flex-end; + min-width: 5rem; `, TextButton: styled.button` color: ${({ theme }) => theme.palette.black}; diff --git a/frontend/src/components/_common/Map/CompareMap.tsx b/frontend/src/components/_common/Map/RoomCompareMap.tsx similarity index 79% rename from frontend/src/components/_common/Map/CompareMap.tsx rename to frontend/src/components/_common/Map/RoomCompareMap.tsx index 2bf8bd55e..10316658f 100644 --- a/frontend/src/components/_common/Map/CompareMap.tsx +++ b/frontend/src/components/_common/Map/RoomCompareMap.tsx @@ -1,6 +1,7 @@ import styled from '@emotion/styled'; import { useEffect, useRef } from 'react'; +import RoomMarker from '@/components/RoomCompare/RoomMarker'; import { Position } from '@/types/address'; import createKakaoMapElements from '@/utils/createKakaoMapElements'; @@ -10,6 +11,7 @@ import loadExternalScriptWithCallback from '../../../utils/loadScript'; const CompareMap = ({ positions }: { positions: Position[] }) => { const mapContainerRef = useRef(null); + const mapRef = useRef(null); useEffect(() => { const initializeMap = () => { @@ -62,6 +64,7 @@ const CompareMap = ({ positions }: { positions: Position[] }) => { level: mapLevel, }; const map = new kakao.maps.Map(mapContainerRef.current, mapOption); + mapRef.current = map; const { createMarker } = createKakaoMapElements(); @@ -91,11 +94,30 @@ const CompareMap = ({ positions }: { positions: Position[] }) => { } }, [location]); + const handleRoomMarkerClick = (positionIndex: number) => { + const move = () => { + const { kakao } = window as any; + + const moveLatLon = new kakao.maps.LatLng(positions[positionIndex].latitude, positions[positionIndex].longitude); + mapRef.current.setLevel(4); + mapRef.current.panTo(moveLatLon); + }; + + if (mapRef.current) { + loadExternalScriptWithCallback('kakaoMap', move); + } + }; + return ( <> {location && ( - + + + handleRoomMarkerClick(0)} /> + handleRoomMarkerClick(1)} /> + + )} @@ -105,7 +127,7 @@ const CompareMap = ({ positions }: { positions: Position[] }) => { const S = { Box: styled.div` width: 100%; - height: 30rem; + height: 20rem; background-color: ${({ theme }) => theme.palette.background}; `, @@ -114,7 +136,7 @@ const S = { width: 100%; height: 100%; `, - LinkButtonBox: styled.div` + RoomMarkBox: styled.div` display: flex; position: absolute; right: 0; @@ -127,13 +149,6 @@ const S = { gap: 1rem; border-radius: 0.3rem; `, - LinkButton: styled.img` - z-index: 10; - box-shadow: 0 0.4rem 1.5rem rgb(0 0 0 / 30%); - width: 3.5rem; - border-radius: 50%; - height: 3.5rem; - `, }; export default CompareMap; diff --git a/frontend/src/mocks/fixtures/roomCompare.ts b/frontend/src/mocks/fixtures/roomCompare.ts index 10e5f9549..31023f2b5 100644 --- a/frontend/src/mocks/fixtures/roomCompare.ts +++ b/frontend/src/mocks/fixtures/roomCompare.ts @@ -4,7 +4,7 @@ import { ChecklistCompare } from '@/types/checklistCompare'; export const threeRoomsForCompare: ChecklistCompare[] = [ { checklistId: 1, - roomName: '아름다운 방', + roomName: '건대입구역 10분거리 방', address: '서울 송파구 올림픽로35다길 42', buildingName: '한국루터회관', deposit: undefined, diff --git a/frontend/src/pages/RoomComparePage.tsx b/frontend/src/pages/RoomComparePage.tsx index fac6b7c23..ea11c6043 100644 --- a/frontend/src/pages/RoomComparePage.tsx +++ b/frontend/src/pages/RoomComparePage.tsx @@ -4,15 +4,12 @@ import { useNavigate } from 'react-router-dom'; import Header from '@/components/_common/Header/Header'; import Layout from '@/components/_common/layout/Layout'; -import CompareMap from '@/components/_common/Map/CompareMap'; -import CompareCard from '@/components/ChecklistCompare/CompareCard'; +import CompareMap from '@/components/_common/Map/RoomCompareMap'; +import CompareCard from '@/components/RoomCompare/CompareCard'; +import RoomMarker from '@/components/RoomCompare/RoomMarker'; import { ROUTE_PATH } from '@/constants/routePath'; -// import { getCompareRooms } from '@/apis/checklist'; -// import Header from '@/components/common/Header/Header'; -// import Layout from '@/components/common/layout/Layout'; -// import CompareCard from '@/components/RoomCompare/CompareCard'; import { threeRoomsForCompare } from '@/mocks/fixtures/roomCompare'; -import { flexRow } from '@/styles/common'; +import { flexCenter, flexRow } from '@/styles/common'; import theme from '@/styles/theme'; import { Position } from '@/types/address'; import { ChecklistCompare } from '@/types/checklistCompare'; @@ -33,8 +30,23 @@ const RoomComparePage = () => { return ( <> -
} /> +
} + center={방 비교하기} + /> + + + + {roomList[0].roomName} + + + + {roomList[1].roomName} + + + + {roomList?.map((room, index) => )} @@ -50,4 +62,23 @@ const S = { RoomGrid: styled.div` ${flexRow} `, + TitleFlex: styled.div` + display: flex; + width: 100vw; + `, + RoomTitle: styled.div` + width: 50%; + margin-bottom: 0.5rem; + ${flexCenter} + gap:0.8rem; + `, + Title: styled.span` + display: inline; + padding: 0.8rem 0; + + font-weight: ${({ theme }) => theme.text.weight.bold}; + font-size: 2rem; + text-align: center; + border-radius: 0.8rem; + `, }; From 275be8c0c534b039feac8b824caa13abbb585f5c Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Mon, 11 Nov 2024 21:24:21 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20=EC=98=B5=EC=85=98=20=EC=9E=90?= =?UTF-8?q?=EC=84=B8=ED=9E=88=20=EB=B3=B4=EA=B8=B0=20=EB=AA=A8=EB=8B=AC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/RoomCompare/CompareCard.tsx | 18 +++++--- .../RoomCompare/CompareCardItem.tsx | 4 +- .../components/RoomCompare/OptionModal.tsx | 43 +++++++++++++++++++ frontend/src/pages/RoomComparePage.tsx | 15 ++++++- 4 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 frontend/src/components/RoomCompare/OptionModal.tsx diff --git a/frontend/src/components/RoomCompare/CompareCard.tsx b/frontend/src/components/RoomCompare/CompareCard.tsx index 65cc2092f..27163c439 100644 --- a/frontend/src/components/RoomCompare/CompareCard.tsx +++ b/frontend/src/components/RoomCompare/CompareCard.tsx @@ -1,18 +1,20 @@ import styled from '@emotion/styled'; +import React from 'react'; import FaceIcon from '@/components/_common/FaceIcon/FaceIcon'; import SubwayStations from '@/components/_common/Subway/SubwayStations'; import CompareCardItem from '@/components/RoomCompare/CompareCardItem'; -import { boxShadow, flexColumn, title1, title3 } from '@/styles/common'; +import { boxShadow, flexColumn, title1, title4 } from '@/styles/common'; import { ChecklistCompare } from '@/types/checklistCompare'; // import calcEmotions from '@/utils/calcEmotions'; interface Props { room: ChecklistCompare; index: number; + openOptionModal: () => void; } -const CompareCard = ({ room }: Props) => { +const CompareCard = ({ room, openOptionModal }: Props) => { return ( {room.address}} /> @@ -27,7 +29,10 @@ const CompareCard = ({ room }: Props) => { /> {room.contractTerm}개월} /> } /> - {room.options.length}개} /> + {room.options.length}개} + /> {/* TODO: 모든 카테고리를 다 보여주고 없으면 - 표시로 변경 */} {room.categories.map(category => ( } /> @@ -36,7 +41,8 @@ const CompareCard = ({ room }: Props) => { ); }; -export default CompareCard; +const CompareCardMemo = React.memo(CompareCard); +export default CompareCardMemo; const S = { Container: styled.div` @@ -70,8 +76,8 @@ const S = { word-break: keep-all; `, OptionButton: styled.button` - ${title3} - padding: 12px 24px; + ${title4} + padding: 12px 16px; border: 1px solid ${({ theme }) => theme.palette.grey300}; border-radius: 8px; ${boxShadow} diff --git a/frontend/src/components/RoomCompare/CompareCardItem.tsx b/frontend/src/components/RoomCompare/CompareCardItem.tsx index a02c2b3fe..75a665f9f 100644 --- a/frontend/src/components/RoomCompare/CompareCardItem.tsx +++ b/frontend/src/components/RoomCompare/CompareCardItem.tsx @@ -1,4 +1,5 @@ import styled from '@emotion/styled'; +import React from 'react'; import { flexCenter, flexColumn } from '@/styles/common'; @@ -18,7 +19,8 @@ const CompareCardItem = ({ label, isLabeled = false, item, height }: Props) => { ); }; -export default CompareCardItem; +const CompareCardItemMemo = React.memo(CompareCardItem); +export default CompareCardItemMemo; const S = { ItemContainer: styled.div<{ height?: number }>` diff --git a/frontend/src/components/RoomCompare/OptionModal.tsx b/frontend/src/components/RoomCompare/OptionModal.tsx new file mode 100644 index 000000000..c0331a49d --- /dev/null +++ b/frontend/src/components/RoomCompare/OptionModal.tsx @@ -0,0 +1,43 @@ +import Modal from '@/components/_common/Modal/Modal'; + +interface Props { + roomTitle1: string; + roomTitle2: string; + isOpen: boolean; + closeModal: () => void; +} + +//TODO: grid 로 수정 +const RoomOptionModal = ({ roomTitle1, roomTitle2, isOpen, closeModal }: Props) => { + return ( + + 옵션 비교 + + + + + + + + + + + + + + + + + + + + + + +
옵션{roomTitle1}{roomTitle2}
냉장고xo
세탁기xo
세탁기xo
+
+
+ ); +}; + +export default RoomOptionModal; diff --git a/frontend/src/pages/RoomComparePage.tsx b/frontend/src/pages/RoomComparePage.tsx index ea11c6043..ac7ef53ca 100644 --- a/frontend/src/pages/RoomComparePage.tsx +++ b/frontend/src/pages/RoomComparePage.tsx @@ -6,8 +6,10 @@ import Header from '@/components/_common/Header/Header'; import Layout from '@/components/_common/layout/Layout'; import CompareMap from '@/components/_common/Map/RoomCompareMap'; import CompareCard from '@/components/RoomCompare/CompareCard'; +import RoomOptionModal from '@/components/RoomCompare/OptionModal'; import RoomMarker from '@/components/RoomCompare/RoomMarker'; import { ROUTE_PATH } from '@/constants/routePath'; +import useModal from '@/hooks/useModal'; import { threeRoomsForCompare } from '@/mocks/fixtures/roomCompare'; import { flexCenter, flexRow } from '@/styles/common'; import theme from '@/styles/theme'; @@ -17,6 +19,7 @@ import { ChecklistCompare } from '@/types/checklistCompare'; const RoomComparePage = () => { const navigate = useNavigate(); // const roomsId = { ...location.state }; + const { isModalOpen, openModal: openOptionModal, closeModal } = useModal(); const [roomList, setRoomList] = useState(threeRoomsForCompare); @@ -49,8 +52,18 @@ const RoomComparePage = () => {
- {roomList?.map((room, index) => )} + {roomList?.map((room, index) => ( + + ))} + {isModalOpen && ( + + )}
); From 454da1cb0f6fc0bcd7b217a09a8d4f75b6a7ac87 Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Tue, 12 Nov 2024 10:48:09 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20=EC=98=B5=EC=85=98=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/assets/icons/answer/bad.tsx | 4 +- frontend/src/assets/icons/answer/good.tsx | 11 ++- .../components/RoomCompare/OptionModal.tsx | 87 ++++++++++++++----- frontend/src/pages/RoomComparePage.tsx | 10 +++ 4 files changed, 85 insertions(+), 27 deletions(-) diff --git a/frontend/src/assets/icons/answer/bad.tsx b/frontend/src/assets/icons/answer/bad.tsx index 1b3f5c9a0..5497fb6d5 100644 --- a/frontend/src/assets/icons/answer/bad.tsx +++ b/frontend/src/assets/icons/answer/bad.tsx @@ -1,6 +1,6 @@ -const Bad = ({ color, ...rest }: React.SVGProps) => { +const Bad = ({ color, width, ...rest }: React.SVGProps) => { return ( - + ) => { +const Good = ({ color, width, ...rest }: React.SVGProps) => { return ( - + ); diff --git a/frontend/src/components/RoomCompare/OptionModal.tsx b/frontend/src/components/RoomCompare/OptionModal.tsx index c0331a49d..02b2144f2 100644 --- a/frontend/src/components/RoomCompare/OptionModal.tsx +++ b/frontend/src/components/RoomCompare/OptionModal.tsx @@ -1,43 +1,84 @@ +import styled from '@emotion/styled'; + +import Bad from '@/assets/icons/answer/bad'; +import Good from '@/assets/icons/answer/good'; import Modal from '@/components/_common/Modal/Modal'; +import { flexCenter, omitText } from '@/styles/common'; +import theme from '@/styles/theme'; interface Props { roomTitle1: string; roomTitle2: string; isOpen: boolean; closeModal: () => void; + hasOptions: hasOption[]; +} + +interface hasOption { + optionName: string; + hasRoom1: boolean; + hasRoom2: boolean; } //TODO: grid 로 수정 -const RoomOptionModal = ({ roomTitle1, roomTitle2, isOpen, closeModal }: Props) => { +const RoomOptionModal = ({ roomTitle1, roomTitle2, isOpen, closeModal, hasOptions }: Props) => { return ( 옵션 비교 - - - - - - - - - - - - - - - - - - - - - -
옵션{roomTitle1}{roomTitle2}
냉장고xo
세탁기xo
세탁기xo
+ + 옵션 + {roomTitle1} + {roomTitle2} + {hasOptions.map(option => { + const { optionName, hasRoom1, hasRoom2 } = option; + return ( + <> + {optionName} + + {hasRoom1 ? ( + + ) : ( + + )} + + + {hasRoom2 ? ( + + ) : ( + + )} + + + ); + })} + 총 개수 + 3개 + 5개 + ); }; export default RoomOptionModal; + +const S = { + Container: styled.div` + display: grid; + grid-template-columns: 0.8fr 1fr 1fr; + `, + ItemText: styled.div` + padding: 0.6rem 1rem; + + ${omitText}; + text-align: center; + border-bottom: 0.05rem solid ${({ theme }) => theme.palette.grey300}; + `, + Item: styled.div` + ${flexCenter}; + height: 2rem; + padding: 0.6rem 1rem; + border-bottom: 0.05rem solid ${({ theme }) => theme.palette.grey300}; + `, +}; diff --git a/frontend/src/pages/RoomComparePage.tsx b/frontend/src/pages/RoomComparePage.tsx index ac7ef53ca..4c5798c1a 100644 --- a/frontend/src/pages/RoomComparePage.tsx +++ b/frontend/src/pages/RoomComparePage.tsx @@ -31,6 +31,15 @@ const RoomComparePage = () => { { latitude: 37.5061912, longitude: 127.1266228 }, ]; + const optionMock = [ + { optionName: '세탁기', hasRoom1: true, hasRoom2: false }, + { optionName: '세탁기', hasRoom1: true, hasRoom2: false }, + { optionName: '세탁기', hasRoom1: true, hasRoom2: false }, + { optionName: '세탁기', hasRoom1: true, hasRoom2: false }, + { optionName: '세탁기', hasRoom1: true, hasRoom2: false }, + { optionName: '세탁기', hasRoom1: true, hasRoom2: false }, + ]; + return ( <>
{ {isModalOpen && ( Date: Tue, 12 Nov 2024 16:52:19 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20=EB=B0=A9=20=EB=B9=84=EA=B5=90=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=94=94?= =?UTF-8?q?=ED=85=8C=EC=9D=BC=20=EB=AA=A8=EB=8B=AC=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EB=B0=8F=20=EB=9D=BC=EC=9A=B0=ED=8A=B8=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/icons/faceIcon/face-icon.good.svg | 18 ++++- .../RoomCompare/CategoryDetailModal.tsx | 19 +++++ .../components/RoomCompare/CategoryScore.tsx | 55 ++++++++++++++ .../components/RoomCompare/CompareCard.tsx | 40 +++++++--- .../RoomCompare/CompareCardCategoryItem.tsx | 51 +++++++++++++ .../RoomCompare/CompareCardItem.tsx | 10 ++- .../components/RoomCompare/OptionModal.tsx | 13 ++-- .../src/components/RoomCompare/RoomMarker.tsx | 19 +++-- .../components/_common/Map/RoomCompareMap.tsx | 4 +- .../Subway/SubwayLineIcon/SubwayLineIcon.tsx | 22 +++--- .../_common/Subway/SubwayStationItem.tsx | 5 +- .../_common/Subway/SubwayStations.tsx | 7 +- frontend/src/mocks/fixtures/roomCompare.ts | 73 ++++++++++++++----- frontend/src/pages/RoomComparePage.tsx | 39 ++++++++-- frontend/src/types/checklistCompare.ts | 2 +- 15 files changed, 302 insertions(+), 75 deletions(-) create mode 100644 frontend/src/components/RoomCompare/CategoryDetailModal.tsx create mode 100644 frontend/src/components/RoomCompare/CategoryScore.tsx create mode 100644 frontend/src/components/RoomCompare/CompareCardCategoryItem.tsx diff --git a/frontend/src/assets/icons/faceIcon/face-icon.good.svg b/frontend/src/assets/icons/faceIcon/face-icon.good.svg index 5ae9767ff..47e287926 100644 --- a/frontend/src/assets/icons/faceIcon/face-icon.good.svg +++ b/frontend/src/assets/icons/faceIcon/face-icon.good.svg @@ -1,6 +1,16 @@ - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/components/RoomCompare/CategoryDetailModal.tsx b/frontend/src/components/RoomCompare/CategoryDetailModal.tsx new file mode 100644 index 000000000..ad2df38c1 --- /dev/null +++ b/frontend/src/components/RoomCompare/CategoryDetailModal.tsx @@ -0,0 +1,19 @@ +import Modal from '@/components/_common/Modal/Modal'; + +interface Props { + isOpen: boolean; + closeModal: () => void; +} + +const CategoryDetailModal = ({ isOpen, closeModal }: Props) => { + return ( + + 카테고리 비교 + +
aa
+
+
+ ); +}; + +export default CategoryDetailModal; diff --git a/frontend/src/components/RoomCompare/CategoryScore.tsx b/frontend/src/components/RoomCompare/CategoryScore.tsx new file mode 100644 index 000000000..8b7c6bdda --- /dev/null +++ b/frontend/src/components/RoomCompare/CategoryScore.tsx @@ -0,0 +1,55 @@ +import styled from '@emotion/styled'; + +import FaceIcon from '@/components/_common/FaceIcon/FaceIcon'; +import FlexBox from '@/components/_common/FlexBox/FlexBox'; +import { boxShadow, flexCenter } from '@/styles/common'; + +const MIN_GOOD_SCORE = 70; +const MIN_SOSO_SCORE = 30; + +interface Props { + roomId: number; + categoryId: number; + score: number | null; + openCategoryModal: (roomId: number, categoryId: number) => void; +} + +const CategoryScore = ({ roomId, categoryId, score, openCategoryModal }: Props) => { + const calcFaceIcon = (score: number | null) => { + if (score === null) return 'NONE'; + if (score >= MIN_GOOD_SCORE) return 'GOOD'; + if (score >= MIN_SOSO_SCORE) return 'SOSO'; + return 'BAD'; + }; + + return ( + + + + + + openCategoryModal(roomId, categoryId)}>{score === null ? '-' : `${score}%`} + + + ); +}; + +export default CategoryScore; + +const S = { + CategoryItemBox: styled.div` + width: 7rem; + + ${flexCenter} + text-align: center; + `, + Score: styled.span` + width: 4rem; + padding: 6px 8px; + border: 1px solid ${({ theme }) => theme.palette.grey300}; + + font-size: ${({ theme }) => theme.text.size.small}; + border-radius: 8px; + ${boxShadow} + `, +}; diff --git a/frontend/src/components/RoomCompare/CompareCard.tsx b/frontend/src/components/RoomCompare/CompareCard.tsx index 27163c439..a2e91c61d 100644 --- a/frontend/src/components/RoomCompare/CompareCard.tsx +++ b/frontend/src/components/RoomCompare/CompareCard.tsx @@ -1,41 +1,61 @@ import styled from '@emotion/styled'; import React from 'react'; -import FaceIcon from '@/components/_common/FaceIcon/FaceIcon'; import SubwayStations from '@/components/_common/Subway/SubwayStations'; +import CategoryScore from '@/components/RoomCompare/CategoryScore'; import CompareCardItem from '@/components/RoomCompare/CompareCardItem'; import { boxShadow, flexColumn, title1, title4 } from '@/styles/common'; import { ChecklistCompare } from '@/types/checklistCompare'; -// import calcEmotions from '@/utils/calcEmotions'; interface Props { room: ChecklistCompare; index: number; openOptionModal: () => void; + openCategoryModal: (roomId: number, categoryId: number) => void; } -const CompareCard = ({ room, openOptionModal }: Props) => { +const EmptyIndicator = ' - '; + +const CompareCard = ({ room, openOptionModal, openCategoryModal }: Props) => { return ( {room.address}} /> - {room.floor}층} /> + {room.floor ? `${room.floor}층` : EmptyIndicator}} /> - {room.deposit}/{room.rent} + {room.deposit ?? EmptyIndicator}/{room.rent ?? EmptyIndicator} } /> + {`${room.structure ?? EmptyIndicator}/${room.size ? `${room.size}평` : EmptyIndicator}`}} + /> {room.contractTerm}개월} /> - } /> + } + /> {room.options.length}개} /> {/* TODO: 모든 카테고리를 다 보여주고 없으면 - 표시로 변경 */} {room.categories.map(category => ( - } /> + + } + /> ))} ); @@ -53,7 +73,6 @@ const S = { align-items: center; gap: 30px; `, - RankWrapper: styled.div` ${flexColumn} gap: 5px; @@ -61,14 +80,11 @@ const S = { Rank: styled.div` ${title1} `, - Score: styled.span` - font-size: ${({ theme }) => theme.text.size.small}; - `, Item: styled.div` display: flex; width: 100%; - font-size: ${({ theme }) => theme.text.size.medium}; + font-size: ${({ theme }) => theme.text.size.small}; line-height: 1.5; letter-spacing: 0.05rem; text-align: center; diff --git a/frontend/src/components/RoomCompare/CompareCardCategoryItem.tsx b/frontend/src/components/RoomCompare/CompareCardCategoryItem.tsx new file mode 100644 index 000000000..f327c62be --- /dev/null +++ b/frontend/src/components/RoomCompare/CompareCardCategoryItem.tsx @@ -0,0 +1,51 @@ +import styled from '@emotion/styled'; +import React from 'react'; + +import { flexCenter, flexColumn } from '@/styles/common'; + +interface Props { + label?: string; + isLabeled?: boolean; + item: React.ReactNode; + height?: number; + score: number; +} + +const CompareCardItem = ({ label, isLabeled = false, item, height, score }: Props) => { + return ( + + {label} + {item} + {score}% + + ); +}; + +export default CompareCardItem; + +const S = { + ItemContainer: styled.div<{ height?: number }>` + width: 100%; + height: ${({ height }) => height && height}rem; + ${flexColumn}; + gap: 1rem; + align-items: center; + `, + ItemText: styled.div` + height: 100%; + + ${flexCenter}; + font-size: ${({ theme }) => theme.text.size.small}; + line-height: 1.5rem; + `, + Score: styled.div` + font-size: ${({ theme }) => theme.text.size.xSmall}; + `, + Label: styled.div<{ isLabeled: boolean }>` + height: 1.5rem; + margin-bottom: 0.5rem; + + color: ${({ theme }) => theme.palette.grey500}; + font-size: ${({ theme }) => theme.text.size.xSmall}; + `, +}; diff --git a/frontend/src/components/RoomCompare/CompareCardItem.tsx b/frontend/src/components/RoomCompare/CompareCardItem.tsx index 75a665f9f..7f7aa2140 100644 --- a/frontend/src/components/RoomCompare/CompareCardItem.tsx +++ b/frontend/src/components/RoomCompare/CompareCardItem.tsx @@ -19,22 +19,26 @@ const CompareCardItem = ({ label, isLabeled = false, item, height }: Props) => { ); }; -const CompareCardItemMemo = React.memo(CompareCardItem); -export default CompareCardItemMemo; +export default CompareCardItem; const S = { ItemContainer: styled.div<{ height?: number }>` width: 100%; height: ${({ height }) => height && height}rem; ${flexColumn}; + gap: 1rem; align-items: center; `, ItemText: styled.div` height: 100%; - ${flexCenter}; + ${flexCenter}; + font-size: ${({ theme }) => theme.text.size.small}; line-height: 1.5rem; `, + Score: styled.div` + font-size: ${({ theme }) => theme.text.size.xSmall}; + `, Label: styled.div<{ isLabeled: boolean }>` height: 1.5rem; margin-bottom: 0.5rem; diff --git a/frontend/src/components/RoomCompare/OptionModal.tsx b/frontend/src/components/RoomCompare/OptionModal.tsx index 02b2144f2..be0e2d355 100644 --- a/frontend/src/components/RoomCompare/OptionModal.tsx +++ b/frontend/src/components/RoomCompare/OptionModal.tsx @@ -27,9 +27,9 @@ const RoomOptionModal = ({ roomTitle1, roomTitle2, isOpen, closeModal, hasOption 옵션 비교 - 옵션 - {roomTitle1} - {roomTitle2} + 옵션 + {roomTitle1} + {roomTitle2} {hasOptions.map(option => { const { optionName, hasRoom1, hasRoom2 } = option; return ( @@ -68,17 +68,18 @@ const S = { display: grid; grid-template-columns: 0.8fr 1fr 1fr; `, - ItemText: styled.div` + ItemText: styled.div<{ isBold?: boolean }>` padding: 0.6rem 1rem; + font-weight: ${({ theme, isBold }) => isBold && theme.text.weight.bold}; ${omitText}; text-align: center; - border-bottom: 0.05rem solid ${({ theme }) => theme.palette.grey300}; + border-bottom: 0.1rem solid ${({ theme }) => theme.palette.grey200}; `, Item: styled.div` ${flexCenter}; height: 2rem; padding: 0.6rem 1rem; - border-bottom: 0.05rem solid ${({ theme }) => theme.palette.grey300}; + border-bottom: 0.1rem solid ${({ theme }) => theme.palette.grey200}; `, }; diff --git a/frontend/src/components/RoomCompare/RoomMarker.tsx b/frontend/src/components/RoomCompare/RoomMarker.tsx index 82793fcb9..ea3eccfc0 100644 --- a/frontend/src/components/RoomCompare/RoomMarker.tsx +++ b/frontend/src/components/RoomCompare/RoomMarker.tsx @@ -1,29 +1,32 @@ import styled from '@emotion/styled'; -import { flexCenter, title2 } from '@/styles/common'; +import { flexCenter } from '@/styles/common'; -const RoomMarker = ({ type, onClick }: { type: 'A' | 'B'; onClick?: () => void }) => { +type Size = 'medium' | 'small'; +const RoomMarker = ({ type, size = 'medium', onClick }: { type: 'A' | 'B'; size?: Size; onClick?: () => void }) => { return ( - + {type} ); }; const S = { - RoomMarker: styled.span<{ type: string }>` + RoomMarker: styled.span<{ type: string; size: Size }>` display: inline; - width: 3rem; - height: 3rem; + width: ${({ size }) => (size === 'medium' ? '2.6rem' : '2rem')}; + height: ${({ size }) => (size === 'medium' ? '2.6rem' : '2rem')}; ${flexCenter}; flex-shrink: 0; background-color: ${({ type, theme }) => (type === 'A' ? theme.palette.yellow600 : theme.palette.green600)}; - border-radius: 50%; - ${title2} color: white; + border-radius: 50%; + + font-weight: ${({ theme }) => theme.text.weight.bold}; + font-size: ${({ theme, size }) => (size === 'medium' ? theme.text.size.medium : theme.text.size.xSmall)}; `, }; diff --git a/frontend/src/components/_common/Map/RoomCompareMap.tsx b/frontend/src/components/_common/Map/RoomCompareMap.tsx index 10316658f..cf1dc1da7 100644 --- a/frontend/src/components/_common/Map/RoomCompareMap.tsx +++ b/frontend/src/components/_common/Map/RoomCompareMap.tsx @@ -114,8 +114,8 @@ const CompareMap = ({ positions }: { positions: Position[] }) => { - handleRoomMarkerClick(0)} /> - handleRoomMarkerClick(1)} /> + handleRoomMarkerClick(0)} /> + handleRoomMarkerClick(1)} /> diff --git a/frontend/src/components/_common/Subway/SubwayLineIcon/SubwayLineIcon.tsx b/frontend/src/components/_common/Subway/SubwayLineIcon/SubwayLineIcon.tsx index b8d1edd3c..e67e16266 100644 --- a/frontend/src/components/_common/Subway/SubwayLineIcon/SubwayLineIcon.tsx +++ b/frontend/src/components/_common/Subway/SubwayLineIcon/SubwayLineIcon.tsx @@ -1,30 +1,33 @@ import styled from '@emotion/styled'; -import { flexCenter, title4 } from '@/styles/common'; +import { flexCenter } from '@/styles/common'; import SUBWAY_LINE_PALLETE, { SubwayLineName } from '@/styles/subway'; +type Size = 'small' | 'medium'; interface Props { lineName: SubwayLineName; + size?: Size; } -const SubwayLineIcon = ({ lineName }: Props) => { +const SubwayLineIcon = ({ lineName, size = 'medium' }: Props) => { const lineColor = SUBWAY_LINE_PALLETE[lineName]; const isNumberTypeSubwayName = lineName.slice(-2) === '호선' && lineName.length === 3; return ( - - {isNumberTypeSubwayName ? lineName.slice(0, lineName.length - 2) : lineName} + + {isNumberTypeSubwayName ? lineName.slice(0, lineName.length - 2) : lineName} ); }; const S = { - Box: styled.span<{ color: string; isCircle: boolean }>` + Box: styled.span<{ color: string; isCircle: boolean; size: Size }>` display: inline-block; - width: ${({ isCircle }) => isCircle && '2rem'}; - height: 2rem; + width: ${({ isCircle, size }) => + isCircle && size === 'medium' ? '2rem' : isCircle && size === 'small' ? '1.4rem' : null}; + height: ${({ size }) => (size === 'medium' ? '2rem' : size === 'small' ? '1.4rem' : null)}; padding: ${({ isCircle }) => (isCircle ? '0.3rem' : '0.3rem 0.6rem')}; border-radius: 2rem; @@ -32,13 +35,14 @@ const S = { text-align: center; `, - Text: styled.span` + Text: styled.span<{ size: Size }>` width: 100%; height: 100%; ${flexCenter}; color: ${({ theme }) => theme.palette.white}; - ${title4} + font-weight: ${({ theme }) => theme.text.weight.semiBold}; + font-size: ${({ theme, size }) => (size === 'small' ? theme.text.size.xSmall : theme.text.size.small)}; `, }; diff --git a/frontend/src/components/_common/Subway/SubwayStationItem.tsx b/frontend/src/components/_common/Subway/SubwayStationItem.tsx index 025bccb04..36d4c0bba 100644 --- a/frontend/src/components/_common/Subway/SubwayStationItem.tsx +++ b/frontend/src/components/_common/Subway/SubwayStationItem.tsx @@ -7,15 +7,16 @@ import { SubwayStation } from '@/types/subway'; interface Props { station: SubwayStation; + size?: 'medium' | 'small'; } -const SubwayStationItem = ({ station }: Props) => { +const SubwayStationItem = ({ station, size }: Props) => { const { stationName, stationLine, walkingTime } = station; return ( - {stationLine?.map(oneLine => )} + {stationLine?.map(oneLine => )} {`${stationName}까지 도보 ${walkingTime}분`} diff --git a/frontend/src/components/_common/Subway/SubwayStations.tsx b/frontend/src/components/_common/Subway/SubwayStations.tsx index 354c97f74..69cb276fc 100644 --- a/frontend/src/components/_common/Subway/SubwayStations.tsx +++ b/frontend/src/components/_common/Subway/SubwayStations.tsx @@ -8,13 +8,16 @@ import { SubwayStation } from '@/types/subway'; interface Props { checklist?: ChecklistInfo; stations: SubwayStation[]; + size?: 'small' | 'medium'; } -const SubwayStations = ({ stations }: Props) => { +const SubwayStations = ({ stations, size }: Props) => { return ( <> {stations?.length ? ( - {stations?.map(station => )} + + {stations?.map(station => )} + ) : ( {'보신 방과 가까운 지하철역을 찾아드릴게요.'} )} diff --git a/frontend/src/mocks/fixtures/roomCompare.ts b/frontend/src/mocks/fixtures/roomCompare.ts index 31023f2b5..5b81e87a2 100644 --- a/frontend/src/mocks/fixtures/roomCompare.ts +++ b/frontend/src/mocks/fixtures/roomCompare.ts @@ -1,13 +1,13 @@ import { nearSubway } from '@/mocks/fixtures/subway'; import { ChecklistCompare } from '@/types/checklistCompare'; -export const threeRoomsForCompare: ChecklistCompare[] = [ +export const roomsForCompare: ChecklistCompare[] = [ { checklistId: 1, roomName: '건대입구역 10분거리 방', address: '서울 송파구 올림픽로35다길 42', buildingName: '한국루터회관', - deposit: undefined, + deposit: 1000, rent: 50, maintenanceFee: 5, contractTerm: 12, @@ -26,13 +26,27 @@ export const threeRoomsForCompare: ChecklistCompare[] = [ { categoryId: 1, categoryName: '청결', - score: 1, + score: 70, }, { categoryId: 2, categoryName: '편의시설', - - score: 2, + score: 60, + }, + { + categoryId: 3, + categoryName: '화장실', + score: 40, + }, + { + categoryId: 4, + categoryName: '보안', + score: 20, + }, + { + categoryId: 4, + categoryName: '보안', + score: null, }, ], geolocation: { @@ -41,32 +55,55 @@ export const threeRoomsForCompare: ChecklistCompare[] = [ }, }, { - checklistId: 2, - roomName: '잠실 A방', - deposit: 1000, - rent: 30, + checklistId: 1, + roomName: '건대입구역 10분거리 방', + address: '서울 송파구 올림픽로35다길 42', + buildingName: '한국루터회관', + deposit: undefined, + rent: 50, + maintenanceFee: 5, + contractTerm: 12, + floor: 5, + realEstate: undefined, + structure: '오픈형 원룸', + size: 25, + floorLevel: '지상', + occupancyMonth: 9, + occupancyPeriod: '중순', + includedMaintenances: [2], + createdAt: '2024-02-01T10:00:00Z', options: [1, 2, 3], nearSubwayStations: nearSubway, categories: [ { categoryId: 1, - categoryName: '청결도', - score: 9, + categoryName: '청결', + score: 20, + }, + { + categoryId: 4, + categoryName: '보안', + score: null, }, { categoryId: 2, categoryName: '편의시설', - - score: 5, + score: 50, + }, + { + categoryId: 3, + categoryName: '화장실', + score: 90, + }, + { + categoryId: 4, + categoryName: '보안', + score: 95, }, ], - address: '서울시 송파구 잠실동', - contractTerm: 12, - floor: 3, - realEstate: '송파 부동산', geolocation: { latitude: 37.5061912, - longitude: 127.0508228, + longitude: 127.2508228, }, }, ]; diff --git a/frontend/src/pages/RoomComparePage.tsx b/frontend/src/pages/RoomComparePage.tsx index 4c5798c1a..b00040586 100644 --- a/frontend/src/pages/RoomComparePage.tsx +++ b/frontend/src/pages/RoomComparePage.tsx @@ -5,12 +5,13 @@ import { useNavigate } from 'react-router-dom'; import Header from '@/components/_common/Header/Header'; import Layout from '@/components/_common/layout/Layout'; import CompareMap from '@/components/_common/Map/RoomCompareMap'; +import CategoryDetailModal from '@/components/RoomCompare/CategoryDetailModal'; import CompareCard from '@/components/RoomCompare/CompareCard'; import RoomOptionModal from '@/components/RoomCompare/OptionModal'; import RoomMarker from '@/components/RoomCompare/RoomMarker'; import { ROUTE_PATH } from '@/constants/routePath'; import useModal from '@/hooks/useModal'; -import { threeRoomsForCompare } from '@/mocks/fixtures/roomCompare'; +import { roomsForCompare } from '@/mocks/fixtures/roomCompare'; import { flexCenter, flexRow } from '@/styles/common'; import theme from '@/styles/theme'; import { Position } from '@/types/address'; @@ -19,9 +20,20 @@ import { ChecklistCompare } from '@/types/checklistCompare'; const RoomComparePage = () => { const navigate = useNavigate(); // const roomsId = { ...location.state }; - const { isModalOpen, openModal: openOptionModal, closeModal } = useModal(); + const { isModalOpen: isOptionModalOpen, openModal: openOptionModal, closeModal: closeOptionModal } = useModal(); + const { isModalOpen: isCategoryModalOpen, openModal: openCategoryModal, closeModal: closeCategoryModal } = useModal(); - const [roomList, setRoomList] = useState(threeRoomsForCompare); + const [roomList, setRoomList] = useState(roomsForCompare); + + const handleOpenCategoryDetailModal = (roomId: number, categoryId: number) => { + openCategoryModal(); + navigate(ROUTE_PATH.roomCompare + `?roomId=${roomId}&categoryId=${categoryId}`); + }; + + const handleCloseategoryDetailModal = () => { + closeCategoryModal(); + navigate(ROUTE_PATH.roomCompare); + }; const handleClickBackward = () => { navigate(ROUTE_PATH.checklistList); @@ -62,18 +74,29 @@ const RoomComparePage = () => { {roomList?.map((room, index) => ( - + ))} - {isModalOpen && ( + {/*방 옵션 비교 모달*/} + {isOptionModalOpen && ( )} + {/*방 카테고리 디테일 모달*/} + {isCategoryModalOpen && ( + + )} ); @@ -100,7 +123,7 @@ const S = { padding: 0.8rem 0; font-weight: ${({ theme }) => theme.text.weight.bold}; - font-size: 2rem; + font-size: 1.8rem; text-align: center; border-radius: 0.8rem; `, diff --git a/frontend/src/types/checklistCompare.ts b/frontend/src/types/checklistCompare.ts index 6664a718f..1ff504334 100644 --- a/frontend/src/types/checklistCompare.ts +++ b/frontend/src/types/checklistCompare.ts @@ -5,7 +5,7 @@ import { SubwayStation } from '@/types/subway'; export interface CategoryScore { categoryId: number; categoryName: string; - score: number; + score: number | null; } export interface ChecklistCompare extends RoomInfo { From 982d21be507aca48d108c8a57b14cf2ec6762ed1 Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Fri, 15 Nov 2024 08:21:38 +0900 Subject: [PATCH 09/11] =?UTF-8?q?fix:=20=EC=98=B5=EC=85=98=20=EB=B9=84?= =?UTF-8?q?=EA=B5=90=20=EB=AA=A8=EB=8B=AC=20css=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/RoomCompare/CategoryDetailModal.tsx | 2 +- .../{OptionModal.tsx => OptionDetailModal.tsx} | 13 ++++++------- frontend/src/pages/RoomComparePage.tsx | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) rename frontend/src/components/RoomCompare/{OptionModal.tsx => OptionDetailModal.tsx} (83%) diff --git a/frontend/src/components/RoomCompare/CategoryDetailModal.tsx b/frontend/src/components/RoomCompare/CategoryDetailModal.tsx index ad2df38c1..576d630a1 100644 --- a/frontend/src/components/RoomCompare/CategoryDetailModal.tsx +++ b/frontend/src/components/RoomCompare/CategoryDetailModal.tsx @@ -10,7 +10,7 @@ const CategoryDetailModal = ({ isOpen, closeModal }: Props) => { 카테고리 비교 -
aa
+
카테고리 비교 내용이 들어갑니다.
); diff --git a/frontend/src/components/RoomCompare/OptionModal.tsx b/frontend/src/components/RoomCompare/OptionDetailModal.tsx similarity index 83% rename from frontend/src/components/RoomCompare/OptionModal.tsx rename to frontend/src/components/RoomCompare/OptionDetailModal.tsx index be0e2d355..7d8dddb10 100644 --- a/frontend/src/components/RoomCompare/OptionModal.tsx +++ b/frontend/src/components/RoomCompare/OptionDetailModal.tsx @@ -20,8 +20,7 @@ interface hasOption { hasRoom2: boolean; } -//TODO: grid 로 수정 -const RoomOptionModal = ({ roomTitle1, roomTitle2, isOpen, closeModal, hasOptions }: Props) => { +const OptionDetailModal = ({ roomTitle1, roomTitle2, isOpen, closeModal, hasOptions }: Props) => { return ( 옵션 비교 @@ -53,28 +52,28 @@ const RoomOptionModal = ({ roomTitle1, roomTitle2, isOpen, closeModal, hasOption ); })} 총 개수 - 3개 - 5개 + 3개 + 5개
); }; -export default RoomOptionModal; +export default OptionDetailModal; const S = { Container: styled.div` display: grid; grid-template-columns: 0.8fr 1fr 1fr; `, - ItemText: styled.div<{ isBold?: boolean }>` + ItemText: styled.div<{ isBold?: boolean; hasBorder?: boolean }>` padding: 0.6rem 1rem; font-weight: ${({ theme, isBold }) => isBold && theme.text.weight.bold}; ${omitText}; text-align: center; - border-bottom: 0.1rem solid ${({ theme }) => theme.palette.grey200}; + border-bottom: ${({ hasBorder, theme }) => hasBorder && `0.1rem solid ${theme.palette.grey200}};`}; `, Item: styled.div` ${flexCenter}; diff --git a/frontend/src/pages/RoomComparePage.tsx b/frontend/src/pages/RoomComparePage.tsx index b00040586..bc576ea0b 100644 --- a/frontend/src/pages/RoomComparePage.tsx +++ b/frontend/src/pages/RoomComparePage.tsx @@ -7,7 +7,7 @@ import Layout from '@/components/_common/layout/Layout'; import CompareMap from '@/components/_common/Map/RoomCompareMap'; import CategoryDetailModal from '@/components/RoomCompare/CategoryDetailModal'; import CompareCard from '@/components/RoomCompare/CompareCard'; -import RoomOptionModal from '@/components/RoomCompare/OptionModal'; +import OptionDetailModal from '@/components/RoomCompare/OptionDetailModal'; import RoomMarker from '@/components/RoomCompare/RoomMarker'; import { ROUTE_PATH } from '@/constants/routePath'; import useModal from '@/hooks/useModal'; @@ -85,7 +85,7 @@ const RoomComparePage = () => { {/*방 옵션 비교 모달*/} {isOptionModalOpen && ( - Date: Fri, 15 Nov 2024 08:52:08 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EC=A7=80=EB=8F=84=20=EA=B1=B0?= =?UTF-8?q?=EB=A6=AC=20=EC=9C=A0=ED=8B=B8=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F?= =?UTF-8?q?=20map=20=EB=A1=9C=EC=A7=81=20=EC=9D=BC=EB=B6=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/RoomCompare/CompareCard.tsx | 6 +-- .../src/components/_common/Map/AddressMap.tsx | 13 +++--- .../components/_common/Map/RealTimeMap.tsx | 10 ++++- .../components/_common/Map/RoomCompareMap.tsx | 42 ++++--------------- frontend/src/pages/RoomComparePage.tsx | 15 +++++-- frontend/src/utils/createKakaoMapElements.ts | 18 +------- frontend/src/utils/mapHelper.ts | 27 ++++++++++++ 7 files changed, 65 insertions(+), 66 deletions(-) create mode 100644 frontend/src/utils/mapHelper.ts diff --git a/frontend/src/components/RoomCompare/CompareCard.tsx b/frontend/src/components/RoomCompare/CompareCard.tsx index a2e91c61d..080d1f05f 100644 --- a/frontend/src/components/RoomCompare/CompareCard.tsx +++ b/frontend/src/components/RoomCompare/CompareCard.tsx @@ -1,5 +1,4 @@ import styled from '@emotion/styled'; -import React from 'react'; import SubwayStations from '@/components/_common/Subway/SubwayStations'; import CategoryScore from '@/components/RoomCompare/CategoryScore'; @@ -42,7 +41,7 @@ const CompareCard = ({ room, openOptionModal, openCategoryModal }: Props) => { label={'옵션'} item={{room.options.length}개} /> - {/* TODO: 모든 카테고리를 다 보여주고 없으면 - 표시로 변경 */} + {/*카테고리별 질문 평점 섹션*/} {room.categories.map(category => ( { ); }; -const CompareCardMemo = React.memo(CompareCard); -export default CompareCardMemo; +export default CompareCard; const S = { Container: styled.div` diff --git a/frontend/src/components/_common/Map/AddressMap.tsx b/frontend/src/components/_common/Map/AddressMap.tsx index 4cb1931d6..2e33c86d6 100644 --- a/frontend/src/components/_common/Map/AddressMap.tsx +++ b/frontend/src/components/_common/Map/AddressMap.tsx @@ -11,7 +11,7 @@ import loadExternalScriptWithCallback from '../../../utils/loadScript'; /* eslint-disable @typescript-eslint/no-explicit-any */ const AddressMap = ({ location }: { location: string }) => { - const mapContainerRef = useRef(null); + const mapElement = useRef(null); const markerRef = useRef(null); const { createMarker } = createKakaoMapElements(); @@ -21,16 +21,17 @@ const AddressMap = ({ location }: { location: string }) => { const { kakao } = window as any; kakao.maps.load(() => { - if (!mapContainerRef.current) return; + if (!mapElement.current) return; const mapOption = { center: new kakao.maps.LatLng(DEFAULT_POSITION.latitude, DEFAULT_POSITION.longitude), level: 3, }; - // 지도 생성 - const map = new kakao.maps.Map(mapContainerRef.current, mapOption); + + const map = new kakao.maps.Map(mapElement.current, mapOption); + // 주소-좌표 변환 객체 생성 const geocoder = new kakao.maps.services.Geocoder(); - // 주소로 좌표 검색 + // 주소로 좌표 검색하여 해당 좌표로 중심 이동 geocoder.addressSearch(location, (result: any, status: any) => { if (status === kakao.maps.services.Status.OK) { const coords = new kakao.maps.LatLng(result[0].y, result[0].x); @@ -59,7 +60,7 @@ const AddressMap = ({ location }: { location: string }) => { <> {location && ( - + diff --git a/frontend/src/components/_common/Map/RealTimeMap.tsx b/frontend/src/components/_common/Map/RealTimeMap.tsx index 4928199ca..d8aac2aad 100644 --- a/frontend/src/components/_common/Map/RealTimeMap.tsx +++ b/frontend/src/components/_common/Map/RealTimeMap.tsx @@ -4,6 +4,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { BangBangCryIcon } from '@/assets/assets'; import Button from '@/components/_common/Button/Button'; import { LoadingSpinner } from '@/components/_common/LoadingSpinner/LoadingSpinner'; +import { DEFAULT_POSITION } from '@/constants/map'; import { flexCenter } from '@/styles/common'; import { Position } from '@/types/address'; import createKakaoMapElements from '@/utils/createKakaoMapElements'; @@ -32,7 +33,7 @@ const RealTimeMap = ({ const infoWindowRef = useRef(null); const mapElement = useRef(null); - const { createMap, createMarker, createInfoWindow } = createKakaoMapElements(); + const { createMarker, createInfoWindow } = createKakaoMapElements(); const [realTimeLocationState, setRealTimeLocationState] = useState('loading'); const initializeMap = () => { @@ -40,7 +41,12 @@ const RealTimeMap = ({ kakao.maps.load(() => { /*카카오 맵 생성 */ - const map = createMap(kakao); + const mapOption = { + center: new kakao.maps.LatLng(DEFAULT_POSITION.latitude, DEFAULT_POSITION.longitude), + level: 3, + }; + + const map = new kakao.maps.Map(mapElement.current, mapOption); mapRef.current = map; /*마커 생성*/ diff --git a/frontend/src/components/_common/Map/RoomCompareMap.tsx b/frontend/src/components/_common/Map/RoomCompareMap.tsx index cf1dc1da7..eba7603ca 100644 --- a/frontend/src/components/_common/Map/RoomCompareMap.tsx +++ b/frontend/src/components/_common/Map/RoomCompareMap.tsx @@ -4,13 +4,13 @@ import { useEffect, useRef } from 'react'; import RoomMarker from '@/components/RoomCompare/RoomMarker'; import { Position } from '@/types/address'; import createKakaoMapElements from '@/utils/createKakaoMapElements'; +import { getDistanceFromLatLonInKm, getMapLevel } from '@/utils/mapHelper'; import loadExternalScriptWithCallback from '../../../utils/loadScript'; /* eslint-disable @typescript-eslint/no-explicit-any */ - -const CompareMap = ({ positions }: { positions: Position[] }) => { - const mapContainerRef = useRef(null); +const RoomCompareMap = ({ positions }: { positions: Position[] }) => { + const mapElement = useRef(null); const mapRef = useRef(null); useEffect(() => { @@ -22,21 +22,6 @@ const CompareMap = ({ positions }: { positions: Position[] }) => { longitude: (positions[0].longitude + positions[1].longitude) / 2, }; - function getDistanceFromLatLonInKm(lat1: number, lng1: number, lat2: number, lng2: number) { - function deg2rad(deg: any) { - return deg * (Math.PI / 180); - } - const R = 6371; - const dLat = deg2rad(lat2 - lat1); - const dLon = deg2rad(lng2 - lng1); - const a = - Math.sin(dLat / 2) * Math.sin(dLat / 2) + - Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); - const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - const d = R * c; - return d; - } - const diff = getDistanceFromLatLonInKm( positions[0].latitude, positions[0].longitude, @@ -44,26 +29,17 @@ const CompareMap = ({ positions }: { positions: Position[] }) => { positions[1].longitude, ); - // 거리에 따른 적절한 지도 level 설정 - const getMapLevel = (distance: number) => { - if (distance < 0.5) return 3; - if (distance < 0.7) return 4; - if (distance < 1) return 5; - if (distance < 3) return 6; - if (distance < 5) return 7; - if (distance < 12) return 9; - return 10; - }; - + /* 두 지점의 거리를 재서 적당한 Map level 설정 */ const mapLevel = getMapLevel(diff); kakao.maps.load(() => { - if (!mapContainerRef.current) return; + if (!mapElement.current) return; const mapOption = { center: new kakao.maps.LatLng(centerOfPosition.latitude, centerOfPosition.longitude), level: mapLevel, }; - const map = new kakao.maps.Map(mapContainerRef.current, mapOption); + + const map = new kakao.maps.Map(mapElement.current, mapOption); mapRef.current = map; const { createMarker } = createKakaoMapElements(); @@ -112,7 +88,7 @@ const CompareMap = ({ positions }: { positions: Position[] }) => { <> {location && ( - + handleRoomMarkerClick(0)} /> handleRoomMarkerClick(1)} /> @@ -151,4 +127,4 @@ const S = { `, }; -export default CompareMap; +export default RoomCompareMap; diff --git a/frontend/src/pages/RoomComparePage.tsx b/frontend/src/pages/RoomComparePage.tsx index bc576ea0b..4273508b5 100644 --- a/frontend/src/pages/RoomComparePage.tsx +++ b/frontend/src/pages/RoomComparePage.tsx @@ -1,10 +1,10 @@ import styled from '@emotion/styled'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import Header from '@/components/_common/Header/Header'; import Layout from '@/components/_common/layout/Layout'; -import CompareMap from '@/components/_common/Map/RoomCompareMap'; +import RoomCompareMap from '@/components/_common/Map/RoomCompareMap'; import CategoryDetailModal from '@/components/RoomCompare/CategoryDetailModal'; import CompareCard from '@/components/RoomCompare/CompareCard'; import OptionDetailModal from '@/components/RoomCompare/OptionDetailModal'; @@ -23,7 +23,12 @@ const RoomComparePage = () => { const { isModalOpen: isOptionModalOpen, openModal: openOptionModal, closeModal: closeOptionModal } = useModal(); const { isModalOpen: isCategoryModalOpen, openModal: openCategoryModal, closeModal: closeCategoryModal } = useModal(); - const [roomList, setRoomList] = useState(roomsForCompare); + const [roomList, setRoomList] = useState([]); + + //TODO: 나중에 비교 데이터 요청해서 받아오는 로직으로 수정 + useEffect(() => { + setRoomList(roomsForCompare); + }); const handleOpenCategoryDetailModal = (roomId: number, categoryId: number) => { openCategoryModal(); @@ -52,6 +57,8 @@ const RoomComparePage = () => { { optionName: '세탁기', hasRoom1: true, hasRoom2: false }, ]; + if (!roomList.length) return
loading
; + return ( <>
{ - + {roomList?.map((room, index) => ( { - const createMap = (kakao: any) => { - const container = document.getElementById('map'); - if (!container) return; - - const center = new kakao.maps.LatLng(DEFAULT_POSITION.latitude, DEFAULT_POSITION.longitude); - - const options = { - center, - level: 3, - }; - - return new kakao.maps.Map(container, options); - }; - const createMarker = (kakao: any, map: any, position: any, color: 'primary' | 'secondary', title?: string) => { const imageSrc = { primary: 'https://github.com/user-attachments/assets/cd52185e-f22f-4d8c-9528-cf9f0593bfaf', @@ -44,7 +28,7 @@ const createKakaoMapElements = () => { return infoWindow; }; - return { createMap, createMarker, createInfoWindow }; + return { createMarker, createInfoWindow }; }; export default createKakaoMapElements; diff --git a/frontend/src/utils/mapHelper.ts b/frontend/src/utils/mapHelper.ts new file mode 100644 index 000000000..0ba256f95 --- /dev/null +++ b/frontend/src/utils/mapHelper.ts @@ -0,0 +1,27 @@ +/*두 개의 지점의 거리를 재는 로직*/ +/* RoomCompareMap에서 사용 */ +export const getDistanceFromLatLonInKm = (lat1: number, lng1: number, lat2: number, lng2: number) => { + const deg2rad = (deg: number) => { + return deg * (Math.PI / 180); + }; + const R = 6371; + const dLat = deg2rad(lat2 - lat1); + const dLon = deg2rad(lng2 - lng1); + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + const d = R * c; + return d; +}; + +/* 거리에 따른 적절한 지도 level 설정 */ +export const getMapLevel = (distance: number) => { + if (distance < 0.5) return 3; + if (distance < 0.7) return 4; + if (distance < 1) return 5; + if (distance < 3) return 6; + if (distance < 5) return 7; + if (distance < 12) return 9; + return 10; +}; From 34b0b298a610d5d832701d120d6b911a1793bb4f Mon Sep 17 00:00:00 2001 From: ooherin <555ohr@naver.com> Date: Sat, 16 Nov 2024 11:08:44 +0900 Subject: [PATCH 11/11] =?UTF-8?q?fix:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/url.ts | 2 ++ frontend/src/assets/icons/answer/bad.tsx | 9 ++++++++- frontend/src/components/RoomCompare/CategoryScore.tsx | 4 +--- frontend/src/components/RoomCompare/CompareCard.tsx | 11 ++++++----- .../_common/Subway/SubwayLineIcon/SubwayLineIcon.tsx | 8 ++++---- frontend/src/constants/system.ts | 6 ++++++ frontend/src/mocks/handlers/roomCompare.ts | 2 +- 7 files changed, 28 insertions(+), 14 deletions(-) diff --git a/frontend/src/apis/url.ts b/frontend/src/apis/url.ts index 7bf577230..71c936628 100644 --- a/frontend/src/apis/url.ts +++ b/frontend/src/apis/url.ts @@ -14,6 +14,8 @@ export const ENDPOINT = { CHECKLIST_CUSTOM: '/custom-checklist', CHECKLIST_ID: (id: number) => `/checklists/${id}`, CHECKLIST_ID_V1: (id: number) => `/v1/checklists/${id}`, + //compare + CHECKLIST_COMPARE: (roomId1: number, roomId2: number) => `/v1/checklists/compare?id=${roomId1}&id=${roomId2}`, // like LIKE: (id: number | ':id') => `/checklists/${id}/like`, diff --git a/frontend/src/assets/icons/answer/bad.tsx b/frontend/src/assets/icons/answer/bad.tsx index 5497fb6d5..7bd0fa527 100644 --- a/frontend/src/assets/icons/answer/bad.tsx +++ b/frontend/src/assets/icons/answer/bad.tsx @@ -1,6 +1,13 @@ const Bad = ({ color, width, ...rest }: React.SVGProps) => { return ( - + void; } -const EmptyIndicator = ' - '; - const CompareCard = ({ room, openOptionModal, openCategoryModal }: Props) => { return ( {room.address}} /> - {room.floor ? `${room.floor}층` : EmptyIndicator}} /> + {room.floor ? `${room.floor}층` : EMPTY_INDICATOR}} /> - {room.deposit ?? EmptyIndicator}/{room.rent ?? EmptyIndicator} + {room.deposit ?? EMPTY_INDICATOR}/{room.rent ?? EMPTY_INDICATOR} } /> {`${room.structure ?? EmptyIndicator}/${room.size ? `${room.size}평` : EmptyIndicator}`}} + item={ + {`${room.structure ?? EMPTY_INDICATOR}/${room.size ? `${room.size}평` : EMPTY_INDICATOR}`} + } /> {room.contractTerm}개월} /> { const lineColor = SUBWAY_LINE_PALLETE[lineName]; @@ -24,10 +26,8 @@ const SubwayLineIcon = ({ lineName, size = 'medium' }: Props) => { const S = { Box: styled.span<{ color: string; isCircle: boolean; size: Size }>` display: inline-block; - - width: ${({ isCircle, size }) => - isCircle && size === 'medium' ? '2rem' : isCircle && size === 'small' ? '1.4rem' : null}; - height: ${({ size }) => (size === 'medium' ? '2rem' : size === 'small' ? '1.4rem' : null)}; + width: ${({ isCircle, size }) => isCircle && sizeMap[size]}; + height: ${({ isCircle, size }) => isCircle && sizeMap[size]}; padding: ${({ isCircle }) => (isCircle ? '0.3rem' : '0.3rem 0.6rem')}; border-radius: 2rem; diff --git a/frontend/src/constants/system.ts b/frontend/src/constants/system.ts index c6845f2c5..74bf9dd79 100644 --- a/frontend/src/constants/system.ts +++ b/frontend/src/constants/system.ts @@ -16,3 +16,9 @@ export const DEFAULT_CHECKLIST_TAB_PAGE = -1; export const STALE_TIME = 5 * 60 * 1000; export const INTERSECTION_CONFIG = { threshold: 0.5, rootMargin: '5px' }; + +export const EMPTY_INDICATOR = ' - '; + +export const MIN_GOOD_SCORE = 70; + +export const MIN_SOSO_SCORE = 30; diff --git a/frontend/src/mocks/handlers/roomCompare.ts b/frontend/src/mocks/handlers/roomCompare.ts index 78a5c4285..22c04876c 100644 --- a/frontend/src/mocks/handlers/roomCompare.ts +++ b/frontend/src/mocks/handlers/roomCompare.ts @@ -4,7 +4,7 @@ import { BASE_URL, ENDPOINT } from '@/apis/url'; import { roomsForCompare } from '@/mocks/fixtures/roomCompare'; export const roomCompareHandlers = [ - http.get(BASE_URL + ENDPOINT.CHECKLIST_QUESTION, () => { + http.get(BASE_URL + ENDPOINT.CHECKLIST_COMPARE(1, 2), () => { return HttpResponse.json(roomsForCompare, { status: 200 }); }), ];