[Feat] 웹뷰 자동 로그인 구현#195
Hidden character warning
Conversation
|
Warning There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure. 🔧 eslint
apps/api/src/controllers/teamController.tsOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the config "@repo/eslint-config/server.js" to extend from. Please check that the name of the config is correct. The config "@repo/eslint-config/server.js" was referenced from the config file in "/apps/api/.eslintrc.js". If you still have problems, please stop by https://eslint.org/chat/help to chat with the team. 개요워크스루이 풀 리퀘스트는 모바일 및 웹 애플리케이션에서 WebView 관련 기능을 개선하고 통합하는 광범위한 변경 사항을 포함합니다. 주요 변경 사항은 API URL 처리, 인증 메시지 처리, 웹뷰 감지 메커니즘 등에 중점을 두고 있으며, 크로스 플랫폼 일관성을 높이기 위한 여러 유틸리티와 훅을 도입했습니다. 변경 사항
시퀀스 다이어그램sequenceDiagram
participant Mobile App
participant WebView
participant Auth Service
Mobile App->>WebView: 로드 이벤트 트리거
WebView->>Auth Service: 인증 데이터 요청
Auth Service-->>WebView: 인증 데이터 응답
WebView->>Mobile App: 인증 메시지 전송
Mobile App->>Mobile App: 인증 상태 업데이트
관련 가능한 PR
제안된 레이블
시 🐰
✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
🚀 Preview URLBranch: 194-feat-rn-webview-브릿지-통신-구현 Preview URL: https://codeit.click?pr=195 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
README.md (4)
2-2: 이미지에 대체 텍스트를 추가해주세요.접근성 향상을 위해 모든 이미지에 의미있는 대체 텍스트(alt text)를 추가하는 것이 좋습니다.
-<img src="..." width="100px" height="100px"/> +<img src="..." width="100px" height="100px" alt="프로젝트 로고"/>Also applies to: 52-52, 57-57, 62-62, 67-67, 72-72
🧰 Tools
🪛 Markdownlint (0.37.0)
2-2: null
Images should have alternate text (alt text)(MD045, no-alt-text)
407-423: 설치 섹션의 제목 레벨이 일관성이 없습니다.Installation 섹션은 h1(#)인데 하위 섹션들이 h3(###)입니다. 제목 레벨을 일관성있게 수정해주세요.
# 🚀 Installation -### 패키지 설치 +## 패키지 설치 -### 개발 모드 +## 개발 모드 -### 프로덕션 모드 +## 프로덕션 모드🧰 Tools
🪛 Markdownlint (0.37.0)
407-407: Expected: h2; Actual: h3
Heading levels should only increment by one level at a time(MD001, heading-increment)
171-171: 코드 블록에 언어 식별자가 없습니다.코드 블록에 적절한 언어 식별자를 추가하면 구문 강조가 적용되어 가독성이 향상됩니다.
-``` +```txt codeit-resources/ # Project Root ├── apps/Also applies to: 394-394
🧰 Tools
🪛 Markdownlint (0.37.0)
171-171: null
Fenced code blocks should have a language specified(MD040, fenced-code-language)
198-198: 강조 표시 대신 제목 태그를 사용하세요.볼드체(**) 대신 적절한 제목 레벨(##, ###)을 사용하는 것이 마크다운 문서의 구조를 더 명확하게 표현할 수 있습니다.
-**1. Web / Mobile** +### 1. Web / Mobile -**2. Backend** +### 2. BackendAlso applies to: 203-203
🧰 Tools
🪛 Markdownlint (0.37.0)
198-198: null
Emphasis used instead of a heading(MD036, no-emphasis-as-heading)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
README.md(1 hunks)
🧰 Additional context used
🪛 Markdownlint (0.37.0)
README.md
407-407: Expected: h2; Actual: h3
Heading levels should only increment by one level at a time
(MD001, heading-increment)
198-198: null
Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
203-203: null
Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
171-171: null
Fenced code blocks should have a language specified
(MD040, fenced-code-language)
394-394: null
Fenced code blocks should have a language specified
(MD040, fenced-code-language)
5-5: null
No empty links
(MD042, no-empty-links)
6-6: null
No empty links
(MD042, no-empty-links)
7-7: null
No empty links
(MD042, no-empty-links)
8-8: null
No empty links
(MD042, no-empty-links)
2-2: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
52-52: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
57-57: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
62-62: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
67-67: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
72-72: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
121-121: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
125-125: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
126-126: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
127-127: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
128-128: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
129-129: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
130-130: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
134-134: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
135-135: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
143-143: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
147-147: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
151-151: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
155-155: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
159-159: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
209-209: null
Images should have alternate text (alt text)
(MD045, no-alt-text)
🔇 Additional comments (3)
README.md (3)
345-347: 미완성된 섹션이 있습니다."Mongo DB 해킹" 섹션이 제목만 있고 내용이 없습니다. 해당 섹션을 완성하거나 제거해주세요.
403-404: 미완성된 섹션이 있습니다."Suspense, Errorboundary" 섹션이 제목만 있고 내용이 없습니다. 해당 섹션을 완성하거나 제거해주세요.
1-423: 전반적으로 잘 작성된 문서입니다!프로젝트의 구조, 기능, 기술적 도전과제들이 상세하게 설명되어 있습니다. 특히 기술적 문제 해결 과정이 잘 문서화되어 있어 매우 인상적입니다.
🧰 Tools
🪛 Markdownlint (0.37.0)
407-407: Expected: h2; Actual: h3
Heading levels should only increment by one level at a time(MD001, heading-increment)
198-198: null
Emphasis used instead of a heading(MD036, no-emphasis-as-heading)
203-203: null
Emphasis used instead of a heading(MD036, no-emphasis-as-heading)
171-171: null
Fenced code blocks should have a language specified(MD040, fenced-code-language)
394-394: null
Fenced code blocks should have a language specified(MD040, fenced-code-language)
5-5: null
No empty links(MD042, no-empty-links)
6-6: null
No empty links(MD042, no-empty-links)
7-7: null
No empty links(MD042, no-empty-links)
8-8: null
No empty links(MD042, no-empty-links)
2-2: null
Images should have alternate text (alt text)(MD045, no-alt-text)
52-52: null
Images should have alternate text (alt text)(MD045, no-alt-text)
57-57: null
Images should have alternate text (alt text)(MD045, no-alt-text)
62-62: null
Images should have alternate text (alt text)(MD045, no-alt-text)
67-67: null
Images should have alternate text (alt text)(MD045, no-alt-text)
72-72: null
Images should have alternate text (alt text)(MD045, no-alt-text)
121-121: null
Images should have alternate text (alt text)(MD045, no-alt-text)
125-125: null
Images should have alternate text (alt text)(MD045, no-alt-text)
126-126: null
Images should have alternate text (alt text)(MD045, no-alt-text)
127-127: null
Images should have alternate text (alt text)(MD045, no-alt-text)
128-128: null
Images should have alternate text (alt text)(MD045, no-alt-text)
129-129: null
Images should have alternate text (alt text)(MD045, no-alt-text)
130-130: null
Images should have alternate text (alt text)(MD045, no-alt-text)
134-134: null
Images should have alternate text (alt text)(MD045, no-alt-text)
135-135: null
Images should have alternate text (alt text)(MD045, no-alt-text)
143-143: null
Images should have alternate text (alt text)(MD045, no-alt-text)
147-147: null
Images should have alternate text (alt text)(MD045, no-alt-text)
151-151: null
Images should have alternate text (alt text)(MD045, no-alt-text)
155-155: null
Images should have alternate text (alt text)(MD045, no-alt-text)
159-159: null
Images should have alternate text (alt text)(MD045, no-alt-text)
209-209: null
Images should have alternate text (alt text)(MD045, no-alt-text)
9fd63ee to
4fd40cf
Compare
There was a problem hiding this comment.
Actionable comments posted: 10
🔭 Outside diff range comments (2)
apps/mobile/utils/getWebViewApiUrl.ts (1)
Line range hint
3-7: 기본 반환값과 환경 변수 유효성 검사 필요
- 알 수 없는 플랫폼에 대한 기본 반환값이 없어 undefined가 반환될 수 있습니다.
- 환경 변수가 설정되지 않은 경우에 대한 처리가 필요합니다.
export const getWebViewApiUrl = () => { - if (Platform.OS === "ios") return process.env.EXPO_PUBLIC_API_URL_IOS; - if (Platform.OS === "android") return process.env.EXPO_PUBLIC_API_URL_ANDROID; + const iosUrl = process.env.EXPO_PUBLIC_API_URL_IOS; + const androidUrl = process.env.EXPO_PUBLIC_API_URL_ANDROID; + + if (!iosUrl || !androidUrl) { + throw new Error('API URL 환경 변수가 설정되지 않았습니다.'); + } + + switch (Platform.OS) { + case 'ios': + return iosUrl; + case 'android': + return androidUrl; + default: + console.warn(`지원되지 않는 플랫폼: ${Platform.OS}`); + return iosUrl; // iOS URL을 기본값으로 사용 + } };apps/web/app/_hooks/useAppRouter.ts (1)
Line range hint
14-20: URL 유효성 검사 및 에러 처리 추가 필요URL 검증과 메시지 전송 실패에 대한 에러 처리가 필요합니다.
const push = (url: string): void => { + if (!url || typeof url !== 'string') { + console.error('Invalid URL provided'); + return; + } if (isWebView) { - sendMessageToWebView({ - type: WEBVIEW_MESSAGE_TYPES.ROUTER_EVENT, - data: url, - }); + try { + sendMessageToWebView({ + type: WEBVIEW_MESSAGE_TYPES.ROUTER_EVENT, + data: url, + }); + } catch (error) { + console.error('Failed to send message to WebView:', error); + router.push(url); // Fallback to regular navigation + } return; }
🧹 Nitpick comments (7)
packages/ui/src/utils/stringifyJson.ts (1)
1-3: JSON 직렬화 오류 처리 추가 필요JSON.stringify는 순환 참조나 BigInt 값과 같은 특수한 경우에 예외를 발생시킬 수 있습니다. 안정성을 위해 try-catch 블록을 추가하는 것이 좋습니다.
export const stringifyJson = <T>(data: T): string => { + try { return JSON.stringify(data); + } catch (error) { + console.error('JSON 직렬화 중 오류 발생:', error); + return ''; + } };packages/ui/src/types/WebViewMessageTypes.ts (1)
7-10: 메시지 타입 제한 필요Message 인터페이스의 type 속성이 string으로 너무 광범위하게 정의되어 있습니다. 허용된 메시지 타입을 명시적으로 정의하면 타입 안정성이 향상됩니다.
+export type MessageType = 'LOGIN' | 'LOGOUT' | 'AUTH_ERROR'; + export interface Message<T> { - type: string; + type: MessageType; data: T; }apps/web/lib/bridge/sendMessageToWebView.ts (1)
8-12: 웹뷰 메시지 전송 구현이 안전합니다.타입 체크와 널 체크가 잘 구현되어 있습니다. 하지만 에러 처리를 추가하면 좋을 것 같습니다.
다음과 같이 에러 처리를 추가하는 것을 고려해보세요:
export const sendMessageToWebView = <T>({ type, data }: Message<T>): void => { if (typeof window !== "undefined" && window.ReactNativeWebView) { - window.ReactNativeWebView.postMessage(stringifyJson({ type, data })); + try { + window.ReactNativeWebView.postMessage(stringifyJson({ type, data })); + } catch (error) { + console.error('Failed to send message to WebView:', error); + } } };apps/web/app/utils/detectDevice.ts (1)
13-14: navigator API 사용 시 타입 안전성 확보가 필요합니다.
navigator.userAgent가 정의되어 있지 않을 경우를 대비한 안전장치가 필요합니다.다음과 같이 개선하는 것을 추천드립니다:
- const userAgent = navigator.userAgent; + const userAgent = navigator.userAgent || '';apps/web/app/utils/detectWebView.ts (2)
18-24: iOS WebView 감지 로직 개선 필요복잡한 조건문을 메서드로 분리하여 가독성을 개선하고, 결과를 캐싱하여 성능을 향상시킬 수 있습니다.
+ const isIOSWebViewUserAgent = (userAgent: string): boolean => { + return userAgent.includes("AppleWebKit") && + !userAgent.includes("Safari") && + !userAgent.includes("CriOS") && + !userAgent.includes("FxiOS"); + }; + - const isIOSWebView = - isIOS && - userAgent.includes("AppleWebKit") && - !userAgent.includes("Safari") && - !userAgent.includes("CriOS") && - !userAgent.includes("FxiOS"); + const isIOSWebView = isIOS && isIOSWebViewUserAgent(userAgent);
27-33: 보안 경고 추가 필요User Agent 문자열은 위조될 수 있으므로, 이에 대한 보안 경고를 주석으로 추가해주세요.
+ // Security Note: User Agent strings can be spoofed. + // This detection method should not be used for security-critical decisions. return { isWebView: isIOSWebView || isAndroidWebView, isIOSWebView, isAndroidWebView, isIOS, isAndroid, };apps/mobile/utils/sendMessageToWeb.ts (1)
6-8: 타입 안전성 개선이 필요합니다.
SendMessage인터페이스의 제네릭 타입 제약이 없어 런타임에 예기치 않은 타입 오류가 발생할 수 있습니다.다음과 같이 수정하는 것을 제안합니다:
-export interface SendMessage<T> extends Message<T> { +export interface SendMessage<T extends Record<string, unknown>> extends Message<T> { webViewRef: RefObject<WebView<object>>; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (30)
apps/mobile/app/(route)/dashboard.tsx(1 hunks)apps/mobile/app/(route)/index.tsx(1 hunks)apps/mobile/app/(route)/meetings.tsx(1 hunks)apps/mobile/app/(route)/seats.tsx(1 hunks)apps/mobile/app/(route)/settings.tsx(1 hunks)apps/mobile/store/authStorage.ts(1 hunks)apps/mobile/utils/getWebViewApiUrl.ts(1 hunks)apps/mobile/utils/sendMessageToWeb.ts(1 hunks)apps/mobile/utils/webViewLoadHandler.ts(1 hunks)apps/web/api/auth.ts(1 hunks)apps/web/api/getWebApiUrl.ts(1 hunks)apps/web/app/_components/AuthGuard.tsx(1 hunks)apps/web/app/_hooks/useAppRouter.ts(1 hunks)apps/web/app/_hooks/useDetectWebView.ts(1 hunks)apps/web/app/_hooks/useSignInMutation.ts(3 hunks)apps/web/app/_hooks/useWebView.ts(0 hunks)apps/web/app/constants/devices.ts(1 hunks)apps/web/app/settings/_components/ResponsiveSettingsPage.tsx(2 hunks)apps/web/app/store/updateWebViewAuthStore.ts(1 hunks)apps/web/app/utils/detectDevice.ts(1 hunks)apps/web/app/utils/detectWebView.ts(1 hunks)apps/web/app/utils/sendMessageToNative.ts(0 hunks)apps/web/components/Gnb/GnbMenu.tsx(2 hunks)apps/web/lib/axios.ts(1 hunks)apps/web/lib/bridge/createWebViewMessageBridge.ts(1 hunks)apps/web/lib/bridge/parseWebViewAuthMessage.ts(1 hunks)apps/web/lib/bridge/sendMessageToWebView.ts(1 hunks)packages/ui/src/types/WebViewMessageTypes.ts(1 hunks)packages/ui/src/utils/storage.ts(1 hunks)packages/ui/src/utils/stringifyJson.ts(1 hunks)
💤 Files with no reviewable changes (2)
- apps/web/app/utils/sendMessageToNative.ts
- apps/web/app/_hooks/useWebView.ts
✅ Files skipped from review due to trivial changes (1)
- apps/web/app/constants/devices.ts
🚧 Files skipped from review as they are similar to previous changes (9)
- apps/web/lib/axios.ts
- apps/mobile/app/(route)/settings.tsx
- apps/web/app/_components/AuthGuard.tsx
- apps/web/api/auth.ts
- apps/web/app/_hooks/useSignInMutation.ts
- apps/web/app/settings/_components/ResponsiveSettingsPage.tsx
- apps/mobile/app/(route)/dashboard.tsx
- apps/mobile/app/(route)/seats.tsx
- apps/mobile/app/(route)/meetings.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
apps/mobile/store/authStorage.ts
[error] 30-30: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Unsafe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🔇 Additional comments (11)
apps/web/lib/bridge/sendMessageToWebView.ts (1)
3-6: 인터페이스 설계가 잘 되었습니다!제네릭을 사용한 Message 인터페이스가 타입 안정성을 보장하며, 다양한 데이터 타입을 지원할 수 있도록 설계되었습니다.
apps/web/app/utils/detectDevice.ts (1)
3-6: 디바이스 정보 인터페이스가 명확합니다.
DeviceInfo인터페이스가 간단하고 명확하게 정의되어 있습니다.apps/web/app/store/updateWebViewAuthStore.ts (1)
7-7: 🛠️ Refactor suggestion데이터 유효성 검사 강화 필요
accessToken확인 외에도user객체의 구조와 필수 필드에 대한 유효성 검사가 필요합니다.- if (!data.accessToken) return; + if (!data.accessToken || !data.user?.id) return;apps/web/lib/bridge/createWebViewMessageBridge.ts (3)
11-17: WebView 환경이 아닐 때의 처리가 적절합니다.브라우저나 SSR 환경에서 실행될 때 빈 구현을 반환하는 것은 좋은 방어적 프로그래밍 사례입니다.
21-28: 플랫폼별 메시지 리스너 구현이 잘 되어있습니다.iOS와 Android의 이벤트 처리 방식 차이를 적절히 고려하여 구현되었습니다.
29-31: 메시지 전송 시 타입 안전성 검토가 필요합니다.
stringifyJson함수 사용 시 실패할 경우에 대한 에러 처리가 누락되어 있습니다.다음과 같이 에러 처리를 추가하는 것을 고려해보세요:
sendMessageToWebView: <T>({ type, data }: Message<T>): void => { - window.ReactNativeWebView?.postMessage(stringifyJson({ type, data })); + try { + const message = stringifyJson({ type, data }); + window.ReactNativeWebView?.postMessage(message); + } catch (error) { + console.error('메시지 직렬화 중 오류 발생:', error); + } },apps/mobile/utils/webViewLoadHandler.ts (1)
26-44: 플랫폼별 로드 이벤트 처리가 잘 구현되어 있습니다.iOS와 Android의 WebView 로드 이벤트 차이를 적절히 고려하여 구현되었습니다.
apps/web/components/Gnb/GnbMenu.tsx (1)
11-11: useDetectWebView 훅으로의 마이그레이션이 적절합니다.기존 useWebView에서 useDetectWebView로의 변경이 잘 이루어졌습니다.
Also applies to: 34-34
apps/mobile/utils/sendMessageToWeb.ts (1)
10-14: 🛠️ Refactor suggestion메시지 전송 시 에러 처리가 필요합니다.
WebView 메시지 전송 과정에서 발생할 수 있는 예외 상황에 대한 처리가 없습니다.
다음과 같이 수정하는 것을 제안합니다:
export const sendMessageToWeb = <T>({ webViewRef, type, data }: SendMessage<T>) => { if (webViewRef.current) { - webViewRef.current.postMessage(stringifyJson({ type, data })); + try { + webViewRef.current.postMessage(stringifyJson({ type, data })); + } catch (error) { + console.error('WebView 메시지 전송 실패:', error); + } } };Likely invalid or redundant comment.
apps/mobile/app/(route)/index.tsx (2)
17-22: 🛠️ Refactor suggestion메시지 처리 로직 개선이 필요합니다.
메시지 처리 과정에서 발생할 수 있는 예외 상황에 대한 처리가 없으며, 타입 검증이 부족합니다.
다음과 같이 수정하는 것을 제안합니다:
const handleMessage = (e: WebViewMessageEvent) => { + try { handleNavigationActions(e); const { type, data } = parseMessage(e); handleAuthStorage(type, data); + } catch (error) { + console.error('메시지 처리 중 오류 발생:', error); + } };Likely invalid or redundant comment.
25-34: 🛠️ Refactor suggestionWebView 에러 처리 및 사용자 경험 개선이 필요합니다.
WebView 로딩 실패나 네트워크 오류 등의 상황에 대한 처리가 없어 사용자 경험이 저하될 수 있습니다.
다음과 같이 수정하는 것을 제안합니다:
<WebView ref={webviewRef} source={{ uri: `${baseUrl}` }} onMessage={handleMessage} {...{ [event]: handler }} className="flex-1" cacheEnabled javaScriptEnabled domStorageEnabled + onError={(syntheticEvent) => { + const { nativeEvent } = syntheticEvent; + console.warn('WebView 오류:', nativeEvent); + }} + renderError={(errorName) => ( + <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> + <Text>페이지를 불러올 수 없습니다. ({errorName})</Text> + </View> + )} />Likely invalid or redundant comment.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
apps/web/app/_hooks/useDetectWebView.ts (1)
13-21: 🛠️ Refactor suggestion웹뷰 감지 로직 개선 필요
이전 리뷰에서 지적된 사항들이 아직 반영되지 않았습니다.
apps/web/app/_hooks/useSignInMutation.ts (1)
35-40:⚠️ Potential issue웹뷰 메시지 전송 시 오류 처리가 필요합니다.
웹뷰로 메시지를 전송하는 과정에서 발생할 수 있는 예외 상황에 대한 처리가 누락되어 있습니다.
다음과 같이 수정을 제안드립니다:
if (isWebView) { try { sendMessageToWebView({ type: WEBVIEW_MESSAGE_TYPES.SIGN_IN_SUCCESS, data: { user, accessToken }, }); } catch (error) { console.error('웹뷰 메시지 전송 실패:', error); notify('error', '자동 로그인 설정 중 오류가 발생했습니다.'); } }
🧹 Nitpick comments (3)
apps/web/lib/bridge/detectWebView.ts (2)
16-22: iOS 웹뷰 감지 로직에 대한 상세 주석 추가 필요현재 주석이 간단하게만 작성되어 있습니다. 각 조건문이 어떤 목적으로 추가되었는지 상세한 설명이 있으면 유지보수에 도움이 될 것 같습니다.
11-14: 사용자 에이전트 파싱 실패에 대한 예외 처리 필요
window.navigator.userAgent접근 시 발생할 수 있는 예외 상황에 대한 처리가 필요합니다.다음과 같이 개선하는 것을 추천드립니다:
export const detectWebView = (): WebViewInfo => { if (typeof window === "undefined") return DEFAULT_WEBVIEW_INFO; + try { const userAgent = window.navigator.userAgent; + } catch (error) { + console.error('Failed to detect user agent:', error); + return DEFAULT_WEBVIEW_INFO; + }apps/web/app/_components/AuthGuard.tsx (1)
16-18: 웹뷰 이벤트 리스너 생성 로직 최적화 필요
webViewEventListener를 컴포넌트 렌더링마다 새로 생성하지 않도록useMemo를 사용하는 것이 좋습니다.다음과 같이 개선하는 것을 추천드립니다:
+ import { useEffect, useState, useMemo } from "react"; // ... const { isIOSWebView, isAndroidWebView } = useDetectWebView(); - const webViewEventListener = createWebViewEventListener({ isIOSWebView, isAndroidWebView }); + const webViewEventListener = useMemo( + () => createWebViewEventListener({ isIOSWebView, isAndroidWebView }), + [isIOSWebView, isAndroidWebView] + );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
apps/mobile/app/(route)/index.tsx(1 hunks)apps/mobile/hooks/useHandleNavigationActions.ts(1 hunks)apps/mobile/store/authStorage.ts(1 hunks)apps/web/api/getWebApiUrl.ts(1 hunks)apps/web/app/_components/AuthGuard.tsx(1 hunks)apps/web/app/_hooks/useAppRouter.ts(1 hunks)apps/web/app/_hooks/useDetectWebView.ts(1 hunks)apps/web/app/_hooks/useSignInMutation.ts(2 hunks)apps/web/app/settings/_components/ResponsiveSettingsPage.tsx(2 hunks)apps/web/lib/bridge/createWebViewEventListener.ts(1 hunks)apps/web/lib/bridge/detectWebView.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/web/api/getWebApiUrl.ts
- apps/web/app/_hooks/useAppRouter.ts
- apps/web/app/settings/_components/ResponsiveSettingsPage.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
apps/mobile/store/authStorage.ts
[error] 30-30: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Unsafe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🔇 Additional comments (7)
apps/web/app/_hooks/useSignInMutation.ts (2)
8-8: 웹뷰 관련 의존성이 적절히 추가되었습니다!웹뷰 메시지 타입과 브릿지 유틸리티가 잘 구성되어 있습니다.
Also applies to: 13-14
24-24: 웹뷰 감지 로직의 구조 개선이 필요합니다.현재 구조에서는 웹뷰 감지와 메시지 전송 로직이 혼재되어 있습니다. 다음과 같은 개선을 제안드립니다:
sendMessageToWebView를 단순 유틸리티 함수로 변경- 웹뷰 감지와 라우팅 로직을 별도의 커스텀 훅으로 분리
예시 구조:
// useHandleSignInSuccess.ts const useHandleSignInSuccess = () => { const { isWebView } = useDetectWebView(); const router = useRouter(); const handleSuccess = async (data: SignInResponseType) => { if (isWebView) { sendMessageToNative({ type: WEBVIEW_MESSAGE_TYPES.SIGN_IN_SUCCESS, data: { user: data.user, accessToken: data.accessToken } }); } await delay(1000); router.replace(PAGE_NAME.DASHBOARD); }; return handleSuccess; };apps/mobile/hooks/useHandleNavigationActions.ts (1)
12-15: 메시지 처리 로직이 개선되었습니다!타입 안전성이 향상되었고 코드가 더 간결해졌습니다. 조기 반환 패턴을 사용하여 가독성도 좋아졌네요.
apps/mobile/app/(route)/index.tsx (2)
25-31: 🛠️ Refactor suggestionWebView 에러 처리가 필요합니다.
WebView 로딩 실패나 네트워크 오류 등의 상황에 대한 처리가 없습니다.
다음과 같이 수정하는 것을 제안합니다:
<WebView ref={webviewRef} source={{ uri: `${baseUrl}` }} onMessage={handleMessage} {...{ [event]: handler }} className="flex-1" + onError={(syntheticEvent) => { + const { nativeEvent } = syntheticEvent; + console.warn('WebView 에러:', nativeEvent); + }} + renderError={(errorName) => ( + <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> + <Text>페이지를 불러올 수 없습니다. ({errorName})</Text> + </View> + )} />Likely invalid or redundant comment.
17-22:⚠️ Potential issue메시지 처리에 에러 핸들링이 필요합니다.
메시지 파싱 및 처리 과정에서 발생할 수 있는 예외 상황에 대한 처리가 여전히 누락되어 있습니다.
다음과 같이 수정하는 것을 제안합니다:
const handleMessage = (e: WebViewMessageEvent) => { + try { const { type, data } = parseMessage(e); handleNavigationActions({ type, data }); handleAuthStorage({ type, data }); + } catch (error) { + console.error('메시지 처리 중 오류 발생:', error); + } };Likely invalid or redundant comment.
apps/mobile/store/authStorage.ts (2)
27-37: 🛠️ Refactor suggestionswitch 문의 case 블록 스코프 처리가 필요합니다.
각 case 문에서 선언된 변수가 다른 case 문에서 접근 가능한 문제가 있습니다.
다음과 같이 수정하는 것을 제안합니다:
export const handleAuthStorage = async ({ type, data }: Message<LoginData>) => { switch (type) { case WEBVIEW_MESSAGE_TYPES.SIGN_IN_SUCCESS: { + const { user, accessToken } = data; + await setAuthData({ accessToken, user }); + break; + } case WEBVIEW_MESSAGE_TYPES.SIGN_OUT_SUCCESS: await clearAuthData(); break; } };Likely invalid or redundant comment.
🧰 Tools
🪛 Biome (1.9.4)
[error] 30-30: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.The declaration is defined in this switch clause:
Unsafe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
7-14:⚠️ Potential issueJSON 파싱 에러 처리가 필요합니다.
JSON.parse호출 시 발생할 수 있는 에러에 대한 처리가 누락되어 있습니다.다음과 같이 수정하는 것을 제안합니다:
export const getAuthData = async () => { const [accessToken, userStr] = await Promise.all([AsyncStorage.getItem("accessToken"), AsyncStorage.getItem("user")]); + let user = null; + if (userStr) { + try { + user = JSON.parse(userStr); + } catch (error) { + console.error('사용자 데이터 파싱 중 오류 발생:', error); + } + } return { accessToken, - user: userStr ? JSON.parse(userStr) : null, + user, }; };Likely invalid or redundant comment.
There was a problem hiding this comment.
Actionable comments posted: 0
🔭 Outside diff range comments (1)
apps/api/src/controllers/teamController.ts (1)
Line range hint
354-359: 트랜잭션 처리 개선이 필요합니다.벌크 업데이트 후 팀 목록을 조회하는 로직이 추가되었습니다. 다음 개선사항을 고려해주세요:
- 벌크 업데이트와 조회 작업을 트랜잭션으로 래핑하여 데이터 일관성을 보장해야 합니다.
- 동시 업데이트 시 발생할 수 있는 경쟁 상태를 방지해야 합니다.
다음과 같이 트랜잭션을 적용하는 것을 추천드립니다:
- await Team.bulkWrite(bulkOperations); - const reorderedTeams = await Team.find().sort({ order: 1 }).lean(); + const session = await Team.startSession(); + let reorderedTeams; + + try { + await session.withTransaction(async () => { + await Team.bulkWrite(bulkOperations, { session }); + reorderedTeams = await Team.find().sort({ order: 1 }).lean().session(session); + }); + } finally { + await session.endSession(); + }
🧹 Nitpick comments (1)
apps/web/app/dashboard/_components/EmptyState.tsx (1)
25-36: 가독성 개선을 위한 리팩토링을 제안드립니다.현재 구현은 정확하지만, 중첩된 조건부 렌더링과 스프레드 연산자의 사용으로 인해 코드의 가독성이 다소 떨어집니다.
다음과 같이 리팩토링하는 것을 고려해보세요:
- <Button - variant="Secondary" - as={isWebView ? "button" : Link} - {...(isWebView - ? { - type: "button", - onClick: handleButtonClick, - } - : { - href: PAGE_NAME.MEETINGS, - })} - > + <Button + variant="Secondary" + as={isWebView ? "button" : Link} + type={isWebView ? "button" : undefined} + onClick={isWebView ? handleButtonClick : undefined} + href={!isWebView ? PAGE_NAME.MEETINGS : undefined} + >이렇게 하면:
- 조건부 로직이 더 명확해집니다
- 스프레드 연산자 없이 props를 직접 전달합니다
- 각 prop의 목적이 더 분명해집니다
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
apps/api/src/controllers/teamController.ts(1 hunks)apps/api/src/models/teamModel.ts(1 hunks)apps/mobile/tsconfig.json(1 hunks)apps/web/app/_hooks/useAppRouter.ts(1 hunks)apps/web/app/dashboard/_components/EmptyState.tsx(2 hunks)apps/web/app/settings/_components/SettingButtons.tsx(2 hunks)apps/web/lib/bridge/sendMessageToWebView.ts(1 hunks)apps/web/next.config.mjs(0 hunks)
💤 Files with no reviewable changes (1)
- apps/web/next.config.mjs
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/mobile/tsconfig.json
- apps/web/app/_hooks/useAppRouter.ts
- apps/web/lib/bridge/sendMessageToWebView.ts
🔇 Additional comments (5)
apps/web/app/dashboard/_components/EmptyState.tsx (2)
5-13: 훌륭한 구현입니다!커스텀 훅을 활용하여 웹뷰 감지와 라우팅 로직을 깔끔하게 분리했습니다. React의 모범 사례를 잘 따르고 있습니다.
15-16: 명확한 함수명 변경입니다!
handleOnClick에서handleButtonClick으로의 이름 변경은 함수의 목적을 더 명확하게 표현합니다.apps/web/app/settings/_components/SettingButtons.tsx (2)
23-23: onClick 이벤트 핸들러 업데이트가 적절히 이루어졌습니다.함수 이름 변경에 따른 호출부 업데이트가 정확하게 반영되었습니다.
10-12: 함수 이름이 더 일반적인 의미로 변경되었습니다.
handleOpenModal에서handleClick으로의 이름 변경이 함수의 재사용성을 높일 수 있지만, 이 함수가 모달을 여는 것에 특화되어 있다는 점을 고려할 때 이전 이름이 더 명확했을 수 있습니다.이 변경이 다른 컴포넌트에서의 재사용을 위한 것인지 확인이 필요합니다:
✅ Verification successful
함수 이름 변경이 적절합니다
handleOpenModal에서handleClick으로의 이름 변경이 문제가 되지 않습니다. 이 함수는SettingButtons.tsx컴포넌트 내부에서만 사용되며, 다른 컴포넌트에서 재사용되지 않습니다. 따라서 컴포넌트의 맥락 내에서 의미가 명확하게 전달됩니다.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: 다른 파일에서 handleClick 함수의 사용 여부 확인 rg "handleClick.*ModalComponentType" --type tsxLength of output: 77
Script:
#!/bin/bash # Search for both old and new function names in TypeScript files rg -t typescript -t typescriptreact "handle(Click|OpenModal).*Modal" # Also search for general modal usage patterns rg -t typescript -t typescriptreact "openModal\(" -A 2Length of output: 197
Script:
#!/bin/bash # Search in the settings directory for both function names cd apps/web/app/settings && find . -type f -exec grep -l "handle\(Click\|OpenModal\)" {} \; # Look for modal-related patterns in the same directory cd apps/web/app/settings && find . -type f -exec grep -l "openModal" {} \;Length of output: 279
apps/api/src/models/teamModel.ts (1)
9-9:order필드의 제약 조건 변경에 대한 검토가 필요합니다.
unique제약 조건이 제거되었습니다. 이는updateTeamOrder컨트롤러의 일괄 업데이트 기능과 일치하지만, 다음 사항을 고려해야 합니다:
- 동시성 문제가 발생할 수 있습니다.
- 중복된 order 값이 발생할 수 있습니다.
다음 스크립트를 실행하여 현재 중복된 order 값이 있는지 확인하십시오:
✅ Verification successful
order필드의 제약 조건 변경이 적절합니다.
unique제약 조건 제거는 다음과 같은 이유로 안전합니다:
teamController.ts의 일괄 업데이트가 원자적 연산으로 처리됩니다.- 순차적인 인덱스 기반 주문으로 일관성이 보장됩니다.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for duplicate order values in teams collection mongosh --eval ' db.teams.aggregate([ { $group: { _id: "$order", count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } } ]) 'Length of output: 295
Script:
#!/bin/bash # Search for files containing team order updates rg -l "order" --type ts # Check for specific order update patterns ast-grep --pattern 'order: { type: Number }' # Look for concurrent update operations rg -B 2 -A 2 "updateMany|findOneAndUpdate|updateOne" --type tsLength of output: 2920
🚀 작업 내용
React Native Webview 자동로그인을 구현했습니다.
구현 시나리오 및 흐름
1. 초기 상태 (로그인 되지 않은 상태)
2. 사용자가 로그인에 성공한 경우
3. 앱을 재실행 하는 경우
추가 내용
플랫폼 별 웹뷰 메세지 처리
react-device-detect 라이브러리를 설치했습니다.
pnpm install부탁드려욥~Window에서는 IOS 시뮬레이터 사용이 불가하기 때문에 Expo Go 어플을 이용해서 테스트 했습니다.
확인결과 에러메세지 토스트 발생 시, 토스트가 노치에 가려지는 현상이 있네유
기능 구현 이후에 각각에 플랫폼에 맞게 디자인 수정도 필요할 듯 합니당
🚨 관련 이슈 (이슈 번호)
✅ 체크리스트
Summary by CodeRabbit
다음은 릴리즈 노트입니다:
새로운 기능
개선 사항
버그 수정
기타 변경사항