diff --git a/app/webview/[slug].tsx b/app/webview/[slug].tsx index 119cc3f..cd406ae 100644 --- a/app/webview/[slug].tsx +++ b/app/webview/[slug].tsx @@ -87,8 +87,19 @@ export default function WebViewScreen() { } }; + const handleNavigateWebview = (slug: string) => { + if (slug.startsWith('club/')) { + const clubId = slug.slice('club/'.length); + if (!clubId) return; + router.push({ pathname: '/club/[id]', params: { id: clubId } }); + } else { + router.push({ pathname: '/webview/[slug]', params: { slug } }); + } + }; + const { handleMessage } = useWebViewMessageHandler({ onNavigateBack: handleBack, + onNavigateWebview: handleNavigateWebview, }); if (!config && !path && !urlParam) { diff --git a/hooks/use-webview-message-handler.ts b/hooks/use-webview-message-handler.ts index dbfa87a..258edc5 100644 --- a/hooks/use-webview-message-handler.ts +++ b/hooks/use-webview-message-handler.ts @@ -4,6 +4,8 @@ import { useCallback } from 'react'; interface UseWebViewMessageHandlerOptions { // 뒤로가기 요청 시 호출 onNavigateBack?: () => void; + // 웹뷰 내 화면 이동 요청 시 호출 + onNavigateWebview?: (slug: string) => void; // 알림 구독 요청 시 호출 onSubscribe?: (clubId: string, clubName?: string) => Promise | void; // 알림 구독 해제 요청 시 호출 @@ -15,6 +17,7 @@ interface UseWebViewMessageHandlerOptions { // WebView 메시지를 처리하는 Hook export const useWebViewMessageHandler = ({ onNavigateBack, + onNavigateWebview, onSubscribe, onUnsubscribe, onShare, @@ -30,6 +33,11 @@ export const useWebViewMessageHandler = ({ case WebViewMessageTypes.NAVIGATE_BACK: onNavigateBack?.(); break; + case WebViewMessageTypes.NAVIGATE_WEBVIEW: + if (message.payload?.slug) { + onNavigateWebview?.(message.payload.slug); + } + break; case WebViewMessageTypes.NOTIFICATION_SUBSCRIBE: if (message.payload?.clubId) { onSubscribe?.(message.payload.clubId, message.payload.clubName); @@ -51,7 +59,7 @@ export const useWebViewMessageHandler = ({ } catch (error) { console.error('[WebViewHandler] 메시지 파싱 오류:', error); } - }, [onNavigateBack, onSubscribe, onUnsubscribe, onShare]); + }, [onNavigateBack, onNavigateWebview, onSubscribe, onUnsubscribe, onShare]); return { handleMessage }; }; diff --git a/types/webview-message.types.ts b/types/webview-message.types.ts index 6ffe7d9..9e48653 100644 --- a/types/webview-message.types.ts +++ b/types/webview-message.types.ts @@ -2,15 +2,17 @@ //WebView 메시지 타입 상수 export const WebViewMessageTypes = { NAVIGATE_BACK: 'NAVIGATE_BACK', + NAVIGATE_WEBVIEW: 'NAVIGATE_WEBVIEW', NOTIFICATION_SUBSCRIBE: 'NOTIFICATION_SUBSCRIBE', NOTIFICATION_UNSUBSCRIBE: 'NOTIFICATION_UNSUBSCRIBE', SHARE: 'SHARE', } as const; // WebView 메시지 Discriminated Union 타입 - + export type WebViewMessage = | { type: 'NAVIGATE_BACK' } + | { type: 'NAVIGATE_WEBVIEW'; payload: { slug: string } } | { type: 'NOTIFICATION_SUBSCRIBE'; payload: { clubId: string; clubName?: string } } | { type: 'NOTIFICATION_UNSUBSCRIBE'; payload: { clubId: string } } | { type: 'SHARE'; payload: { title: string; text: string; url: string } }; diff --git a/ui/home/home-webview-screen.tsx b/ui/home/home-webview-screen.tsx index 4469cf9..c6da484 100644 --- a/ui/home/home-webview-screen.tsx +++ b/ui/home/home-webview-screen.tsx @@ -68,7 +68,8 @@ export function HomeWebViewScreen({ onError }: HomeWebViewScreenProps) { case 'NAVIGATE_WEBVIEW': if (payload.slug?.startsWith('club/')) { - const clubId = payload.slug.replace('club/', ''); + const clubId = payload.slug.slice('club/'.length); + if (!clubId) break; router.push({ pathname: '/club/[id]', params: { id: clubId } }); } else if (payload.slug?.startsWith('promotions/')) { router.push({ pathname: '/webview/[slug]', params: { slug: 'promotions', path: `/${payload.slug}`, hideHeader: 'true' } });