feat: 쇼핑몰 연동 옷등록 api 연동#32
Conversation
📝 WalkthroughWalkthroughAdds a full shopping-mall link clothes registration flow: a Zustand draft store, ChangesShopping-mall link registration flow
Sequence Diagram(s)sequenceDiagram
actor User
participant ShoppingMallTermsScreen
participant ShoppingMallLinkRegistrationScreen
participant fetchProductLinkPreview
participant useShoppingMallRegistrationStore
participant ShoppingMallLinkStyleScreen
participant ShoppingMallLinkDetailsScreen
participant createClothesFromLink
rect rgba(100, 149, 237, 0.5)
note over User, ShoppingMallTermsScreen: Terms Gate
User->>ShoppingMallTermsScreen: mount
ShoppingMallTermsScreen->>ShoppingMallTermsScreen: checkAgreement (hasAgreedToShoppingMallTerms)
alt already agreed
ShoppingMallTermsScreen-->>User: redirect to shopping-mall route
else not agreed
ShoppingMallTermsScreen-->>User: render agreement UI
User->>ShoppingMallTermsScreen: agree + continue
ShoppingMallTermsScreen->>ShoppingMallTermsScreen: saveShoppingMallTermsAgreement
ShoppingMallTermsScreen-->>User: navigate to link entry
end
end
rect rgba(144, 238, 144, 0.5)
note over User, useShoppingMallRegistrationStore: Link Preview
User->>ShoppingMallLinkRegistrationScreen: submit URL
ShoppingMallLinkRegistrationScreen->>fetchProductLinkPreview: fetchProductLinkPreview(url)
fetchProductLinkPreview-->>ShoppingMallLinkRegistrationScreen: ProductLinkPreview or ApiError
ShoppingMallLinkRegistrationScreen->>useShoppingMallRegistrationStore: setDraft(preview fields)
ShoppingMallLinkRegistrationScreen-->>User: navigate to style screen
end
rect rgba(255, 165, 0, 0.5)
note over User, createClothesFromLink: Style + Details + Save
User->>ShoppingMallLinkStyleScreen: select color/category → next
ShoppingMallLinkStyleScreen->>useShoppingMallRegistrationStore: setDraft(color, category)
User->>ShoppingMallLinkDetailsScreen: enter date, price, closet section → save
ShoppingMallLinkDetailsScreen->>createClothesFromLink: createClothesFromLink(payload)
createClothesFromLink-->>ShoppingMallLinkDetailsScreen: result or ApiError
ShoppingMallLinkDetailsScreen->>useShoppingMallRegistrationStore: resetDraft()
ShoppingMallLinkDetailsScreen-->>User: navigate to completion + optional toast
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/features/clothes-registration/api/link-preview-api.ts (1)
39-49: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value
sourceShopguard accepts any string, not the declared union.
isProductLinkPreviewonly checkstypeof candidate.sourceShop === "string", so an unexpected value would still be cast to the"MUSINSA" | "ABLY" | "ZIGZAG" | "UNKNOWN"union. This is a type-soundness gap rather than a runtime crash; consider narrowing against the allowed set (or falling back to"UNKNOWN") if downstream code switches on it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/clothes-registration/api/link-preview-api.ts` around lines 39 - 49, `isProductLinkPreview` currently treats `candidate.sourceShop` as any string, which is wider than the declared `"MUSINSA" | "ABLY" | "ZIGZAG" | "UNKNOWN"` union. Update the guard in `link-preview-api.ts` so `sourceShop` is validated against the allowed enum-like values (or normalized to `"UNKNOWN"`), alongside the existing checks for `sourceUrl`, `productName`, and the other fields, so downstream switches on `sourceShop` remain type-safe.src/features/clothes-registration/api/create-clothes-from-link-api.ts (1)
87-90: 🩺 Stability & Availability | 🔵 TrivialConsider adding an explicit timeout to
createClothesFromLink.apiClientdefaults to 10s, while the link preview flow already extends to 30s. If this endpoint also does external fetch/persistence work, the default can cut off valid requests too early.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/clothes-registration/api/create-clothes-from-link-api.ts` around lines 87 - 90, The createClothesFromLink request currently relies on the apiClient default timeout, which may be too short for link-based fetch and persistence work. Update createClothesFromLink in create-clothes-from-link-api.ts to pass an explicit longer timeout on the apiClient.post call, consistent with the slower link preview flow, so valid requests are not aborted prematurely.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen.tsx`:
- Around line 76-95: Reset the loading state in
ShoppingMallLinkRegistrationScreen’s link fetch flow because router.push keeps
this screen mounted in the stack, leaving it stuck in a loading state when
returning. Update the try path around fetchProductLinkPreview, setDraft, and
router.push so fetchState is set back to "idle" before or immediately after
navigating to clothesRegistrationRoutes.shoppingMallStyle, while keeping the
existing error handling unchanged.
In `@src/features/clothes-registration/screens/ShoppingMallTermsScreen.tsx`:
- Around line 39-49: In ShoppingMallTermsScreen, the redirect path in the
agreement check still clears the loading state in the finally block, which
causes the terms UI to flash before navigation. Update the logic around the
hasAgreed branch in the agreement-checking effect so that when
router.replace(clothesRegistrationRoutes.shoppingMallLink) is triggered, the
screen keeps showing the spinner and does not call setIsCheckingAgreement(false)
for that redirect path. Use the existing isMounted, hasAgreed, and
setIsCheckingAgreement flow to separate the redirect case from the normal
failure/unknown case.
---
Nitpick comments:
In `@src/features/clothes-registration/api/create-clothes-from-link-api.ts`:
- Around line 87-90: The createClothesFromLink request currently relies on the
apiClient default timeout, which may be too short for link-based fetch and
persistence work. Update createClothesFromLink in
create-clothes-from-link-api.ts to pass an explicit longer timeout on the
apiClient.post call, consistent with the slower link preview flow, so valid
requests are not aborted prematurely.
In `@src/features/clothes-registration/api/link-preview-api.ts`:
- Around line 39-49: `isProductLinkPreview` currently treats
`candidate.sourceShop` as any string, which is wider than the declared
`"MUSINSA" | "ABLY" | "ZIGZAG" | "UNKNOWN"` union. Update the guard in
`link-preview-api.ts` so `sourceShop` is validated against the allowed enum-like
values (or normalized to `"UNKNOWN"`), alongside the existing checks for
`sourceUrl`, `productName`, and the other fields, so downstream switches on
`sourceShop` remain type-safe.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 03e42a42-35ee-4a49-a647-553598f3eb09
⛔ Files ignored due to path filters (1)
assets/image-placeholder.svgis excluded by!**/*.svg
📒 Files selected for processing (15)
app/(main)/clothes/register/shopping-mall/details.tsxapp/(main)/clothes/register/shopping-mall/style.tsxsrc/features/clothes-registration/api/create-clothes-from-link-api.test.tssrc/features/clothes-registration/api/create-clothes-from-link-api.tssrc/features/clothes-registration/api/link-preview-api.test.tssrc/features/clothes-registration/api/link-preview-api.tssrc/features/clothes-registration/data/shopping-mall-terms-agreement.tssrc/features/clothes-registration/routes.tssrc/features/clothes-registration/screens/ClothesStyleSelector.tsxsrc/features/clothes-registration/screens/ShoppingMallLinkRegistrationFlowScreens.tsxsrc/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen.tsxsrc/features/clothes-registration/screens/ShoppingMallManualRegistrationScreens.tsxsrc/features/clothes-registration/screens/ShoppingMallTermsScreen.tsxsrc/lib/storage/keys.tssrc/stores/useShoppingMallRegistrationStore.ts
| try { | ||
| const preview = await fetchProductLinkPreview(url.trim()); | ||
|
|
||
| setDraft({ | ||
| sourceUrl: preview.sourceUrl, | ||
| productName: preview.productName, | ||
| imageUrl: preview.imageUrl, | ||
| price: preview.price, | ||
| color: preview.color, | ||
| category: preview.category, | ||
| purchaseDate: null, | ||
| storageLocation: null, | ||
| sectionId: null, | ||
| }); | ||
| router.push(clothesRegistrationRoutes.shoppingMallStyle); | ||
| } catch { | ||
| setErrorMessage("상품 정보를 불러올 수 없습니다. 상품 페이지를 확인하거나 직접 입력해 주세요."); | ||
| setFetchState("error"); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the target screen and adjacent navigation/state logic.
git ls-files | rg 'src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen\.tsx|src/features/clothes-registration/routes|src/features/clothes-registration'
echo '---'
ast-grep outline src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen.tsx --view expanded
echo '---'
cat -n src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen.tsx | sed -n '1,220p'Repository: WEARTRACK/FE
Length of output: 11793
🏁 Script executed:
#!/bin/bash
set -euo pipefail
git ls-files | rg 'src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen\.tsx|src/features/clothes-registration/routes|src/features/clothes-registration'
echo '---'
ast-grep outline src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen.tsx --view expanded
echo '---'
cat -n src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen.tsx | sed -n '1,220p'Repository: WEARTRACK/FE
Length of output: 11793
🏁 Script executed:
#!/bin/bash
set -euo pipefail
git ls-files | rg 'src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen\.tsx|src/features/clothes-registration/routes|src/features/clothes-registration'
echo '---'
ast-grep outline src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen.tsx --view expanded
echo '---'
cat -n src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen.tsx | sed -n '1,220p'Repository: WEARTRACK/FE
Length of output: 11793
🏁 Script executed:
#!/bin/bash
set -euo pipefail
set -euo pipefail
echo '--- routes.ts ---'
cat -n src/features/clothes-registration/routes.ts | sed -n '1,220p'
echo '--- ShoppingMallLinkRegistrationFlowScreens.tsx ---'
cat -n src/features/clothes-registration/screens/ShoppingMallLinkRegistrationFlowScreens.tsx | sed -n '1,240p'
echo '--- ShoppingMallManualRegistrationScreens.tsx ---'
cat -n src/features/clothes-registration/screens/ShoppingMallManualRegistrationScreens.tsx | sed -n '1,240p'
echo '--- ShoppingMallTermsScreen.tsx (outline only) ---'
ast-grep outline src/features/clothes-registration/screens/ShoppingMallTermsScreen.tsx --view expandedRepository: WEARTRACK/FE
Length of output: 18389
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- routes.ts ---'
cat -n src/features/clothes-registration/routes.ts | sed -n '1,220p'
echo '--- ShoppingMallLinkRegistrationFlowScreens.tsx ---'
cat -n src/features/clothes-registration/screens/ShoppingMallLinkRegistrationFlowScreens.tsx | sed -n '1,240p'
echo '--- ShoppingMallManualRegistrationScreens.tsx ---'
cat -n src/features/clothes-registration/screens/ShoppingMallManualRegistrationScreens.tsx | sed -n '1,240p'
echo '--- ShoppingMallTermsScreen.tsx (outline only) ---'
ast-grep outline src/features/clothes-registration/screens/ShoppingMallTermsScreen.tsx --view expandedRepository: WEARTRACK/FE
Length of output: 18389
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- routes.ts ---'
cat -n src/features/clothes-registration/routes.ts | sed -n '1,220p'
echo '--- ShoppingMallLinkRegistrationFlowScreens.tsx ---'
cat -n src/features/clothes-registration/screens/ShoppingMallLinkRegistrationFlowScreens.tsx | sed -n '1,240p'
echo '--- ShoppingMallManualRegistrationScreens.tsx ---'
cat -n src/features/clothes-registration/screens/ShoppingMallManualRegistrationScreens.tsx | sed -n '1,240p'
echo '--- files containing ShoppingMallLinkRegistrationScreen references ---'
rg -n "ShoppingMallLinkRegistrationScreen|shoppingMallStyle|shoppingMallManualStyle" src/features/clothes-registration -g '!**/*.svg'Repository: WEARTRACK/FE
Length of output: 19003
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- routes.ts ---'
cat -n src/features/clothes-registration/routes.ts | sed -n '1,220p'
echo '--- ShoppingMallLinkRegistrationFlowScreens.tsx ---'
cat -n src/features/clothes-registration/screens/ShoppingMallLinkRegistrationFlowScreens.tsx | sed -n '1,240p'
echo '--- ShoppingMallManualRegistrationScreens.tsx ---'
cat -n src/features/clothes-registration/screens/ShoppingMallManualRegistrationScreens.tsx | sed -n '1,240p'
echo '--- files containing ShoppingMallLinkRegistrationScreen references ---'
rg -n "ShoppingMallLinkRegistrationScreen|shoppingMallStyle|shoppingMallManualStyle" src/features/clothes-registration -g '!**/*.svg'Repository: WEARTRACK/FE
Length of output: 19003
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- files with Stack / unmountOnBlur / shopping-mall layout ---'
rg -n "unmountOnBlur|<Stack|createNativeStackNavigator|shopping-mall|shoppingMallStyle|shoppingMallLink|shoppingMallManualStyle" src app -g '!**/*.svg'
echo '--- likely layout files under app ---'
git ls-files | rg '(^app/.*layout\.(tsx|ts)$|(^src/.*layout\.(tsx|ts)$))'
echo '--- shopping mall route files ---'
git ls-files | rg 'shopping-mall|clothes/register'Repository: WEARTRACK/FE
Length of output: 3433
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- files with Stack / unmountOnBlur / shopping-mall layout ---'
rg -n "unmountOnBlur|<Stack|createNativeStackNavigator|shopping-mall|shoppingMallStyle|shoppingMallLink|shoppingMallManualStyle" src app -g '!**/*.svg'
echo '--- likely layout files under app ---'
git ls-files | rg '(^app/.*layout\.(tsx|ts)$|(^src/.*layout\.(tsx|ts)$))'
echo '--- shopping mall route files ---'
git ls-files | rg 'shopping-mall|clothes/register'Repository: WEARTRACK/FE
Length of output: 3433
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- files with Stack / unmountOnBlur / shopping-mall layout ---'
rg -n "unmountOnBlur|<Stack|createNativeStackNavigator|shopping-mall|shoppingMallStyle|shoppingMallLink|shoppingMallManualStyle" src app -g '!**/*.svg'
echo '--- likely layout files under app ---'
git ls-files | rg '(^app/.*layout\.(tsx|ts)$|(^src/.*layout\.(tsx|ts)$))'
echo '--- shopping mall route files ---'
git ls-files | rg 'shopping-mall|clothes/register'Repository: WEARTRACK/FE
Length of output: 3433
🌐 Web query:
Expo Router Stack push previous screen remains mounted back gesture behavior documentation React Navigation stack inactive screens stay mounted
💡 Result:
In Expo Router, which is built upon React Navigation, the Stack navigator operates by maintaining a history of screens [1]. When you perform a "push" navigation, the new screen is added to the top of the stack, and the previous screen remains mounted in the background [2][3]. This is the standard behavior for stack navigators, allowing for performant transitions and the ability to return to the previous state exactly as it was left [2][3]. Regarding back gesture behavior and screen mounting: 1. Inactive Screens Stay Mounted: By default, React Navigation's stack navigator does not unmount inactive screens when a new screen is pushed on top of them [3]. They remain in the navigation state, keeping their component instance alive [3]. This is intentional to ensure that going back (via back gesture or router.back()) is instantaneous and preserves the user's scroll position, input state, and other component data [2]. 2. Customizing Push/Navigation Behavior: If you observe that navigating to a route does not push a new screen but instead navigates to an existing instance, it is likely due to the navigator's default logic that prevents pushing duplicate routes [4][2]. You can override this behavior by using the getId prop on your <Stack.Screen> component to ensure that the stack treats different parameters as unique screens, forcing a new push instead of reusing an existing screen [4][5]. 3. Controlling Back Behavior: If you need to intercept or prevent the back gesture, you can use the beforeRemove event listener on the navigation object via the useNavigation hook [6]. This allows you to perform custom logic (like showing a confirmation alert) or prevent the default pop action entirely [6]. 4. Deep Linking and Initial Routes: If your back navigation seems to behave unexpectedly when deep linking directly to nested screens, ensure you have configured unstable_settings with an initialRouteName in your layout file [1]. This tells the stack which screen should be considered the "root" of that stack, ensuring the back button or gesture correctly returns to that screen rather than exiting the stack entirely [1]. If you are seeing performance issues or excessive memory usage due to too many mounted screens, consider using router.replace() when navigating to avoid building an unnecessarily deep stack [7][1][8].
Citations:
- 1: https://docs.expo.dev/router/basics/navigation/
- 2: https://medium.com/@jacrplante/react-native-screens-using-react-navigation-stacks-33ad366eafb9
- 3: https://source--react-navigation-docs.netlify.app/docs/stack-navigator/
- 4: https://docs.expo.dev/router/advanced/stack/
- 5: Stack Navigator Goes Back to Previous Screen if Route Matches, Even if Params Are Different on v2 expo/router#747
- 6: https://stackoverflow.com/questions/75826317/prevent-default-back-navigation-when-using-expo-router
- 7: https://www.youtube.com/watch?v=izZv6a99Roo
- 8: https://medium.com/@coby09/building-seamless-navigation-in-expo-router-tabs-modals-and-stacks-2df1a5522321
🌐 Web query:
Expo Router Stack push previous screen remains mounted back gesture behavior documentation React Navigation stack inactive screens stay mounted
💡 Result:
Short answer: In Expo Router (which uses React Navigation), the “previous screen stays mounted” behavior is expected with stacks unless you opt into specific unmount/pause options; inactive screens are normally kept rendered/paused depending on configuration. The back-swipe/gesture behavior is controlled by React Navigation stack options like gestureEnabled/fullScreenGestureEnabled and by iOS/native-screens behavior. 1) Why the previous screen often remains mounted when you push a new screen - React Navigation’s stack does not generally unmount the previous screen when you navigate forward; it keeps the existing instance and shows the new screen, then unmounts on back only when the stack removes it. - React Navigation Native Stack (and React Navigation stack with react-native-screens integration) provides an inactiveBehavior option to control what happens to inactive screens (unmount vs pause vs none). React Navigation documents that inactiveBehavior supports values pause, unmount, and none, and the default is pause.[1][2] - pause cleans up effects while keeping the screen “inactive” (so you may still see state not being fully torn down the way an unmount would).[1][2] - unmount actually unmounts when the screen becomes inactive (state is lost).[1] - Separately, React Navigation also documents detachInactiveScreens (default true) to detach inactive screens from the view hierarchy to save memory, and detachPreviousScreen to control whether the previous screen remains visible through the active screen.[3] Practical implication for your Expo Router question (“previous screen remains mounted back gesture behavior”): - If you observe that the prior screen is still mounted (or appears to resume without a full remount) after pushing, that aligns with stack “inactive” behavior not necessarily being unmount.[1][2] 2) How to change inactive screens behavior (unmount/pause) React Navigation Stack docs show the config for inactiveBehavior on the stack navigator (this is applicable to Expo Router’s <Stack> as it forwards native stack options): - Set inactiveBehavior: 'unmount' to unmount inactive screens when they lose focus.[1] - Set inactiveBehavior: 'pause' (default) to clean up effects when inactive but keep the screen in memory.[1][2] - Set inactiveBehavior: 'none' to keep rendering normally.[2] 3) Expo Router Stack push/back gesture options (gesture behavior documentation) Expo Router’s Stack docs list important iOS gesture-related options: - gestureEnabled (enables back gestures for the screen; used with the stack’s native iOS gesture system in React Navigation/Native Stack). [4] - fullScreenGestureEnabled (iOS): whether the gesture to dismiss should work on the whole screen; defaults to false.[4] - animationMatchesGesture (iOS): whether the gesture-dismiss should use the animation provided to the stack’s animation prop; defaults to false.[4] These options directly relate to “back gesture behavior” in Expo Router stacks.[4] 4) Notes on reported weird behavior when using iOS back-swipe quickly - There is an Expo GitHub issue describing “strange router behavior on fast back gesture multiple times on iOS,” including cases where it appears the navigation “replays” itself.[5] - The same issue notes a scenario with gestureEnabled/gesture disable differences and suggests it may be related to react-native-screens behavior.[5] 5) Putting it together (what you should check) - If your goal is to ensure the previous screen does NOT remain mounted (state fully reset), configure the stack to unmount inactive screens: use inactiveBehavior: 'unmount'.[1][2] - If your goal is to fix/shape iOS back-swipe behavior, verify you’re using the correct Expo Router stack screenOptions such as gestureEnabled and (if needed) fullScreenGestureEnabled, and ensure your animation configuration is appropriate (e.g., animationMatchesGesture).[4] If you share the exact Expo Router <Stack> configuration (including screenOptions, presentation, and whether you use nested stacks/tabs), I can tell you which specific option most likely causes your “previous screen remains mounted” observation and how to adjust it.
Citations:
- 1: https://reactnavigation.org/docs/8.x/navigation-lifecycle/
- 2: https://reactnavigation.org/docs/8.x/stack-navigator/
- 3: https://reactnavigation.org/docs/stack-navigator/
- 4: https://docs.expo.dev/router/advanced/stack/
- 5: Strange router behavior on fast back gesture multiple times on iOS expo/expo#38936
Reset fetchState after navigating to the style screen
router.push(...) keeps this screen in the stack, so coming back returns to the loading state with no retry button. Set fetchState back to "idle" before or after the push.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/features/clothes-registration/screens/ShoppingMallLinkRegistrationScreen.tsx`
around lines 76 - 95, Reset the loading state in
ShoppingMallLinkRegistrationScreen’s link fetch flow because router.push keeps
this screen mounted in the stack, leaving it stuck in a loading state when
returning. Update the try path around fetchProductLinkPreview, setDraft, and
router.push so fetchState is set back to "idle" before or immediately after
navigating to clothesRegistrationRoutes.shoppingMallStyle, while keeping the
existing error handling unchanged.
| if (hasAgreed) { | ||
| router.replace(clothesRegistrationRoutes.shoppingMallLink); | ||
| return; | ||
| } | ||
| } catch { | ||
| // If the local cache cannot be read, show the agreement screen again. | ||
| } finally { | ||
| if (isMounted) { | ||
| setIsCheckingAgreement(false); | ||
| } | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Already-agreed users may briefly see the terms screen before redirect.
When hasAgreed is true, router.replace is queued but the finally block still runs setIsCheckingAgreement(false), re-rendering the full terms UI for a frame before navigation completes. Keep showing the spinner on the redirect path.
🩹 Proposed fix to keep the spinner during redirect
if (hasAgreed) {
router.replace(clothesRegistrationRoutes.shoppingMallLink);
return;
}
} catch {
// If the local cache cannot be read, show the agreement screen again.
+ if (isMounted) {
+ setIsCheckingAgreement(false);
+ }
+ return;
} finally {
- if (isMounted) {
- setIsCheckingAgreement(false);
- }
}
+
+ if (isMounted) {
+ setIsCheckingAgreement(false);
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (hasAgreed) { | |
| router.replace(clothesRegistrationRoutes.shoppingMallLink); | |
| return; | |
| } | |
| } catch { | |
| // If the local cache cannot be read, show the agreement screen again. | |
| } finally { | |
| if (isMounted) { | |
| setIsCheckingAgreement(false); | |
| } | |
| } | |
| if (hasAgreed) { | |
| router.replace(clothesRegistrationRoutes.shoppingMallLink); | |
| return; | |
| } | |
| } catch { | |
| // If the local cache cannot be read, show the agreement screen again. | |
| if (isMounted) { | |
| setIsCheckingAgreement(false); | |
| } | |
| return; | |
| } finally { | |
| } | |
| if (isMounted) { | |
| setIsCheckingAgreement(false); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/features/clothes-registration/screens/ShoppingMallTermsScreen.tsx` around
lines 39 - 49, In ShoppingMallTermsScreen, the redirect path in the agreement
check still clears the loading state in the finally block, which causes the
terms UI to flash before navigation. Update the logic around the hasAgreed
branch in the agreement-checking effect so that when
router.replace(clothesRegistrationRoutes.shoppingMallLink) is triggered, the
screen keeps showing the spinner and does not call setIsCheckingAgreement(false)
for that redirect path. Use the existing isMounted, hasAgreed, and
setIsCheckingAgreement flow to separate the redirect case from the normal
failure/unknown case.
✨ 기능 요약
📌 작업 내용
🌱 참고 사항
Summary by CodeRabbit
New Features
Bug Fixes