From 22b7623aeb8c0d7a8b7ce81afaed69c832cf26c7 Mon Sep 17 00:00:00 2001 From: Mina Choi Date: Wed, 2 Sep 2026 09:20:55 +0900 Subject: [PATCH] =?UTF-8?q?[fix]=20solution/frontend:=202=EB=8B=A8?= =?UTF-8?q?=EA=B3=84=EC=97=90=EC=84=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=EC=9D=84=20=EC=9A=94=EA=B5=AC=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로그인은 에디터 진입에서 한 번 받는 것이 이 앱의 흐름인데, 장소 API 가 전부 토큰을 요구해서 (place.py) 2단계가 로그인 벽이 되어 있었다. 토큰이 없으면 서버를 부르지 않고 입력한 상호·주소로 신원을 세워 3단계로 넘어간다. 검증은 로그인 뒤에 다시 할 수 있다. --- .../src/features/onboarding/Step2PlaceSearch.tsx | 16 +++++++++++++++- .../src/features/onboarding/usePlaceSearch.ts | 11 +++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/solution/frontend/src/features/onboarding/Step2PlaceSearch.tsx b/solution/frontend/src/features/onboarding/Step2PlaceSearch.tsx index e75cb7b..00f42d4 100644 --- a/solution/frontend/src/features/onboarding/Step2PlaceSearch.tsx +++ b/solution/frontend/src/features/onboarding/Step2PlaceSearch.tsx @@ -1,7 +1,7 @@ import {useState} from 'react'; import {useSearchParams} from 'react-router'; import {ArrowRight, Check, MapPin, Phone, Search, TriangleAlert} from 'lucide-react'; -import type {PlaceCandidate} from '@/api'; +import {getAccessToken, type PlaceCandidate} from '@/api'; import {Badge} from '@/components/ui/badge'; import {Button} from '@/components/ui/button'; import {Input} from '@/components/ui/input'; @@ -83,6 +83,14 @@ export function Step2PlaceSearch() { const runSearch = () => { clearIdentity(); // 상호를 고쳐 다시 찾는 것이므로 앞서 확정한 신원은 물린다 setPickedIndex(null); + // ★ 로그인 전에는 서버를 부르지 않는다. 로그인은 에디터 진입에서 한 번 받는 것이 이 앱의 흐름인데, + // 장소 API 는 전부 토큰을 요구해서(place.py) 여기서 부르면 2단계가 로그인 벽이 된다. + // 입력한 값으로 신원을 세우고 넘어간다 — 검증은 로그인 뒤에 다시 할 수 있다. + if (!getAccessToken()) { + confirmIdentity(search.confirmManual(storeName, location)); + goToStep(3); + return; + } void search.search(storeName, location); }; @@ -113,6 +121,12 @@ export function Step2PlaceSearch() { const pickByUrl = async () => { const url = placeUrl.trim(); if (!url) return; + // URL 확인도 서버가 토큰을 요구한다 — 로그인 전에는 입력값으로 넘어간다. + if (!getAccessToken()) { + confirmIdentity(search.confirmManual(storeName, location)); + goToStep(3); + return; + } const identity = await search.confirmByUrl(url); if (!identity) return; confirmIdentity(identity); diff --git a/solution/frontend/src/features/onboarding/usePlaceSearch.ts b/solution/frontend/src/features/onboarding/usePlaceSearch.ts index 1d0a5f3..609cd07 100644 --- a/solution/frontend/src/features/onboarding/usePlaceSearch.ts +++ b/solution/frontend/src/features/onboarding/usePlaceSearch.ts @@ -132,15 +132,10 @@ export function usePlaceSearch(industry: IndustryType, existingPlaceId: string | // 누른 검색이 토큰 없이 나가 '로그인 만료'로 떨어진다 — 만료가 아니라 경합이다. await ensureAutoSession(); - // ★ '만료' 가 아니라 **아직 로그인한 적이 없는 것**이다(자동 로그인 계정이 없으면 - // ensureAutoSession 이 즉시 끝난다). 지도 검색·URL 확인 모두 서버가 토큰을 요구하므로 - // (place.py 전 엔드포인트가 IsValidAccessToken) 이 단계는 로그인 없이는 지나갈 수 없다. + // ★ 토큰이 없으면 화면(Step2)이 검색을 부르지 않고 입력값으로 넘어간다 — 2단계는 로그인 벽이 아니다. + // 그래도 여기 도달했다면 세션이 도중에 끊긴 것이므로, 로그인을 요구하지 말고 조용히 물러난다. if (!getAccessToken()) { - setState({ - ...INITIAL, - phase: 'unavailable', - unavailableReason: '내 가게 확인은 로그인이 필요합니다. 로그인한 뒤 다시 검색해 주세요.', - }); + setState({...INITIAL}); return; }