-
Notifications
You must be signed in to change notification settings - Fork 13
Hotfix/crisp ios issue #1403
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Hotfix/crisp ios issue #1403
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| '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> | ||
| ) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,106 @@ | ||||||||||||||||||||
| 'use client' | ||||||||||||||||||||
|
|
||||||||||||||||||||
| import { useState, useEffect } from 'react' | ||||||||||||||||||||
| import { useCrispIframeReady } from '@/hooks/useCrispIframeReady' | ||||||||||||||||||||
| import PeanutLoading from '../PeanutLoading' | ||||||||||||||||||||
| import { Button } from '@/components/0_Bruddle' | ||||||||||||||||||||
|
|
||||||||||||||||||||
| interface CrispIframeProps { | ||||||||||||||||||||
| crispProxyUrl: string | ||||||||||||||||||||
| enabled?: boolean | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** | ||||||||||||||||||||
| * Shared Crisp iframe component with loading and error states | ||||||||||||||||||||
| * DRY component used by both SupportDrawer and SupportPage | ||||||||||||||||||||
| */ | ||||||||||||||||||||
| export const CrispIframe = ({ crispProxyUrl, enabled = true }: CrispIframeProps) => { | ||||||||||||||||||||
| const [componentError, setComponentError] = useState<string | null>(null) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // 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() } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
Comment on lines
+20
to
+27
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix unconditional hook call violation. Wrapping 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 📝 Committable suggestion
Suggested change
🧰 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. (lint/correctness/useHookAtTopLevel) 🤖 Prompt for AI Agents |
||||||||||||||||||||
|
|
||||||||||||||||||||
| const { isReady, hasError, retry } = hookState | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Debug logging for iOS | ||||||||||||||||||||
| 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]) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Catch render errors | ||||||||||||||||||||
| if (componentError) { | ||||||||||||||||||||
| return ( | ||||||||||||||||||||
| <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">Something went wrong</p> | ||||||||||||||||||||
| <p className="text-sm text-grey-1"> | ||||||||||||||||||||
| Please email us at{' '} | ||||||||||||||||||||
| <a href="mailto:support@peanut.me" className="text-purple-1 underline"> | ||||||||||||||||||||
| support@peanut.me | ||||||||||||||||||||
| </a> | ||||||||||||||||||||
| </p> | ||||||||||||||||||||
| {componentError && <p className="text-xs text-error">{componentError}</p>} | ||||||||||||||||||||
| </div> | ||||||||||||||||||||
| <Button | ||||||||||||||||||||
| onClick={() => window.location.reload()} | ||||||||||||||||||||
| shadowSize="4" | ||||||||||||||||||||
| variant="purple" | ||||||||||||||||||||
| icon="retry" | ||||||||||||||||||||
| iconSize={16} | ||||||||||||||||||||
| > | ||||||||||||||||||||
| Reload page | ||||||||||||||||||||
| </Button> | ||||||||||||||||||||
| </div> | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| return ( | ||||||||||||||||||||
| <> | ||||||||||||||||||||
| {!isReady && ( | ||||||||||||||||||||
| <div className="absolute inset-0 z-10 flex items-center justify-center bg-background"> | ||||||||||||||||||||
| <PeanutLoading /> | ||||||||||||||||||||
| </div> | ||||||||||||||||||||
| )} | ||||||||||||||||||||
| {hasError && ( | ||||||||||||||||||||
| <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" | ||||||||||||||||||||
| /> | ||||||||||||||||||||
|
Comment on lines
+79
to
+103
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Retry button never reloads the Crisp iframe.
'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 |
||||||||||||||||||||
| </> | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| } | ||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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