From 0af4020bfe7bcf7121f3c806ebdc28efe9ca5498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EB=AF=BC=EA=B7=A0?= <97932282+skyblue1232@users.noreply.github.com> Date: Sun, 17 May 2026 15:24:56 +0900 Subject: [PATCH 1/4] chore/owner-register --- apps/customer/next-env.d.ts | 2 +- apps/owner/src/app/signup/page.tsx | 7 ++++++- packages/api/src/models/auth.ts | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/customer/next-env.d.ts b/apps/customer/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/apps/customer/next-env.d.ts +++ b/apps/customer/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/owner/src/app/signup/page.tsx b/apps/owner/src/app/signup/page.tsx index 9d25c2d..d1bee3a 100644 --- a/apps/owner/src/app/signup/page.tsx +++ b/apps/owner/src/app/signup/page.tsx @@ -59,10 +59,15 @@ export default function SignupPage() { passwordConfirm, }, { - onSuccess: () => { + onSuccess: (res) => { + const accessToken = res.data.accessToken; + + localStorage.setItem("ownerAccessToken", accessToken); + setSignupCompleted(email); router.push("/signup/business"); }, + onError: (error) => { console.log("회원가입 실패", error); }, diff --git a/packages/api/src/models/auth.ts b/packages/api/src/models/auth.ts index 4d7278a..1ee43f3 100644 --- a/packages/api/src/models/auth.ts +++ b/packages/api/src/models/auth.ts @@ -9,6 +9,7 @@ export interface JoinReqDTO { } export interface JoinRespDTO { + accessToken: string; memberName: string; email: string; } From 1b45c487e702a673285de39af1368c63130d66bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EB=AF=BC=EA=B7=A0?= <97932282+skyblue1232@users.noreply.github.com> Date: Sun, 17 May 2026 16:55:20 +0900 Subject: [PATCH 2/4] refactor/address-search --- .../signup/register/_apis/loadDaumPostcode.ts | 52 ++++++++ .../signup/register/_apis/openDaumPostcode.ts | 31 +++++ .../register/_apis/searchAddressBykakao.ts | 68 ---------- .../_components/AddressSearchBottomSheet.tsx | 122 ++++++------------ .../signup/register/_types/address-search.ts | 29 ++++- 5 files changed, 147 insertions(+), 155 deletions(-) create mode 100644 apps/owner/src/app/signup/register/_apis/loadDaumPostcode.ts create mode 100644 apps/owner/src/app/signup/register/_apis/openDaumPostcode.ts delete mode 100644 apps/owner/src/app/signup/register/_apis/searchAddressBykakao.ts diff --git a/apps/owner/src/app/signup/register/_apis/loadDaumPostcode.ts b/apps/owner/src/app/signup/register/_apis/loadDaumPostcode.ts new file mode 100644 index 0000000..2d0cd0c --- /dev/null +++ b/apps/owner/src/app/signup/register/_apis/loadDaumPostcode.ts @@ -0,0 +1,52 @@ +export function loadDaumPostcode(): Promise { + return new Promise((resolve, reject) => { + if (typeof window === "undefined") { + reject(new Error("window is undefined")); + return; + } + + if (window.daum?.Postcode) { + resolve(); + return; + } + + const existingScript = document.querySelector( + 'script[src*="postcode.v2.js"]', + ); + + if (existingScript) { + existingScript.addEventListener( + "load", + () => { + if (window.daum?.Postcode) resolve(); + else reject(new Error("Daum Postcode is not loaded.")); + }, + { once: true }, + ); + + existingScript.addEventListener( + "error", + () => reject(new Error("Failed to load Daum Postcode script.")), + { once: true }, + ); + + return; + } + + const script = document.createElement("script"); + script.src = + "https://t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"; + script.async = true; + + script.onload = () => { + if (window.daum?.Postcode) resolve(); + else reject(new Error("Daum Postcode is not loaded.")); + }; + + script.onerror = () => { + reject(new Error("Failed to load Daum Postcode script.")); + }; + + document.head.appendChild(script); + }); +} \ No newline at end of file diff --git a/apps/owner/src/app/signup/register/_apis/openDaumPostcode.ts b/apps/owner/src/app/signup/register/_apis/openDaumPostcode.ts new file mode 100644 index 0000000..84224b3 --- /dev/null +++ b/apps/owner/src/app/signup/register/_apis/openDaumPostcode.ts @@ -0,0 +1,31 @@ +import { loadDaumPostcode } from "./loadDaumPostcode"; +import type { + AddressSearchItem, + DaumPostcodeData, +} from "../_types/address-search"; + +export async function openDaumPostcode(): Promise { + await loadDaumPostcode(); + + return new Promise((resolve, reject) => { + if (!window.daum?.Postcode) { + reject(new Error("Daum Postcode is not loaded.")); + return; + } + + new window.daum.Postcode({ + oncomplete: (data: DaumPostcodeData) => { + const roadAddress = data.roadAddress || data.address || ""; + const lotNumberAddress = data.jibunAddress || ""; + + resolve({ + id: `${data.zonecode}-${roadAddress || lotNumberAddress}`, + label: roadAddress || lotNumberAddress, + roadAddress, + lotNumberAddress, + zonecode: data.zonecode, + }); + }, + }).open(); + }); +} \ No newline at end of file diff --git a/apps/owner/src/app/signup/register/_apis/searchAddressBykakao.ts b/apps/owner/src/app/signup/register/_apis/searchAddressBykakao.ts deleted file mode 100644 index 3da000e..0000000 --- a/apps/owner/src/app/signup/register/_apis/searchAddressBykakao.ts +++ /dev/null @@ -1,68 +0,0 @@ -"use client"; - -import type { AddressSearchItem } from "../_types/address-search"; - -export function searchAddressByKakao( - keyword: string, - size = 10, -): Promise { - return new Promise((resolve, reject) => { - const trimmedKeyword = keyword.trim(); - - if (!trimmedKeyword) { - resolve([]); - return; - } - - if ( - typeof window === "undefined" || - !window.kakao?.maps?.services - ) { - reject(new Error("Kakao services library is not loaded.")); - return; - } - - const geocoder = new window.kakao.maps.services.Geocoder(); - - geocoder.addressSearch( - trimmedKeyword, - (result: KakaoAddressSearchResult[], status: string) => { - const { kakao } = window; - - if (status === kakao.maps.services.Status.ZERO_RESULT) { - resolve([]); - return; - } - - if (status !== kakao.maps.services.Status.OK) { - reject(new Error("주소 검색 중 오류가 발생했습니다.")); - return; - } - - const mapped = result.slice(0, size).map((item, index) => { - const lotNumberAddress = - item.address?.address_name || item.address_name || ""; - - const roadAddress = - item.road_address?.address_name || item.address_name || ""; - - return { - id: `${item.x}-${item.y}-${index}`, - label: roadAddress || lotNumberAddress, - lotNumberAddress, - roadAddress, - longitude: Number(item.x), - latitude: Number(item.y), - }; - }); - - resolve(mapped); - }, - { - page: 1, - size, - analyze_type: window.kakao.maps.services.AnalyzeType.SIMILAR, - }, - ); - }); -} \ No newline at end of file diff --git a/apps/owner/src/app/signup/register/_components/AddressSearchBottomSheet.tsx b/apps/owner/src/app/signup/register/_components/AddressSearchBottomSheet.tsx index b5c5586..0b6b0c7 100644 --- a/apps/owner/src/app/signup/register/_components/AddressSearchBottomSheet.tsx +++ b/apps/owner/src/app/signup/register/_components/AddressSearchBottomSheet.tsx @@ -1,9 +1,9 @@ "use client"; import { useEffect, useRef, useState } from "react"; -import { BottomSheet, Input } from "@compasser/design-system"; +import { BottomSheet, Button } from "@compasser/design-system"; import type { AddressSearchItem } from "../_types/address-search"; -import { searchAddressByKakao } from "../_apis/searchAddressBykakao"; +import { openDaumPostcode } from "../_apis/openDaumPostcode"; interface AddressSearchBottomSheetProps { open: boolean; @@ -16,59 +16,36 @@ export default function AddressSearchBottomSheet({ onClose, onSelectAddress, }: AddressSearchBottomSheetProps) { - const [keyword, setKeyword] = useState(""); - const [results, setResults] = useState([]); - const [isSearching, setIsSearching] = useState(false); + const [isOpening, setIsOpening] = useState(false); + const hasOpenedRef = useRef(false); - const debounceRef = useRef(null); + const handleOpenPostcode = async () => { + try { + setIsOpening(true); - useEffect(() => { - if (!open) { - setKeyword(""); - setResults([]); - setIsSearching(false); + const selectedAddress = await openDaumPostcode(); + + onSelectAddress(selectedAddress); + onClose(); + } catch (error) { + console.error("주소 검색 실패", error); + } finally { + setIsOpening(false); } - }, [open]); + }; useEffect(() => { - if (!open) return; - - const trimmedKeyword = keyword.trim(); - - if (!trimmedKeyword) { - setResults([]); - setIsSearching(false); + if (!open) { + hasOpenedRef.current = false; + setIsOpening(false); return; } - if (debounceRef.current) { - window.clearTimeout(debounceRef.current); - } - - debounceRef.current = window.setTimeout(async () => { - try { - setIsSearching(true); - const searched = await searchAddressByKakao(trimmedKeyword, 10); - setResults(searched); - } catch (error) { - console.error(error); - setResults([]); - } finally { - setIsSearching(false); - } - }, 250); + if (hasOpenedRef.current) return; - return () => { - if (debounceRef.current) { - window.clearTimeout(debounceRef.current); - } - }; - }, [keyword, open]); - - const handleSelectItem = (item: AddressSearchItem) => { - onSelectAddress(item); - onClose(); - }; + hasOpenedRef.current = true; + void handleOpenPostcode(); + }, [open]); return ( - setKeyword(event.target.value)} - placeholder="주소를 입력해주세요" - /> - - {results.length > 0 && ( -
- {results.map((item) => ( - - ))} -
- )} - - {keyword.trim() && isSearching && ( -

- 검색 중... +

+ 주소 검색 창에서 주소를 선택하면 상점 주소에 자동으로 입력됩니다.

- )} - {keyword.trim() && !isSearching && results.length === 0 && ( -

- 검색 결과가 없습니다. -

- )} + +
); } \ No newline at end of file diff --git a/apps/owner/src/app/signup/register/_types/address-search.ts b/apps/owner/src/app/signup/register/_types/address-search.ts index 6f8a069..73c83c5 100644 --- a/apps/owner/src/app/signup/register/_types/address-search.ts +++ b/apps/owner/src/app/signup/register/_types/address-search.ts @@ -1,8 +1,31 @@ export interface AddressSearchItem { id: string; label: string; + roadAddress: string; lotNumberAddress: string; + zonecode: string; +} + +export interface DaumPostcodeData { + zonecode: string; roadAddress: string; - longitude: number; - latitude: number; -} \ No newline at end of file + jibunAddress: string; + address: string; + buildingName: string; + bname: string; +} + +declare global { + interface Window { + daum?: { + Postcode: new (options: { + oncomplete: (data: DaumPostcodeData) => void; + onclose?: () => void; + }) => { + open: () => void; + }; + }; + } +} + +export {}; \ No newline at end of file From 80a90fb1a55698302f064c6920d56d6a4946c946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EB=AF=BC=EA=B7=A0?= <97932282+skyblue1232@users.noreply.github.com> Date: Sun, 17 May 2026 17:24:55 +0900 Subject: [PATCH 3/4] chore/main-preview-count --- .../app/(tabs)/main/_components/CafeIntro.tsx | 22 +++++++++++-------- apps/owner/src/app/(tabs)/main/page.tsx | 6 ++--- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/owner/src/app/(tabs)/main/_components/CafeIntro.tsx b/apps/owner/src/app/(tabs)/main/_components/CafeIntro.tsx index a481d94..69e0835 100644 --- a/apps/owner/src/app/(tabs)/main/_components/CafeIntro.tsx +++ b/apps/owner/src/app/(tabs)/main/_components/CafeIntro.tsx @@ -8,15 +8,19 @@ import QRRewardConfirmModal from "./QRRewardConfirmModal"; import { useWritingRewardMutation } from "@/shared/queries/mutation/store-manager/useQrMutation"; interface CafeIntroProps { - cafeName: string; + cafeName?: string | null; } -const formatCafeName = (name: string) => { - if (name.length <= 10) { - return { firstLine: name, secondLine: "" }; +const DEFAULT_CAFE_NAME = "등록된 가게"; + +const formatCafeName = (name?: string | null) => { + const safeName = name?.trim() || DEFAULT_CAFE_NAME; + + if (safeName.length <= 10) { + return { firstLine: safeName, secondLine: "" }; } - const firstTen = name.slice(0, 10); + const firstTen = safeName.slice(0, 10); const spaceIndexes = [...firstTen] .map((char, index) => (char === " " ? index : -1)) .filter((index) => index !== -1); @@ -25,14 +29,14 @@ const formatCafeName = (name: string) => { const breakIndex = spaceIndexes[1]; return { - firstLine: name.slice(0, breakIndex).trim(), - secondLine: name.slice(breakIndex + 1).trim(), + firstLine: safeName.slice(0, breakIndex).trim(), + secondLine: safeName.slice(breakIndex + 1).trim(), }; } return { - firstLine: name.slice(0, 10).trim(), - secondLine: name.slice(10).trim(), + firstLine: safeName.slice(0, 10).trim(), + secondLine: safeName.slice(10).trim(), }; }; diff --git a/apps/owner/src/app/(tabs)/main/page.tsx b/apps/owner/src/app/(tabs)/main/page.tsx index a888f00..3920f71 100644 --- a/apps/owner/src/app/(tabs)/main/page.tsx +++ b/apps/owner/src/app/(tabs)/main/page.tsx @@ -14,7 +14,7 @@ export default function OwnerMainPage() { id: reservation.reservationId, customerName: `회원 ${reservation.memberId}`, randomBoxName: `예약 #${reservation.reservationId}`, - price: reservation.totalPrice, + price: reservation.totalPrice ?? 0, })) ?? []; if (isLoading) { @@ -42,8 +42,8 @@ export default function OwnerMainPage() { ); From 6ef1995bf1e67b0d8f35337834388c40e276147c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EB=AF=BC=EA=B7=A0?= <97932282+skyblue1232@users.noreply.github.com> Date: Sun, 17 May 2026 17:35:46 +0900 Subject: [PATCH 4/4] chore/work-flow --- apps/owner/src/app/(tabs)/mypage/store-account/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/owner/src/app/(tabs)/mypage/store-account/page.tsx b/apps/owner/src/app/(tabs)/mypage/store-account/page.tsx index f9c2488..9174e6c 100644 --- a/apps/owner/src/app/(tabs)/mypage/store-account/page.tsx +++ b/apps/owner/src/app/(tabs)/mypage/store-account/page.tsx @@ -29,4 +29,4 @@ export default function StoreAccountPage() { ); -} \ No newline at end of file +}