From d9c89665ce66cb298483616dad404561791516c3 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 15:55:08 +0900 Subject: [PATCH 01/30] =?UTF-8?q?feat:=20react-daum-postcode=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/package.json b/package.json index 0aa46f2..953ae8e 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "next-themes": "^0.4.6", "prettier": "^3.6.2", "react": "^19.1.1", + "react-daum-postcode": "^3.2.0", "react-dom": "^19.1.1", "react-hook-form": "^7.62.0", "react-kakao-maps-sdk": "^1.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e67a427..8be35bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,6 +56,9 @@ importers: react: specifier: ^19.1.1 version: 19.1.1 + react-daum-postcode: + specifier: ^3.2.0 + version: 3.2.0(react@19.1.1) react-dom: specifier: ^19.1.1 version: 19.1.1(react@19.1.1) @@ -2588,6 +2591,11 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + react-daum-postcode@3.2.0: + resolution: {integrity: sha512-NHY8TUicZXMqykbKYT8kUo2PEU7xu1DFsdRmyWJrLEUY93Xhd3rEdoJ7vFqrvs+Grl9wIm9Byxh3bI+eZxepMQ==} + peerDependencies: + react: '>=16.8.0' + react-dom@19.1.1: resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} peerDependencies: @@ -5377,6 +5385,10 @@ snapshots: queue-microtask@1.2.3: {} + react-daum-postcode@3.2.0(react@19.1.1): + dependencies: + react: 19.1.1 + react-dom@19.1.1(react@19.1.1): dependencies: react: 19.1.1 From f82425ed40c7951233df0146f92b1b46e8e75b5f Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 15:55:34 +0900 Subject: [PATCH 02/30] =?UTF-8?q?feat:=20=EC=A3=BC=EC=86=8C=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=A0=95=EC=9D=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/types/address.type.ts | 6 ++++++ src/features/main/types/index.ts | 1 + 2 files changed, 7 insertions(+) create mode 100644 src/features/main/types/address.type.ts diff --git a/src/features/main/types/address.type.ts b/src/features/main/types/address.type.ts new file mode 100644 index 0000000..66f761b --- /dev/null +++ b/src/features/main/types/address.type.ts @@ -0,0 +1,6 @@ +export type AddressType = { + address: string; + addressType: string; + bname: string; + buildingName: string; +}; diff --git a/src/features/main/types/index.ts b/src/features/main/types/index.ts index 8aefa50..af05bf5 100644 --- a/src/features/main/types/index.ts +++ b/src/features/main/types/index.ts @@ -1,2 +1,3 @@ +export * from './address.type'; export * from './house-types.type'; export * from './properties-type.type'; From d530ceb2b6b8afc24c4006964b74882dbf3b221d Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 15:56:13 +0900 Subject: [PATCH 03/30] =?UTF-8?q?feat:=20=EC=A3=BC=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=9B=85(useAddressSearch)=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/hooks/index.ts | 1 + src/features/main/hooks/useAddressSearch.ts | 60 +++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/features/main/hooks/useAddressSearch.ts diff --git a/src/features/main/hooks/index.ts b/src/features/main/hooks/index.ts index 6eb5c2e..84653d2 100644 --- a/src/features/main/hooks/index.ts +++ b/src/features/main/hooks/index.ts @@ -1 +1,2 @@ export * from './useChartConfig'; +export * from './useAddressSearch'; diff --git a/src/features/main/hooks/useAddressSearch.ts b/src/features/main/hooks/useAddressSearch.ts new file mode 100644 index 0000000..a022f04 --- /dev/null +++ b/src/features/main/hooks/useAddressSearch.ts @@ -0,0 +1,60 @@ +import { useEffect, useState } from 'react'; +import { useFormContext } from 'react-hook-form'; + +import type { SearchAddressType } from '../model'; +import type { AddressType } from '../types'; + +export const useAddressSearch = () => { + const [isOpen, setIsOpen] = useState(false); + + const form = useFormContext(); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape' && isOpen) { + setIsOpen(false); + } + }; + + if (isOpen) { + document.addEventListener('keydown', handleKeyDown); + } + + return () => { + document.removeEventListener('keydown', handleKeyDown); + }; + }, [isOpen]); + + const completeAddress = (data: AddressType) => { + let fullAddress = data.address; + let extraAddress = ''; + + if (data.addressType === 'R') { + if (data.bname !== '') { + extraAddress += data.bname; + } + if (data.buildingName !== '') { + extraAddress += extraAddress !== '' ? `, ${data.buildingName}` : data.buildingName; + } + fullAddress += extraAddress !== '' ? ` (${extraAddress})` : ''; + } + + form.setValue('address', fullAddress); + setIsOpen(false); + }; + + const openSearch = () => { + setIsOpen(true); + }; + + const closeSearch = () => { + setIsOpen(false); + }; + + return { + isOpen, + completeAddress, + openSearch, + closeSearch, + }; +}; From 5d43dafe4ad7a51dd841f87ba6054c1720e25dd5 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 15:56:25 +0900 Subject: [PATCH 04/30] =?UTF-8?q?feat:=20=EC=A3=BC=EC=86=8C=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=ED=95=84=EB=93=9C=EC=97=90=20=EC=A3=BC=EC=86=8C=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20UI=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/components/common/AddressField.tsx | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/features/main/components/common/AddressField.tsx b/src/features/main/components/common/AddressField.tsx index 9dfc80e..89c059b 100644 --- a/src/features/main/components/common/AddressField.tsx +++ b/src/features/main/components/common/AddressField.tsx @@ -1,12 +1,19 @@ +import DaumPostcode from 'react-daum-postcode'; import { useFormContext } from 'react-hook-form'; -import { FormField, FormItem, FormLabel, FormMessage, Input } from '@/shared'; +import { X } from 'lucide-react'; + +import { Button, FormField, FormItem, FormLabel, FormMessage, Input } from '@/shared'; import { FORM_FIELDS, LABEL_TEXTS, PLACEHOLDER_TEXTS } from '../../constants'; +import { useAddressSearch } from '../../hooks'; import { type SearchAddressType } from '../../model'; export const AddressField = () => { + const { isOpen, completeAddress, openSearch, closeSearch } = useAddressSearch(); + const form = useFormContext(); + return ( { render={({ field }) => ( {LABEL_TEXTS.ADDRESS} - + + + {isOpen && ( +
+
+
+

주소 검색

+ +
+ +
+
+ )}
)} /> From 3ce6ee951d786b6c165537b3d209b1d5559a1cba Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 17:01:13 +0900 Subject: [PATCH 05/30] =?UTF-8?q?feat:=20=EC=9E=A5=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/apis/index.ts | 1 + src/features/main/apis/search-place.api.ts | 44 ++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/features/main/apis/search-place.api.ts diff --git a/src/features/main/apis/index.ts b/src/features/main/apis/index.ts index af484f6..476a7d2 100644 --- a/src/features/main/apis/index.ts +++ b/src/features/main/apis/index.ts @@ -1 +1,2 @@ export * from './diagnosis.api'; +export * from './search-place.api'; diff --git a/src/features/main/apis/search-place.api.ts b/src/features/main/apis/search-place.api.ts new file mode 100644 index 0000000..086dca6 --- /dev/null +++ b/src/features/main/apis/search-place.api.ts @@ -0,0 +1,44 @@ +import { fetchInstance } from '@/shared'; + +export const SEARCH_PLACE_API_PATH = '/api/places/search'; + +export interface SearchPlaceAPIRequest { + q: string; + radiusKm: number; + includeExternal: boolean; + page: number; + size: number; +} + +export interface SearchPlaceAPIResponse { + content: { + placeId: number; + landlordId: number; + address: string; + addressDetail: string; + lat: number; + lng: number; + createdAt: string; + updatedAt: string; + externalProvider: string; + externalPlaceId: string; + }[]; + page: number; + size: number; + totalElements: number; + totalPages: number; +} + +export const searchPlaceAPI = async ({ + q, + radiusKm, + includeExternal, + page, + size, +}: SearchPlaceAPIRequest) => { + const response = await fetchInstance.get(SEARCH_PLACE_API_PATH, { + params: { q, radiusKm, includeExternal, page, size }, + }); + + return response.data; +}; From 36088760f36853450d1ce807c766667a357da8d5 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 17:06:14 +0900 Subject: [PATCH 06/30] =?UTF-8?q?feat:=20=EC=9E=A5=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=9B=85(useGetSearchPlace)=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/hooks/index.ts | 1 + src/features/main/hooks/useGetSearchPlace.ts | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/features/main/hooks/useGetSearchPlace.ts diff --git a/src/features/main/hooks/index.ts b/src/features/main/hooks/index.ts index 84653d2..0d9865d 100644 --- a/src/features/main/hooks/index.ts +++ b/src/features/main/hooks/index.ts @@ -1,2 +1,3 @@ export * from './useChartConfig'; export * from './useAddressSearch'; +export * from './useGetSearchPlace'; diff --git a/src/features/main/hooks/useGetSearchPlace.ts b/src/features/main/hooks/useGetSearchPlace.ts new file mode 100644 index 0000000..0473928 --- /dev/null +++ b/src/features/main/hooks/useGetSearchPlace.ts @@ -0,0 +1,18 @@ +import { useQuery } from '@tanstack/react-query'; + +import { type SearchPlaceAPIRequest, searchPlaceAPI } from '../apis'; + +export const SearchPlaceQueryKey = ['searchPlace']; + +export const useGetSearchPlace = ({ + q, + radiusKm, + includeExternal, + page, + size, +}: SearchPlaceAPIRequest) => { + return useQuery({ + queryKey: SearchPlaceQueryKey, + queryFn: () => searchPlaceAPI({ q, radiusKm, includeExternal, page, size }), + }); +}; From 1281a179802c5dba869183575d7b36220ac88940 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 17:14:27 +0900 Subject: [PATCH 07/30] =?UTF-8?q?feat:=20=EC=9E=A5=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=83=80=EC=9E=85=20=EC=A0=95=EC=9D=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/types/index.ts | 1 + src/features/main/types/search-place.type.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/features/main/types/search-place.type.ts diff --git a/src/features/main/types/index.ts b/src/features/main/types/index.ts index af05bf5..40f5843 100644 --- a/src/features/main/types/index.ts +++ b/src/features/main/types/index.ts @@ -1,3 +1,4 @@ export * from './address.type'; export * from './house-types.type'; export * from './properties-type.type'; +export * from './search-place.type'; diff --git a/src/features/main/types/search-place.type.ts b/src/features/main/types/search-place.type.ts new file mode 100644 index 0000000..1aace4f --- /dev/null +++ b/src/features/main/types/search-place.type.ts @@ -0,0 +1,12 @@ +export type SearchPlaceType = { + placeId: number; + landlordId: number; + address: string; + addressDetail: string; + lat: number; + lng: number; + createdAt: string; + updatedAt: string; + externalProvider: string; + externalPlaceId: string; +}; From 633ee611feaa2a644de3dec4ec31aa9eb52b9771 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:39:13 +0900 Subject: [PATCH 08/30] =?UTF-8?q?feat:=20zustand=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 ++- pnpm-lock.yaml | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 953ae8e..1d7a530 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,8 @@ "tailwind-merge": "^3.3.1", "tailwind-scrollbar-hide": "^4.0.0", "tailwindcss": "^4.1.12", - "zod": "^4.0.17" + "zod": "^4.0.17", + "zustand": "^5.0.8" }, "devDependencies": { "@eslint/js": "^9.33.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8be35bb..5c4c33a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,6 +89,9 @@ importers: zod: specifier: ^4.0.17 version: 4.0.17 + zustand: + specifier: ^5.0.8 + version: 5.0.8(@types/react@19.1.10)(immer@10.1.1)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) devDependencies: '@eslint/js': specifier: ^9.33.0 @@ -3092,6 +3095,24 @@ packages: zod@4.0.17: resolution: {integrity: sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ==} + zustand@5.0.8: + resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: '@babel/code-frame@7.27.1': @@ -5990,3 +6011,10 @@ snapshots: yocto-queue@0.1.0: {} zod@4.0.17: {} + + zustand@5.0.8(@types/react@19.1.10)(immer@10.1.1)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)): + optionalDependencies: + '@types/react': 19.1.10 + immer: 10.1.1 + react: 19.1.1 + use-sync-external-store: 1.5.0(react@19.1.1) From 16327a3c2d1ceb4eb482a222e610a47fccb0b07e Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:39:29 +0900 Subject: [PATCH 09/30] =?UTF-8?q?feat:=20=EC=9E=A5=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20API=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=ED=9B=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/apis/index.ts | 1 - src/features/main/apis/search-place.api.ts | 44 ---------------------- src/features/main/index.ts | 1 + 3 files changed, 1 insertion(+), 45 deletions(-) delete mode 100644 src/features/main/apis/search-place.api.ts diff --git a/src/features/main/apis/index.ts b/src/features/main/apis/index.ts index 476a7d2..af484f6 100644 --- a/src/features/main/apis/index.ts +++ b/src/features/main/apis/index.ts @@ -1,2 +1 @@ export * from './diagnosis.api'; -export * from './search-place.api'; diff --git a/src/features/main/apis/search-place.api.ts b/src/features/main/apis/search-place.api.ts deleted file mode 100644 index 086dca6..0000000 --- a/src/features/main/apis/search-place.api.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { fetchInstance } from '@/shared'; - -export const SEARCH_PLACE_API_PATH = '/api/places/search'; - -export interface SearchPlaceAPIRequest { - q: string; - radiusKm: number; - includeExternal: boolean; - page: number; - size: number; -} - -export interface SearchPlaceAPIResponse { - content: { - placeId: number; - landlordId: number; - address: string; - addressDetail: string; - lat: number; - lng: number; - createdAt: string; - updatedAt: string; - externalProvider: string; - externalPlaceId: string; - }[]; - page: number; - size: number; - totalElements: number; - totalPages: number; -} - -export const searchPlaceAPI = async ({ - q, - radiusKm, - includeExternal, - page, - size, -}: SearchPlaceAPIRequest) => { - const response = await fetchInstance.get(SEARCH_PLACE_API_PATH, { - params: { q, radiusKm, includeExternal, page, size }, - }); - - return response.data; -}; diff --git a/src/features/main/index.ts b/src/features/main/index.ts index 5ecdd1f..2da1779 100644 --- a/src/features/main/index.ts +++ b/src/features/main/index.ts @@ -1 +1,2 @@ export * from './ui'; +export * from './hooks'; From ca5712df1fe8cce7910cfd3406244d6373c9f4d7 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:39:49 +0900 Subject: [PATCH 10/30] =?UTF-8?q?feat:=20=EC=9E=A5=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=9B=85(useGetSearchPlace)=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=20=EB=B0=8F=20=EC=B9=B4=EC=B9=B4=EC=98=A4=20=EC=A3=BC=EC=86=8C?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=20=ED=9B=85(useKakaoAddressSearch)=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/hooks/index.ts | 2 +- src/features/main/hooks/useGetSearchPlace.ts | 18 ------ .../main/hooks/useKakaoAddressSearch.ts | 56 +++++++++++++++++++ 3 files changed, 57 insertions(+), 19 deletions(-) delete mode 100644 src/features/main/hooks/useGetSearchPlace.ts create mode 100644 src/features/main/hooks/useKakaoAddressSearch.ts diff --git a/src/features/main/hooks/index.ts b/src/features/main/hooks/index.ts index 0d9865d..db3e054 100644 --- a/src/features/main/hooks/index.ts +++ b/src/features/main/hooks/index.ts @@ -1,3 +1,3 @@ export * from './useChartConfig'; export * from './useAddressSearch'; -export * from './useGetSearchPlace'; +export * from './useKakaoAddressSearch'; diff --git a/src/features/main/hooks/useGetSearchPlace.ts b/src/features/main/hooks/useGetSearchPlace.ts deleted file mode 100644 index 0473928..0000000 --- a/src/features/main/hooks/useGetSearchPlace.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; - -import { type SearchPlaceAPIRequest, searchPlaceAPI } from '../apis'; - -export const SearchPlaceQueryKey = ['searchPlace']; - -export const useGetSearchPlace = ({ - q, - radiusKm, - includeExternal, - page, - size, -}: SearchPlaceAPIRequest) => { - return useQuery({ - queryKey: SearchPlaceQueryKey, - queryFn: () => searchPlaceAPI({ q, radiusKm, includeExternal, page, size }), - }); -}; diff --git a/src/features/main/hooks/useKakaoAddressSearch.ts b/src/features/main/hooks/useKakaoAddressSearch.ts new file mode 100644 index 0000000..7e585fa --- /dev/null +++ b/src/features/main/hooks/useKakaoAddressSearch.ts @@ -0,0 +1,56 @@ +import { useState } from 'react'; +import { useFormContext } from 'react-hook-form'; + +import { type AddressSearchResult, searchAddressToCoordinates } from '@/shared'; + +import { type SearchAddressType } from '../model'; +import { useMapAddress } from '../store'; + +export const useKakaoAddressSearch = () => { + const [isSearching, setIsSearching] = useState(false); + const [searchResult, setSearchResult] = useState(null); + const { setMapAddress } = useMapAddress(); + + const form = useFormContext(); + const address = form.watch('address'); + + const searchAddress = async () => { + if (!address || address.trim().length === 0) { + setSearchResult({ + success: false, + error: '주소를 입력해주세요.', + }); + return; + } + + setIsSearching(true); + setSearchResult(null); + + try { + const result = await searchAddressToCoordinates(address); + setSearchResult(result); + + if (result.success && result.data) { + setMapAddress({ + address: result.data.address, + latitude: result.data.latitude, + longitude: result.data.longitude, + }); + } + } catch { + setSearchResult({ + success: false, + error: '주소 검색 중 오류가 발생했습니다.', + }); + } finally { + setIsSearching(false); + } + }; + + return { + searchAddress, + isSearching, + searchResult, + address, + }; +}; From db58c09864aa1dc529d77a88f5015b01aea16e12 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:43:46 +0900 Subject: [PATCH 11/30] =?UTF-8?q?feat:=20=EB=A7=B5=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EB=B0=8F=20=EB=AA=A8=EB=93=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/index.ts | 1 + src/entities/map/index.ts | 1 + src/entities/map/types/index.ts | 1 + src/entities/map/types/map.type.ts | 5 +++++ 4 files changed, 8 insertions(+) create mode 100644 src/entities/map/index.ts create mode 100644 src/entities/map/types/index.ts create mode 100644 src/entities/map/types/map.type.ts diff --git a/src/entities/index.ts b/src/entities/index.ts index 6bf3065..d57fe8e 100644 --- a/src/entities/index.ts +++ b/src/entities/index.ts @@ -1,2 +1,3 @@ export * from './auth'; export * from './chart'; +export * from './map'; diff --git a/src/entities/map/index.ts b/src/entities/map/index.ts new file mode 100644 index 0000000..fcb073f --- /dev/null +++ b/src/entities/map/index.ts @@ -0,0 +1 @@ +export * from './types'; diff --git a/src/entities/map/types/index.ts b/src/entities/map/types/index.ts new file mode 100644 index 0000000..4b3f498 --- /dev/null +++ b/src/entities/map/types/index.ts @@ -0,0 +1 @@ +export * from './map.type'; diff --git a/src/entities/map/types/map.type.ts b/src/entities/map/types/map.type.ts new file mode 100644 index 0000000..2510452 --- /dev/null +++ b/src/entities/map/types/map.type.ts @@ -0,0 +1,5 @@ +export type MapAddress = { + address: string; + latitude: number; + longitude: number; +}; From 1b9f66ccf2832b78d8ef8d714f14bbb115e3d48f Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:44:09 +0900 Subject: [PATCH 12/30] =?UTF-8?q?feat:=20=EC=8A=A4=ED=94=BC=EB=84=88=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20UI=20=EC=9D=B8=EB=8D=B1=EC=8A=A4=EC=97=90=20?= =?UTF-8?q?=EB=82=B4=EB=B3=B4=EB=82=B4=EA=B8=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/components/ui/index.ts | 1 + src/shared/components/ui/spinner.tsx | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 src/shared/components/ui/spinner.tsx diff --git a/src/shared/components/ui/index.ts b/src/shared/components/ui/index.ts index f25fb2f..4bbfdfe 100644 --- a/src/shared/components/ui/index.ts +++ b/src/shared/components/ui/index.ts @@ -7,3 +7,4 @@ export * from './label'; export * from './avatar'; export * from './radio-group'; export * from './select'; +export * from './spinner'; diff --git a/src/shared/components/ui/spinner.tsx b/src/shared/components/ui/spinner.tsx new file mode 100644 index 0000000..7e2fe83 --- /dev/null +++ b/src/shared/components/ui/spinner.tsx @@ -0,0 +1,13 @@ +export const Spinner = () => { + return ( +
+
+ Loading... +
+
+ ); +}; From 3ae30078aaca8c8c9a1b822755b57d54b03accaa Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:55:10 +0900 Subject: [PATCH 13/30] =?UTF-8?q?feat:=20=EC=B9=B4=EC=B9=B4=EC=98=A4=20?= =?UTF-8?q?=EB=A7=B5=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=EB=A7=B5=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=9C=A0=ED=8B=B8=EB=A6=AC=ED=8B=B0=EC=99=80=20UI=20=EB=82=B4?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EA=B8=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/map/index.ts | 2 ++ src/entities/map/ui/KakaoMap.tsx | 37 ++++++++++++++++++++++++++++++++ src/entities/map/ui/index.ts | 1 + 3 files changed, 40 insertions(+) create mode 100644 src/entities/map/ui/KakaoMap.tsx create mode 100644 src/entities/map/ui/index.ts diff --git a/src/entities/map/index.ts b/src/entities/map/index.ts index fcb073f..e12841b 100644 --- a/src/entities/map/index.ts +++ b/src/entities/map/index.ts @@ -1 +1,3 @@ export * from './types'; +export * from './utils'; +export * from './ui'; diff --git a/src/entities/map/ui/KakaoMap.tsx b/src/entities/map/ui/KakaoMap.tsx new file mode 100644 index 0000000..e0b6289 --- /dev/null +++ b/src/entities/map/ui/KakaoMap.tsx @@ -0,0 +1,37 @@ +import { Map, MapMarker, useKakaoLoader } from 'react-kakao-maps-sdk'; + +import { toast } from 'sonner'; + +import { Spinner } from '@/shared'; + +type Props = { + lat: number; + lng: number; +}; + +export const KakaoMap = ({ lat, lng }: Props) => { + const [loading, error] = useKakaoLoader({ + appkey: import.meta.env.VITE_KAKAOMAP_API_KEY, + libraries: ['clusterer', 'drawing', 'services'], + }); + + const center = { + lat: lat, + lng: lng, + }; + + if (loading) return ; + + if (error) return toast.error(error.message); + + return ( + + + + ); +}; diff --git a/src/entities/map/ui/index.ts b/src/entities/map/ui/index.ts new file mode 100644 index 0000000..bab08f6 --- /dev/null +++ b/src/entities/map/ui/index.ts @@ -0,0 +1 @@ +export * from './KakaoMap'; From 495967558f008ec0454f20cd391311febb156faf Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:55:40 +0900 Subject: [PATCH 14/30] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=EB=A7=B5=20?= =?UTF-8?q?=EA=B0=92=20=EC=83=81=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/constants/default-map-value.ts | 5 +++++ src/shared/constants/index.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 src/shared/constants/default-map-value.ts diff --git a/src/shared/constants/default-map-value.ts b/src/shared/constants/default-map-value.ts new file mode 100644 index 0000000..3126f4d --- /dev/null +++ b/src/shared/constants/default-map-value.ts @@ -0,0 +1,5 @@ +export const BEXCO_ADDRESS = { + address: '부산 해운대구 APEC로 55', + latitude: 35.1690637154991, + longitude: 129.136018268316, +}; diff --git a/src/shared/constants/index.ts b/src/shared/constants/index.ts index 0899ce9..798e507 100644 --- a/src/shared/constants/index.ts +++ b/src/shared/constants/index.ts @@ -1,3 +1,4 @@ export * from './router-path'; export * from './risk-chart-segments'; export * from './chart-color'; +export * from './default-map-value'; From e497c3c585fadb9aabf1d7f623acd581c06dcd41 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:56:32 +0900 Subject: [PATCH 15/30] =?UTF-8?q?feat:=20=EC=B9=B4=EC=B9=B4=EC=98=A4?= =?UTF-8?q?=EB=A7=B5=20API=EB=A5=BC=20=ED=99=9C=EC=9A=A9=ED=95=9C=20?= =?UTF-8?q?=EC=A3=BC=EC=86=8C=20=EA=B2=80=EC=83=89=20=EC=9C=A0=ED=8B=B8?= =?UTF-8?q?=EB=A6=AC=ED=8B=B0=20=EB=B0=8F=20=ED=83=80=EC=9E=85=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/map/utils/index.ts | 1 + src/entities/map/utils/search-coordinates.ts | 114 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/entities/map/utils/index.ts create mode 100644 src/entities/map/utils/search-coordinates.ts diff --git a/src/entities/map/utils/index.ts b/src/entities/map/utils/index.ts new file mode 100644 index 0000000..d0ce68e --- /dev/null +++ b/src/entities/map/utils/index.ts @@ -0,0 +1 @@ +export * from './search-coordinates'; diff --git a/src/entities/map/utils/search-coordinates.ts b/src/entities/map/utils/search-coordinates.ts new file mode 100644 index 0000000..b8348c6 --- /dev/null +++ b/src/entities/map/utils/search-coordinates.ts @@ -0,0 +1,114 @@ +// 카카오맵 API 타입 정의 +declare global { + interface Window { + kakao: { + maps: { + services: { + Geocoder: new () => { + addressSearch: ( + address: string, + callback: (result: KakaoGeocoderResult[], status: string) => void, + ) => void; + }; + }; + }; + }; + } +} + +export interface KakaoGeocoderResult { + address: { + address_name: string; + b_code: string; + h_code: string; + main_address_no: string; + mountain_yn: string; + region_1depth_name: string; + region_2depth_name: string; + region_3depth_h_name: string; + region_3depth_name: string; + sub_address_no: string; + x: string; + y: string; + }; + road_address: { + address_name: string; + building_name: string; + main_building_no: string; + region_1depth_name: string; + region_2depth_name: string; + region_3depth_name: string; + road_name: string; + sub_building_no: string; + underground_yn: string; + x: string; + y: string; + zone_no: string; + } | null; + x: string; // 경도 + y: string; // 위도 +} + +export interface AddressSearchResult { + success: boolean; + data?: { + address: string; + latitude: number; + longitude: number; + }; + error?: string; +} + +/** + * 카카오맵 API를 사용하여 주소를 좌표로 변환하는 함수 + * @param address 검색할 주소 + * @returns Promise + */ +export const searchAddressToCoordinates = (address: string): Promise => { + return new Promise((resolve) => { + // 카카오맵 API가 로드되지 않은 경우 + if (!window.kakao?.maps?.services?.Geocoder) { + resolve({ + success: false, + error: '카카오맵 API가 로드되지 않았습니다.', + }); + return; + } + + const geocoder = new window.kakao.maps.services.Geocoder(); + + geocoder.addressSearch(address, (result: KakaoGeocoderResult[], status: string) => { + if (status === 'OK' && result.length > 0) { + const firstResult = result[0]; + const addressInfo = firstResult.road_address || firstResult.address; + + resolve({ + success: true, + data: { + address: addressInfo.address_name, + latitude: parseFloat(firstResult.y), + longitude: parseFloat(firstResult.x), + }, + }); + } else if (status === 'ZERO_RESULT') { + resolve({ + success: false, + error: '검색 결과가 없습니다.', + }); + } else { + resolve({ + success: false, + error: `검색 중 오류가 발생했습니다: ${status}`, + }); + } + }); + }); +}; + +/** + * 카카오맵 API 스크립트가 로드되었는지 확인하는 함수 + * @returns boolean + */ +export const isKakaoMapLoaded = (): boolean => { + return !!window.kakao?.maps?.services?.Geocoder; +}; From 37e16dd96f352b3ab2ce6d7fcc5c9409f14890df Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:56:47 +0900 Subject: [PATCH 16/30] =?UTF-8?q?feat:=20=EC=A3=BC=EC=86=8C=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EA=B4=80=EB=A6=AC=20=ED=9B=85(useMapAddress)=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9D=B8=EB=8D=B1=EC=8A=A4=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/store/index.ts | 1 + src/features/main/store/useMapAddress.ts | 50 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/features/main/store/index.ts create mode 100644 src/features/main/store/useMapAddress.ts diff --git a/src/features/main/store/index.ts b/src/features/main/store/index.ts new file mode 100644 index 0000000..c88c0b6 --- /dev/null +++ b/src/features/main/store/index.ts @@ -0,0 +1 @@ +export * from './useMapAddress'; diff --git a/src/features/main/store/useMapAddress.ts b/src/features/main/store/useMapAddress.ts new file mode 100644 index 0000000..1907946 --- /dev/null +++ b/src/features/main/store/useMapAddress.ts @@ -0,0 +1,50 @@ +import { create } from 'zustand'; + +import type { MapAddress } from '@/entities'; + +type MapAddressState = { + mapAddress: MapAddress | null; + + setMapAddress: (address: MapAddress) => void; + clearMapAddress: () => void; + updateCoordinates: (latitude: number, longitude: number) => void; + updateAddress: (address: string) => void; +}; + +export const useMapAddress = create()((set, get) => ({ + mapAddress: null, + + setMapAddress: (address: MapAddress) => { + set({ mapAddress: address }); + }, + + clearMapAddress: () => { + set({ mapAddress: null }); + }, + + updateCoordinates: (latitude: number, longitude: number) => { + const currentAddress = get().mapAddress; + if (currentAddress) { + set({ + mapAddress: { + ...currentAddress, + latitude, + longitude, + }, + }); + } + }, + + updateAddress: (address: string) => { + const currentAddress = get().mapAddress; + + if (currentAddress) { + set({ + mapAddress: { + ...currentAddress, + address, + }, + }); + } + }, +})); From 0be8b3deaa9a75ae07f6fbbad1ffef5ab467e30c Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:57:25 +0900 Subject: [PATCH 17/30] =?UTF-8?q?fix:=20=EC=A3=BC=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=9C=A0=ED=8B=B8=EB=A6=AC=ED=8B=B0=EC=9D=98=20imp?= =?UTF-8?q?ort=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/hooks/useKakaoAddressSearch.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/features/main/hooks/useKakaoAddressSearch.ts b/src/features/main/hooks/useKakaoAddressSearch.ts index 7e585fa..1be850d 100644 --- a/src/features/main/hooks/useKakaoAddressSearch.ts +++ b/src/features/main/hooks/useKakaoAddressSearch.ts @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useFormContext } from 'react-hook-form'; -import { type AddressSearchResult, searchAddressToCoordinates } from '@/shared'; +import { type AddressSearchResult, searchAddressToCoordinates } from '@/entities'; import { type SearchAddressType } from '../model'; import { useMapAddress } from '../store'; @@ -9,6 +9,7 @@ import { useMapAddress } from '../store'; export const useKakaoAddressSearch = () => { const [isSearching, setIsSearching] = useState(false); const [searchResult, setSearchResult] = useState(null); + const { setMapAddress } = useMapAddress(); const form = useFormContext(); From 076554b6ca8b76d0fca41ed6d836f498fd7642db Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:57:42 +0900 Subject: [PATCH 18/30] =?UTF-8?q?feat:=20=EC=B9=B4=EC=B9=B4=EC=98=A4?= =?UTF-8?q?=EB=A7=B5=20=EA=B4=80=EB=A0=A8=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/components/features/index.ts | 1 - .../features/kakao-map/KakaoMap.tsx | 32 ------------------- .../components/features/kakao-map/index.ts | 1 - 3 files changed, 34 deletions(-) delete mode 100644 src/shared/components/features/kakao-map/KakaoMap.tsx delete mode 100644 src/shared/components/features/kakao-map/index.ts diff --git a/src/shared/components/features/index.ts b/src/shared/components/features/index.ts index 96856a9..37d77ea 100644 --- a/src/shared/components/features/index.ts +++ b/src/shared/components/features/index.ts @@ -1,4 +1,3 @@ export * from './layout'; export * from './header'; export * from './optimized-image'; -export * from './kakao-map'; diff --git a/src/shared/components/features/kakao-map/KakaoMap.tsx b/src/shared/components/features/kakao-map/KakaoMap.tsx deleted file mode 100644 index 1fb5eac..0000000 --- a/src/shared/components/features/kakao-map/KakaoMap.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Map, MapMarker, useKakaoLoader } from 'react-kakao-maps-sdk'; - -type Props = { - lat: number; - lng: number; -}; - -export const KakaoMap = ({ lat, lng }: Props) => { - const [loading, error] = useKakaoLoader({ - appkey: import.meta.env.VITE_KAKAOMAP_API_KEY, - libraries: ['clusterer', 'drawing', 'services'], - }); - - const center = { - lat: lat, - lng: lng, - }; - - if (loading) return
Loading...
; - if (error) return
Error: {error.message}
; - - return ( - - - - ); -}; diff --git a/src/shared/components/features/kakao-map/index.ts b/src/shared/components/features/kakao-map/index.ts deleted file mode 100644 index bab08f6..0000000 --- a/src/shared/components/features/kakao-map/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './KakaoMap'; From 96b32389f5f1c54ee868d78a8664da2a8fa786da Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:57:55 +0900 Subject: [PATCH 19/30] =?UTF-8?q?refactor:=20=EC=B9=B4=EC=B9=B4=EC=98=A4?= =?UTF-8?q?=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=9B=85=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/auth/hooks/useKakaoLogin.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/entities/auth/hooks/useKakaoLogin.ts b/src/entities/auth/hooks/useKakaoLogin.ts index b8d5ab0..252b62d 100644 --- a/src/entities/auth/hooks/useKakaoLogin.ts +++ b/src/entities/auth/hooks/useKakaoLogin.ts @@ -5,12 +5,9 @@ import { BASE_URL } from '@/shared'; import { getTicketApi } from '../apis'; -// --- 1. "로그인 시작"을 위한 useMutation --- -// 이 훅은 API를 호출하지 않아. 오직 카카오 로그인 페이지로 '이동'시키는 액션만 책임져. export const useKakaoLogin = () => { return useMutation({ mutationFn: () => { - // 실제로는 Promise를 반환할 필요는 없지만, mutationFn은 Promise를 기대해. window.location.href = `${BASE_URL}/oauth2/authorization/kakao`; return Promise.resolve(); }, @@ -20,7 +17,6 @@ export const useKakaoLogin = () => { }); }; -// --- 2. "콜백 처리"를 위한 useQuery --- export const KakaoCallbackQueryKey = { callback: (ticket: string) => ['kakaoCallback', ticket], }; @@ -28,9 +24,7 @@ export const KakaoCallbackQueryKey = { export const useKakaoCallback = (ticket: string) => { return useQuery({ queryKey: KakaoCallbackQueryKey.callback(ticket), - // code가 있을 때만 이 쿼리를 실행해. queryFn: () => getTicketApi(ticket), - // 이 쿼리는 한 번만 실행되면 되므로, 재시도나 캐시 관련 옵션을 조정할 수 있어. retry: 0, staleTime: Infinity, }); From c6e62ed3941c55885478cc17584738f623348b73 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:59:14 +0900 Subject: [PATCH 20/30] =?UTF-8?q?feat:=20=EC=A7=80=EB=8F=84=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=97=90=EC=84=9C=20=EC=A3=BC?= =?UTF-8?q?=EC=86=8C=20=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC=20=ED=9B=85?= =?UTF-8?q?=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=97=AC=20=EC=9C=84?= =?UTF-8?q?=EB=8F=84=20=EB=B0=8F=20=EA=B2=BD=EB=8F=84=20=EB=8F=99=EC=A0=81?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/ui/MapSection.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/features/main/ui/MapSection.tsx b/src/features/main/ui/MapSection.tsx index 96f0445..ba0e2d5 100644 --- a/src/features/main/ui/MapSection.tsx +++ b/src/features/main/ui/MapSection.tsx @@ -1,8 +1,15 @@ -import { Button, KakaoMap } from '@/shared'; +import { KakaoMap } from '@/entities'; +import { BEXCO_ADDRESS, Button } from '@/shared'; import { HOUSE_TYPES } from '../constants'; +import { useMapAddress } from '../store'; export const MapSection = () => { + const { mapAddress } = useMapAddress(); + + const lat = mapAddress?.latitude || BEXCO_ADDRESS.latitude; + const lng = mapAddress?.longitude || BEXCO_ADDRESS.longitude; + return (
@@ -13,9 +20,8 @@ export const MapSection = () => { ))}
- {/* TODO: 추후 지도 (카카오맵, 네이버 지도, 구글 맵 등) 컴포넌트 추가 */}
- +
); From c28e7908bd7ef9231bbaede4ce14f84d037c1591 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:59:40 +0900 Subject: [PATCH 21/30] =?UTF-8?q?feat:=20=EC=A3=BC=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B8=B0=EB=8A=A5=EC=97=90=20=EC=B9=B4=EC=B9=B4?= =?UTF-8?q?=EC=98=A4=EB=A7=B5=20API=20=EC=97=B0=EB=8F=99=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A7=80=EB=8F=84=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/components/common/AddressField.tsx | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/features/main/components/common/AddressField.tsx b/src/features/main/components/common/AddressField.tsx index 89c059b..3ed9efe 100644 --- a/src/features/main/components/common/AddressField.tsx +++ b/src/features/main/components/common/AddressField.tsx @@ -1,19 +1,29 @@ import DaumPostcode from 'react-daum-postcode'; import { useFormContext } from 'react-hook-form'; -import { X } from 'lucide-react'; +import { MapPin, X } from 'lucide-react'; import { Button, FormField, FormItem, FormLabel, FormMessage, Input } from '@/shared'; import { FORM_FIELDS, LABEL_TEXTS, PLACEHOLDER_TEXTS } from '../../constants'; -import { useAddressSearch } from '../../hooks'; +import { useAddressSearch, useKakaoAddressSearch } from '../../hooks'; import { type SearchAddressType } from '../../model'; export const AddressField = () => { const { isOpen, completeAddress, openSearch, closeSearch } = useAddressSearch(); + const { searchAddress } = useKakaoAddressSearch(); const form = useFormContext(); + const searchMap = () => { + const address = form.getValues('address'); + + if (address && address.trim().length > 0) { + // 카카오맵 API로 주소 검색 + searchAddress(); + } + }; + return ( { render={({ field }) => ( {LABEL_TEXTS.ADDRESS} - +
+ + +
{isOpen && ( From 28a31946bb9dcb274b14a536fc7c2e6536b90897 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 18:59:53 +0900 Subject: [PATCH 22/30] =?UTF-8?q?fix:=20MainPage=EC=97=90=EC=84=9C=20Landl?= =?UTF-8?q?ordReliabilitySection=EC=9D=98=20=EC=9C=84=EC=B9=98=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/main/MainPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/main/MainPage.tsx b/src/pages/main/MainPage.tsx index 8d07d37..5ab4551 100644 --- a/src/pages/main/MainPage.tsx +++ b/src/pages/main/MainPage.tsx @@ -17,8 +17,8 @@ export default function MainPage() { - + ); From 983d4ecaf77f6f3b63c17574c3aec0268a6d1277 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 19:01:40 +0900 Subject: [PATCH 23/30] =?UTF-8?q?fix:=20MainPage=EC=97=90=EC=84=9C=20Landl?= =?UTF-8?q?ordPropertySection=EC=9D=98=20=EC=9C=84=EC=B9=98=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/main/MainPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/main/MainPage.tsx b/src/pages/main/MainPage.tsx index 5ab4551..8d07d37 100644 --- a/src/pages/main/MainPage.tsx +++ b/src/pages/main/MainPage.tsx @@ -17,8 +17,8 @@ export default function MainPage() { - + ); From 7854985f30d54a226d220f7acd26e18cdbc1aca4 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 19:45:37 +0900 Subject: [PATCH 24/30] =?UTF-8?q?fix:=20KakaoMap=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=EC=84=9C=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=ED=91=9C=EC=8B=9C=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/map/ui/KakaoMap.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/entities/map/ui/KakaoMap.tsx b/src/entities/map/ui/KakaoMap.tsx index e0b6289..5fdc493 100644 --- a/src/entities/map/ui/KakaoMap.tsx +++ b/src/entities/map/ui/KakaoMap.tsx @@ -1,7 +1,5 @@ import { Map, MapMarker, useKakaoLoader } from 'react-kakao-maps-sdk'; -import { toast } from 'sonner'; - import { Spinner } from '@/shared'; type Props = { @@ -22,15 +20,10 @@ export const KakaoMap = ({ lat, lng }: Props) => { if (loading) return ; - if (error) return toast.error(error.message); + if (error) return
오류 : {error.message}
; return ( - + ); From aed4b0167abcc3716a5b4c6a30bb510d5573ec57 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 19:45:54 +0900 Subject: [PATCH 25/30] =?UTF-8?q?fix:=20=EC=A3=BC=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=9B=85=EC=97=90=EC=84=9C=20=EB=AA=A8=EB=8B=AC=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC=20=EC=83=81=ED=83=9C=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=9D=BC=20=EB=AC=B8=EC=84=9C=EC=9D=98=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EC=9E=A0=EA=B8=88=20=EB=B0=8F=20=ED=95=B4=EC=A0=9C?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/hooks/useAddressSearch.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/features/main/hooks/useAddressSearch.ts b/src/features/main/hooks/useAddressSearch.ts index a022f04..83acf1f 100644 --- a/src/features/main/hooks/useAddressSearch.ts +++ b/src/features/main/hooks/useAddressSearch.ts @@ -17,10 +17,12 @@ export const useAddressSearch = () => { }; if (isOpen) { + document.body.style.overflow = 'hidden'; document.addEventListener('keydown', handleKeyDown); } return () => { + document.body.style.overflow = 'unset'; document.removeEventListener('keydown', handleKeyDown); }; }, [isOpen]); From 9cf7686495cb75ba20b5a637f32c85830a7d2f5d Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 19:46:11 +0900 Subject: [PATCH 26/30] =?UTF-8?q?fix:=20=EC=A3=BC=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=9B=85=EC=97=90=EC=84=9C=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EB=A1=9C=EA=B9=85=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/main/hooks/useKakaoAddressSearch.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/features/main/hooks/useKakaoAddressSearch.ts b/src/features/main/hooks/useKakaoAddressSearch.ts index 1be850d..ca1b4f1 100644 --- a/src/features/main/hooks/useKakaoAddressSearch.ts +++ b/src/features/main/hooks/useKakaoAddressSearch.ts @@ -38,7 +38,9 @@ export const useKakaoAddressSearch = () => { longitude: result.data.longitude, }); } - } catch { + } catch (error) { + console.error('주소 검색 중 예기치 않은 오류 발생:', error); + setSearchResult({ success: false, error: '주소 검색 중 오류가 발생했습니다.', From 514039d0b1a47983610cc2c24295a5c38d4d57b9 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 19:48:23 +0900 Subject: [PATCH 27/30] =?UTF-8?q?feat:=20@radix-ui/react-dialog=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?pnpm-lock.yaml=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/package.json b/package.json index 1d7a530..38e3efb 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@hookform/resolvers": "^5.2.1", "@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-radio-group": "^1.3.8", "@radix-ui/react-select": "^2.2.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c4c33a..835eaaa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@radix-ui/react-checkbox': specifier: ^1.3.3 version: 1.3.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@radix-ui/react-label': specifier: ^2.1.7 version: 2.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -573,6 +576,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-direction@1.1.1': resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} peerDependencies: @@ -3447,6 +3463,28 @@ snapshots: optionalDependencies: '@types/react': 19.1.10 + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + aria-hidden: 1.2.6 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-remove-scroll: 2.7.1(@types/react@19.1.10)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + '@radix-ui/react-direction@1.1.1(@types/react@19.1.10)(react@19.1.1)': dependencies: react: 19.1.1 From f650f3f8fd3f0c5e628407be9d68bfceb3f7a8d7 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 19:49:04 +0900 Subject: [PATCH 28/30] =?UTF-8?q?feat:=20Dialog=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20Radix=20U?= =?UTF-8?q?I=20Dialog=20=EA=B5=AC=EC=84=B1=20=EC=9A=94=EC=86=8C=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/components/ui/dialog.tsx | 128 ++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/shared/components/ui/dialog.tsx diff --git a/src/shared/components/ui/dialog.tsx b/src/shared/components/ui/dialog.tsx new file mode 100644 index 0000000..dcd77a6 --- /dev/null +++ b/src/shared/components/ui/dialog.tsx @@ -0,0 +1,128 @@ +import * as React from 'react'; + +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { XIcon } from 'lucide-react'; + +import { cn } from '../../utils'; + +function Dialog({ ...props }: React.ComponentProps) { + return ; +} + +function DialogTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function DialogPortal({ ...props }: React.ComponentProps) { + return ; +} + +function DialogClose({ ...props }: React.ComponentProps) { + return ; +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean; +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ); +} + +function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogTitle({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +}; From e1f84a4c23841f0ada9f2ee5a8bf1d59b156e9d4 Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 20:04:32 +0900 Subject: [PATCH 29/30] =?UTF-8?q?fix:=20Dialog=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=9D=98=20=EB=8B=AB=EA=B8=B0=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=ED=81=AC=EA=B8=B0=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/components/ui/dialog.tsx | 2 +- src/shared/components/ui/index.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shared/components/ui/dialog.tsx b/src/shared/components/ui/dialog.tsx index dcd77a6..ef9a23a 100644 --- a/src/shared/components/ui/dialog.tsx +++ b/src/shared/components/ui/dialog.tsx @@ -60,7 +60,7 @@ function DialogContent({ {showCloseButton && ( Close diff --git a/src/shared/components/ui/index.ts b/src/shared/components/ui/index.ts index 4bbfdfe..c4ae336 100644 --- a/src/shared/components/ui/index.ts +++ b/src/shared/components/ui/index.ts @@ -8,3 +8,4 @@ export * from './avatar'; export * from './radio-group'; export * from './select'; export * from './spinner'; +export * from './dialog'; From 485923cdbcdc3bc0f765f65f0450585f070f0e3e Mon Sep 17 00:00:00 2001 From: Dobbymin Date: Fri, 22 Aug 2025 20:04:48 +0900 Subject: [PATCH 30/30] =?UTF-8?q?feat:=20=EC=A3=BC=EC=86=8C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20Dialog=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=ED=95=98=EC=97=AC=20UI=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/components/common/AddressField.tsx | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/features/main/components/common/AddressField.tsx b/src/features/main/components/common/AddressField.tsx index 3ed9efe..0d229e5 100644 --- a/src/features/main/components/common/AddressField.tsx +++ b/src/features/main/components/common/AddressField.tsx @@ -1,7 +1,14 @@ import DaumPostcode from 'react-daum-postcode'; import { useFormContext } from 'react-hook-form'; -import { MapPin, X } from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from '@/shared/components/ui/dialog'; +import { MapPin } from 'lucide-react'; import { Button, FormField, FormItem, FormLabel, FormMessage, Input } from '@/shared'; @@ -39,34 +46,25 @@ export const AddressField = () => { onClick={openSearch} className='cursor-pointer' /> -
- {isOpen && ( -
-
-
-

주소 검색

- -
- -
-
- )} + + + + 주소 검색 + 주소를 검색하여 선택해주세요. + + + + )} />