Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughReplaces local iframe readiness/polling logic with a shared Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review in depth.
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 15797 @Hugo0, here's my in-depth review: 1. ✅ Does this fix the iOS support chat not rendering issue?Yes, this should fix the issue. The root cause is correctly identified and addressed:
The fix targets the exact problem: iOS Safari streaming deadlock. 2.
|
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/app/(mobile-ui)/support/page.tsx(1 hunks)src/app/crisp-proxy/page.tsx(4 hunks)src/components/Global/SupportDrawer/index.tsx(1 hunks)src/hooks/useCrispIframeReady.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 942
File: src/components/AddMoney/consts/index.ts:2151-2162
Timestamp: 2025-06-30T10:44:08.048Z
Learning: Hugo0 often agrees with refactoring suggestions but defers implementation due to time constraints, preferring to track improvements as follow-up issues when they're part of larger architectural changes.
📚 Learning: 2025-08-07T12:53:50.946Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1072
File: src/app/(setup)/setup/page.tsx:173-175
Timestamp: 2025-08-07T12:53:50.946Z
Learning: In the peanut-ui setup flow at `src/app/(setup)/setup/page.tsx`, when handling unsupported scenarios, both device not supported and browser not supported cases should show the same "Unsupported browser" message using the `UnsupportedBrowserModal` component, rather than having distinct messaging for each scenario.
Applied to files:
src/app/(mobile-ui)/support/page.tsxsrc/components/Global/SupportDrawer/index.tsx
📚 Learning: 2024-10-23T09:38:27.670Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In `src/app/request/pay/page.tsx`, if `linkRes` is not OK in the `generateMetadata` function, the desired behavior is to use the standard title and preview image without throwing an error.
Applied to files:
src/app/(mobile-ui)/support/page.tsx
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.
Applied to files:
src/app/crisp-proxy/page.tsx
📚 Learning: 2025-09-11T17:46:12.507Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.507Z
Learning: Functions in Next.js that are not marked with "use server" and contain secrets are unsafe to import in client components, as they get bundled into the client JavaScript and can leak environment variables to the browser.
Applied to files:
src/app/crisp-proxy/page.tsx
📚 Learning: 2025-09-11T17:46:12.507Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.507Z
Learning: In Next.js applications, functions marked with "use server" are server actions that are safe to import in client components. Next.js generates proxy stubs for these functions, ensuring the actual implementation and any secrets (like process.env variables) remain on the server and are not bundled into the client JavaScript.
Applied to files:
src/app/crisp-proxy/page.tsx
📚 Learning: 2025-09-15T17:25:12.198Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/hooks/useCreateOnramp.ts:47-49
Timestamp: 2025-09-15T17:25:12.198Z
Learning: Server Actions in Next.js are specifically designed to be called from Client Components. They are asynchronous functions marked with 'use server' that run on the server but can be imported and invoked directly from client-side code. This is a core feature of the Next.js App Router, eliminating the need to create separate API routes for server-side operations called from the client.
Applied to files:
src/app/crisp-proxy/page.tsx
📚 Learning: 2024-10-29T16:06:38.812Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
Applied to files:
src/app/crisp-proxy/page.tsx
🧬 Code graph analysis (3)
src/app/(mobile-ui)/support/page.tsx (3)
src/hooks/useCrispProxyUrl.ts (1)
useCrispProxyUrl(15-69)src/hooks/useCrispIframeReady.ts (1)
useCrispIframeReady(19-76)src/components/0_Bruddle/Button.tsx (1)
Button(78-269)
src/components/Global/SupportDrawer/index.tsx (2)
src/hooks/useCrispIframeReady.ts (1)
useCrispIframeReady(19-76)src/components/0_Bruddle/Button.tsx (1)
Button(78-269)
src/hooks/useCrispIframeReady.ts (1)
src/hooks/useGetDeviceType.ts (1)
useDeviceType(37-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
src/app/(mobile-ui)/support/page.tsx
Outdated
| <p className="text-sm text-grey-1"> | ||
| Check your internet connection and try again. If the problem persists, you can email us at{' '} | ||
| <a href="mailto:hello@peanut.to" className="text-purple-1 underline"> | ||
| support@peanut.me | ||
| </a> |
There was a problem hiding this comment.
Fix mismatched support email link.
The visible address says support@peanut.me while the link opens hello@peanut.to. Anyone copying the text will reach the wrong inbox. Please align the displayed text with the actual destination.
- <a href="mailto:hello@peanut.to" className="text-purple-1 underline">
- support@peanut.me
- </a>
+ <a href="mailto:hello@peanut.to" className="text-purple-1 underline">
+ hello@peanut.to
+ </a>📝 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.
| <p className="text-sm text-grey-1"> | |
| Check your internet connection and try again. If the problem persists, you can email us at{' '} | |
| <a href="mailto:hello@peanut.to" className="text-purple-1 underline"> | |
| support@peanut.me | |
| </a> | |
| <p className="text-sm text-grey-1"> | |
| Check your internet connection and try again. If the problem persists, you can email us at{' '} | |
| <a href="mailto:hello@peanut.to" className="text-purple-1 underline"> | |
| hello@peanut.to | |
| </a> |
🤖 Prompt for AI Agents
In src/app/(mobile-ui)/support/page.tsx around lines 27 to 31, the anchor href
uses mailto:hello@peanut.to while the visible text shows support@peanut.me;
update the anchor so the mailto destination matches the displayed address
(change href to mailto:support@peanut.me) to ensure the link sends mail to the
same support address shown to users.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/app/(mobile-ui)/support/page.tsx(1 hunks)src/components/Global/CrispIframe/index.tsx(1 hunks)src/components/Global/SupportDrawer/index.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:279-279
Timestamp: 2025-08-14T08:02:26.705Z
Learning: For hotfixes in the peanut-ui codebase, prefer generic error messages over specific validation error details until the copy can be reviewed with the team, even when the validation functions return detailed error messages.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 942
File: src/components/AddMoney/consts/index.ts:2151-2162
Timestamp: 2025-06-30T10:44:08.048Z
Learning: Hugo0 often agrees with refactoring suggestions but defers implementation due to time constraints, preferring to track improvements as follow-up issues when they're part of larger architectural changes.
📚 Learning: 2025-08-07T12:53:50.946Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1072
File: src/app/(setup)/setup/page.tsx:173-175
Timestamp: 2025-08-07T12:53:50.946Z
Learning: In the peanut-ui setup flow at `src/app/(setup)/setup/page.tsx`, when handling unsupported scenarios, both device not supported and browser not supported cases should show the same "Unsupported browser" message using the `UnsupportedBrowserModal` component, rather than having distinct messaging for each scenario.
Applied to files:
src/app/(mobile-ui)/support/page.tsx
📚 Learning: 2025-07-24T13:26:10.290Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1014
File: src/components/Claim/Link/Initial.view.tsx:413-413
Timestamp: 2025-07-24T13:26:10.290Z
Learning: In the peanut-ui repository, the change from `${SQUID_API_URL}/route` to `${SQUID_API_URL}/v2/route` in src/components/Claim/Link/Initial.view.tsx was a typo fix, not an API migration, as the codebase was already using Squid API v2.
Applied to files:
src/app/(mobile-ui)/support/page.tsx
📚 Learning: 2025-08-14T08:02:26.705Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:279-279
Timestamp: 2025-08-14T08:02:26.705Z
Learning: For hotfixes in the peanut-ui codebase, prefer generic error messages over specific validation error details until the copy can be reviewed with the team, even when the validation functions return detailed error messages.
Applied to files:
src/app/(mobile-ui)/support/page.tsx
🧬 Code graph analysis (3)
src/app/(mobile-ui)/support/page.tsx (3)
src/hooks/useCrispUserData.ts (1)
useCrispUserData(23-56)src/hooks/useCrispProxyUrl.ts (1)
useCrispProxyUrl(15-69)src/components/Global/CrispIframe/index.tsx (1)
CrispIframe(16-54)
src/components/Global/CrispIframe/index.tsx (3)
src/hooks/useCrispIframeReady.ts (1)
useCrispIframeReady(19-76)src/components/Global/PeanutLoading/index.tsx (1)
PeanutLoading(4-19)src/components/0_Bruddle/Button.tsx (1)
Button(78-269)
src/components/Global/SupportDrawer/index.tsx (4)
src/context/SupportModalContext.tsx (1)
useSupportModalContext(39-45)src/hooks/useCrispUserData.ts (1)
useCrispUserData(23-56)src/hooks/useCrispProxyUrl.ts (1)
useCrispProxyUrl(15-69)src/components/Global/CrispIframe/index.tsx (1)
CrispIframe(16-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (2)
src/app/(mobile-ui)/support/page.tsx (1)
5-14: Shared CrispIframe integration looks good.Import and usage align with the shared component; no issues spotted.
src/components/Global/SupportDrawer/index.tsx (1)
7-20: Drawer wiring to CrispIframe checks out.Passing the proxy URL and gating readiness with the drawer’s open state matches the shared hook’s contract.
| <div className="absolute inset-0 z-20 flex flex-col items-center justify-center gap-4 bg-background p-6 text-center"> | ||
| <div className="space-y-2"> | ||
| <p className="text-base font-semibold">Having trouble loading support chat</p> | ||
| <p className="text-sm text-grey-1"> | ||
| Check your internet connection and try again. If the problem persists, you can email us at{' '} | ||
| <a href="mailto:support@peanut.me" className="text-purple-1 underline"> | ||
| support@peanut.me | ||
| </a> | ||
| </p> | ||
| </div> | ||
| <Button onClick={retry} shadowSize="4" variant="purple" icon="retry" iconSize={16}> | ||
| Try again | ||
| </Button> | ||
| </div> | ||
| )} | ||
| <iframe | ||
| src={crispProxyUrl} | ||
| className="h-full w-full" | ||
| style={{ | ||
| height: '100%', | ||
| width: '100%', | ||
| minHeight: '-webkit-fill-available', | ||
| }} | ||
| title="Support Chat" | ||
| /> |
There was a problem hiding this comment.
Retry button never reloads the Crisp iframe.
retry only resets hook state; the <iframe> keeps its original instance, so iOS users stuck on a blank load stay stuck even after pressing “Try again.” Please force a remount (or cache-busting source) when retrying so the Crisp proxy actually reloads.
'use client'
+import { useCallback, useState } from 'react'
import { useCrispIframeReady } from '@/hooks/useCrispIframeReady'
import PeanutLoading from '../PeanutLoading'
import { Button } from '@/components/0_Bruddle'
@@
-export const CrispIframe = ({ crispProxyUrl, enabled = true }: CrispIframeProps) => {
- const { isReady, hasError, retry } = useCrispIframeReady(enabled)
+export const CrispIframe = ({ crispProxyUrl, enabled = true }: CrispIframeProps) => {
+ const [reloadNonce, setReloadNonce] = useState(0)
+ const { isReady, hasError, retry } = useCrispIframeReady(enabled)
+ const handleRetry = useCallback(() => {
+ setReloadNonce((prev) => prev + 1)
+ retry()
+ }, [retry])
@@
- <Button onClick={retry} shadowSize="4" variant="purple" icon="retry" iconSize={16}>
+ <Button onClick={handleRetry} shadowSize="4" variant="purple" icon="retry" iconSize={16}>
Try again
</Button>
</div>
)}
<iframe
+ key={reloadNonce}
src={crispProxyUrl}
className="h-full w-full"🤖 Prompt for AI Agents
In src/components/Global/CrispIframe/index.tsx around lines 27 to 51, the Retry
button only resets hook state but does not cause the iframe to reload, so on iOS
the original iframe instance remains blank; update the retry handler to force a
remount or cache-bust the iframe src: add a local key or stamp state (e.g.
reloadCounter or srcTimestamp) that is incremented/updated in retry and pass it
as the iframe key or append it as a query param to crispProxyUrl so React
unmounts/remounts the iframe (or the browser treats the URL as new) and the
Crisp proxy actually reloads.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/components/Global/CrispIframe/index.tsx (1)
89-89: Retry button doesn't reload the iframe.As noted in the previous review, the
retryfunction only resets hook state but doesn't cause the iframe to remount or reload its source. Users experiencing a blank Crisp load will remain stuck even after clicking "Try again."Add a key prop to force iframe remount on retry:
+'use client' + +import { useCallback, useState } from 'react' import { useCrispIframeReady } from '@/hooks/useCrispIframeReady' import PeanutLoading from '../PeanutLoading' import { Button } from '@/components/0_Bruddle' export const CrispIframe = ({ crispProxyUrl, enabled = true }: CrispIframeProps) => { + const [iframeKey, setIframeKey] = useState(0) const { isReady, hasError, retry } = useCrispIframeReady(enabled) + + const handleRetry = useCallback(() => { + setIframeKey((prev) => prev + 1) + retry() + }, [retry]) // ... rest of component ... - <Button onClick={retry} shadowSize="4" variant="purple" icon="retry" iconSize={16}> + <Button onClick={handleRetry} shadowSize="4" variant="purple" icon="retry" iconSize={16}> Try again </Button> </div> )} <iframe + key={iframeKey} src={crispProxyUrl}
🧹 Nitpick comments (1)
src/components/Global/CrispIframe/index.tsx (1)
32-42: Consider consolidating debug logs.The two separate
useEffecthooks for logging serve different purposes but could be combined for cleaner code. Given this is debug instrumentation for the iOS fix, the current approach is acceptable.If you prefer, consolidate into one effect:
- useEffect(() => { - console.log('[CrispIframe] Component mounted', { - enabled, - crispProxyUrl, - userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'SSR', - }) - }, [enabled, crispProxyUrl]) - - useEffect(() => { - console.log('[CrispIframe] State:', { isReady, hasError }) - }, [isReady, hasError]) + useEffect(() => { + console.log('[CrispIframe] Mount/Update:', { + enabled, + crispProxyUrl, + isReady, + hasError, + userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'SSR', + }) + }, [enabled, crispProxyUrl, isReady, hasError])
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/app/(mobile-ui)/support-test/page.tsx(1 hunks)src/app/(mobile-ui)/support/page.tsx(1 hunks)src/components/Global/CrispIframe/index.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/app/(mobile-ui)/support/page.tsx
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:279-279
Timestamp: 2025-08-14T08:02:26.705Z
Learning: For hotfixes in the peanut-ui codebase, prefer generic error messages over specific validation error details until the copy can be reviewed with the team, even when the validation functions return detailed error messages.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 942
File: src/components/AddMoney/consts/index.ts:2151-2162
Timestamp: 2025-06-30T10:44:08.048Z
Learning: Hugo0 often agrees with refactoring suggestions but defers implementation due to time constraints, preferring to track improvements as follow-up issues when they're part of larger architectural changes.
🧬 Code graph analysis (1)
src/components/Global/CrispIframe/index.tsx (3)
src/hooks/useCrispIframeReady.ts (1)
useCrispIframeReady(19-76)src/components/0_Bruddle/Button.tsx (1)
Button(78-269)src/components/Global/PeanutLoading/index.tsx (1)
PeanutLoading(4-19)
🪛 Biome (2.1.2)
src/components/Global/CrispIframe/index.tsx
[error] 23-23: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
🪛 GitHub Actions: Tests
src/app/(mobile-ui)/support-test/page.tsx
[warning] 1-1: Code style issues found in the file. Run 'prettier --write' to fix.
[error] 1-1: Prettier formatting check failed. Command 'pnpm prettier --check .' exited with code 1. Run 'pnpm prettier --write .' to fix code style issues.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (1)
src/components/Global/CrispIframe/index.tsx (1)
52-52: Confirm correct support email address with team.The codebase currently uses
support@peanut.meconsistently in both lines 52 and 84 ofsrc/components/Global/CrispIframe/index.tsx, with no instances ofhello@peanut.tofound. However, the review comment references inconsistencies between these two addresses.Please verify with your team which email address is the correct support contact. If
hello@peanut.tois the intended address, lines 52 and 84 need to be updated.
| 'use client' | ||
|
|
||
| /** | ||
| * MINIMAL TEST PAGE for iOS debugging | ||
| * This bypasses all custom hooks to test if basic rendering works | ||
| */ | ||
| export default function SupportTestPage() { | ||
| return ( | ||
| <div | ||
| style={{ | ||
| width: '100%', | ||
| height: '100vh', | ||
| background: '#f0f0f0', | ||
| display: 'flex', | ||
| alignItems: 'center', | ||
| justifyContent: 'center', | ||
| flexDirection: 'column', | ||
| padding: '20px', | ||
| }} | ||
| > | ||
| <h1 style={{ fontSize: '24px', marginBottom: '20px' }}>iOS Test Page</h1> | ||
| <p style={{ marginBottom: '10px' }}>If you see this, page rendering works!</p> | ||
| <p style={{ fontSize: '12px', color: '#666' }}> | ||
| User agent: {typeof navigator !== 'undefined' ? navigator.userAgent : 'Loading...'} | ||
| </p> | ||
| <div style={{ marginTop: '20px' }}> | ||
| <a href="/support" style={{ color: 'blue', textDecoration: 'underline' }}> | ||
| Try /support page | ||
| </a> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
There was a problem hiding this comment.
Fix formatting to pass CI checks.
The pipeline reports Prettier formatting issues that will block merge.
Run the following command to fix:
pnpm prettier --write .🧰 Tools
🪛 GitHub Actions: Tests
[warning] 1-1: Code style issues found in the file. Run 'prettier --write' to fix.
[error] 1-1: Prettier formatting check failed. Command 'pnpm prettier --check .' exited with code 1. Run 'pnpm prettier --write .' to fix code style issues.
🤖 Prompt for AI Agents
In src/app/(mobile-ui)/support-test/page.tsx lines 1-33, Prettier formatting
errors are blocking CI; run the project's formatter to fix the file (execute:
pnpm prettier --write .), review the modified file to ensure 'use client' and
JSX remain unchanged, stage and commit the formatted changes, and push to the
branch so CI can re-run.
| // Defensive: Catch any hook errors | ||
| let hookState | ||
| try { | ||
| hookState = useCrispIframeReady(enabled) | ||
| } catch (error) { | ||
| console.error('[CrispIframe] Hook error:', error) | ||
| hookState = { isReady: true, hasError: true, retry: () => window.location.reload() } | ||
| } |
There was a problem hiding this comment.
Fix unconditional hook call violation.
Wrapping useCrispIframeReady in a try/catch creates a conditional hook call, which violates the Rules of Hooks. React requires hooks to be called unconditionally at the top level of every render. If the hook throws, subsequent renders will have mismatched hook order, causing React errors.
Move error handling into the hook itself, or wrap this entire component in an error boundary:
- // Defensive: Catch any hook errors
- let hookState
- try {
- hookState = useCrispIframeReady(enabled)
- } catch (error) {
- console.error('[CrispIframe] Hook error:', error)
- hookState = { isReady: true, hasError: true, retry: () => window.location.reload() }
- }
-
- const { isReady, hasError, retry } = hookState
+ const { isReady, hasError, retry } = useCrispIframeReady(enabled)If you need error boundaries for the entire component, add one in the parent that renders <CrispIframe>.
📝 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.
| // Defensive: Catch any hook errors | |
| let hookState | |
| try { | |
| hookState = useCrispIframeReady(enabled) | |
| } catch (error) { | |
| console.error('[CrispIframe] Hook error:', error) | |
| hookState = { isReady: true, hasError: true, retry: () => window.location.reload() } | |
| } | |
| const { isReady, hasError, retry } = useCrispIframeReady(enabled) |
🧰 Tools
🪛 Biome (2.1.2)
[error] 23-23: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
🤖 Prompt for AI Agents
In src/components/Global/CrispIframe/index.tsx around lines 20 to 27, you
currently wrap the hook call in a try/catch which conditionally calls a hook and
violates the Rules of Hooks; instead, call useCrispIframeReady unconditionally
at the top of the component and move any try/catch/error handling into the hook
implementation (have the hook catch exceptions and return an error state like {
isReady:false, hasError:true, retry:() => ... }), or remove the try/catch here
and wrap the CrispIframe component in a React Error Boundary at the parent
level; update the component to use the error flags returned by the hook (or rely
on the boundary) and remove the local try/catch to ensure hooks are always
called in the same order.
Problem: Support drawer blank forever on iOS
Fix: Removed Suspense + manual URL params + device-specific timeouts
Status: Ready to test on iOS device
What Was Wrong
iOS Safari + Suspense + useSearchParams = streaming deadlock → blank screen forever