Skip to content

[TASK-13900] Feat/kyc modal changes#1137

Merged
Hugo0 merged 4 commits intopeanut-wallet-devfrom
feat/kyc-modal-changes
Aug 29, 2025
Merged

[TASK-13900] Feat/kyc modal changes#1137
Hugo0 merged 4 commits intopeanut-wallet-devfrom
feat/kyc-modal-changes

Conversation

@Zishan-7
Copy link
Contributor

No description provided.

@vercel
Copy link

vercel bot commented Aug 27, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
peanut-wallet Ready Ready Preview Comment Aug 29, 2025 0:06am

@notion-workspace
Copy link

KYC modal ui updates

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 27, 2025

Walkthrough

Adds a new StartVerificationView component and updates IframeWrapper to require a start step before mounting the iframe, introduce help/stop modals, clipboard copy and router actions, conditional close/confirmation behavior, and additional in-UI CTAs while retaining postMessage handling.

Changes

Cohort / File(s) Summary
New pre-verification view
src/components/Global/IframeWrapper/StartVerificationView.tsx
Adds StartVerificationView React component (client-side) rendering a two-panel UI with CloudsBackground and ThinkingPeanut illustration, explanatory copy, and a "Start Secure Verification" button that calls onStartVerification. Default export added.
IframeWrapper flow & UI controls
src/components/Global/IframeWrapper/index.tsx
Integrates StartVerificationView as a prerequisite step; adds state (isHelpModalOpen, modalVariant, copied, isVerificationStarted), handleCopy (clipboard), modalDetails via useMemo; introduces ActionModal, new bottom CTAs (copy link, contact support, stop/continue verification), overlay/pointer-event control, conditional close/confirmation flows, and preserves iframe postMessage handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • Hugo0
  • kushagrasarathe
  • jjramirezn
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/kyc-modal-changes

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/Global/IframeWrapper/index.tsx (1)

93-109: Validate postMessage origin and source to prevent spoofed closes.

Currently any window can post a crafted message to close the modal. Validate both event.origin against src and event.source against the iframe’s contentWindow.

-    useEffect(() => {
-        const handleMessage = (event: MessageEvent) => {
-            const data = event.data
-            if (data?.name === 'complete' && data?.metadata?.status === 'completed') {
-                onClose('completed')
-            }
-            // @dev note: kinda hacky, but tos modal takes too long to close using websocket, so we use the signedAgreementId to close it
-            // persona fires this event when the user clicks the "accept" button within the iframe
-            if (data?.signedAgreementId) {
-                onClose('tos_accepted')
-            }
-        }
-
-        window.addEventListener('message', handleMessage)
-        return () => window.removeEventListener('message', handleMessage)
-    }, [onClose])
+    useEffect(() => {
+        const expectedOrigin = (() => {
+            try {
+                return new URL(src, window.location.href).origin
+            } catch {
+                return undefined
+            }
+        })()
+
+        const handleMessage = (event: MessageEvent) => {
+            // Only accept messages from our iframe and expected origin
+            if (iframeRef.current && event.source !== iframeRef.current.contentWindow) return
+            if (expectedOrigin && event.origin !== expectedOrigin) return
+
+            const data = event.data
+            if (data?.name === 'complete' && data?.metadata?.status === 'completed') {
+                onClose('completed')
+            }
+            // Persona fires this when the user clicks "accept" within the iframe (TOS)
+            if (data?.signedAgreementId) {
+                onClose('tos_accepted')
+            }
+        }
+
+        window.addEventListener('message', handleMessage)
+        return () => window.removeEventListener('message', handleMessage)
+    }, [onClose, src])

Additional changes required elsewhere in this file are provided in separate comments (import useRef and attach ref to the iframe).

🧹 Nitpick comments (5)
src/components/Global/IframeWrapper/StartVerificationView.tsx (2)

13-19: Prefer passing the static import to Next/Image and improve alt text.

Pass the imported image object directly for optimal handling and use a more descriptive alt for accessibility.

-                <Image
-                    src={ThinkingPeanut.src}
-                    alt="verification"
+                <Image
+                    src={ThinkingPeanut}
+                    alt="Illustration of Peanut thinking during identity verification"
                     className="relative w-full max-w-72 object-contain md:max-w-80"
                     height={100}
                     width={100}
                 />

23-24: Consider using h2 inside a modal to avoid multiple h1s on a page.

If this renders within a page that already has an h1, switch to h2 for better document outline.

-                <h1 className="text-3xl font-extrabold">Secure Verification. Limited Data Use.</h1>
+                <h2 className="text-3xl font-extrabold">Secure Verification. Limited Data Use.</h2>
src/components/Global/IframeWrapper/index.tsx (3)

25-30: Harden clipboard copy with error handling.

navigator.clipboard can fail (HTTP, permissions). Add try/catch and avoid silent failures.

-    const handleCopy = (textToCopy: string) => {
-        navigator.clipboard.writeText(textToCopy).then(() => {
-            setCopied(true)
-            setTimeout(() => setCopied(false), 2000)
-        })
-    }
+    const handleCopy = async (textToCopy: string) => {
+        try {
+            await navigator.clipboard.writeText(textToCopy)
+            setCopied(true)
+            window.setTimeout(() => setCopied(false), 2000)
+        } catch (err) {
+            console.error('Copy to clipboard failed', err)
+        }
+    }

179-186: Attach a ref to the iframe and grant microphone permission if Persona needs liveness/audio.

Ref is required for event.source checks. Also consider microphone permission; many KYC flows need it.

-                            <iframe
-                                key={src}
-                                src={src}
-                                allow="camera;"
+                            <iframe
+                                key={src}
+                                ref={iframeRef}
+                                src={src}
+                                allow="camera; microphone;"
                                 style={{ width: '100%', height: '80%', border: 'none' }}
                                 className="rounded-md"
                                 sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-top-navigation-by-user-activation"
                             />

If microphone isn’t required, keeping camera only is fine—please confirm with Persona integration notes.


86-92: Reset verification-start state when modal hides.

Without reset, reopening the modal skips the pre-verification screen. Reset on visibility change.

     useEffect(() => {
         if (!visible || src === '') {
             setShowCloseConfirmMessage(false)
         }
+        if (!visible) {
+            setIsVerificationStarted(false)
+        }
     }, [visible, src])
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b0aedbc and 0f45b54.

📒 Files selected for processing (2)
  • src/components/Global/IframeWrapper/StartVerificationView.tsx (1 hunks)
  • src/components/Global/IframeWrapper/index.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/components/Global/IframeWrapper/StartVerificationView.tsx (1)
src/components/0_Bruddle/Button.tsx (1)
  • Button (76-267)
src/components/Global/IframeWrapper/index.tsx (2)
src/components/Global/Icons/Icon.tsx (2)
  • IconName (62-120)
  • Icon (189-198)
src/components/0_Bruddle/Button.tsx (2)
  • ButtonVariant (7-16)
  • Button (76-267)
⏰ 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/components/Global/IframeWrapper/StartVerificationView.tsx (1)

33-35: LGTM: Clear primary action and wiring.

Primary CTA text is explicit and correctly calls onStartVerification.

src/components/Global/IframeWrapper/index.tsx (1)

134-137: Two-phase render is clean and reduces third‑party load until intent is clear.

Nice UX touch to defer iframe load until the user opts in.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/components/Global/IframeWrapper/index.tsx (1)

1-1: Harden postMessage handling: validate origin and source; add iframe ref.

Currently any window can trigger completion/close. Bind to the iframe window and verify event.origin against src. Also import/use useRef.

-import { useEffect, useMemo, useState } from 'react'
+import { useEffect, useMemo, useRef, useState } from 'react'
@@
-    const router = useRouter()
+    const router = useRouter()
+    const iframeRef = useRef<HTMLIFrameElement>(null)
+    const allowedOrigin = useMemo(() => {
+        try {
+            return new URL(src).origin
+        } catch {
+            return null
+        }
+    }, [src])
@@
-    useEffect(() => {
-        const handleMessage = (event: MessageEvent) => {
-            const data = event.data
-            if (data?.name === 'complete' && data?.metadata?.status === 'completed') {
-                onClose('completed')
-            }
-            // @dev note: kinda hacky, but tos modal takes too long to close using websocket, so we use the signedAgreementId to close it
-            // persona fires this event when the user clicks the "accept" button within the iframe
-            if (data?.signedAgreementId) {
-                onClose('tos_accepted')
-            }
-        }
-
-        window.addEventListener('message', handleMessage)
-        return () => window.removeEventListener('message', handleMessage)
-    }, [onClose])
+    useEffect(() => {
+        const handleMessage = (event: MessageEvent) => {
+            const data = event.data
+            // Enforce origin and source checks
+            if (allowedOrigin && event.origin !== allowedOrigin) return
+            if (iframeRef.current && event.source !== iframeRef.current.contentWindow) return
+            if (data?.name === 'complete' && data?.metadata?.status === 'completed') {
+                onClose('completed')
+                return
+            }
+            // persona fires this event when the user clicks the "accept" button within the iframe
+            if (data?.signedAgreementId) {
+                onClose('tos_accepted')
+            }
+        }
+        window.addEventListener('message', handleMessage)
+        return () => window.removeEventListener('message', handleMessage)
+    }, [onClose, allowedOrigin])
@@
-                        <iframe
+                        <iframe
+                            ref={iframeRef}
                             key={src}
                             src={src}
                             allow="camera;"

Also applies to: 23-24, 93-109, 178-185

🧹 Nitpick comments (4)
src/components/Global/IframeWrapper/index.tsx (4)

25-31: Handle clipboard API failures.

Add catch/finally to avoid silent failures and ensure copied state resets.

-    const handleCopy = (textToCopy: string) => {
-        navigator.clipboard.writeText(textToCopy).then(() => {
-            setCopied(true)
-            setTimeout(() => setCopied(false), 2000)
-        })
-    }
+    const handleCopy = (textToCopy: string) => {
+        navigator.clipboard
+            .writeText(textToCopy)
+            .then(() => setCopied(true))
+            .catch((err) => {
+                console.warn('Clipboard write failed:', err)
+            })
+            .finally(() => {
+                setTimeout(() => setCopied(false), 2000)
+            })
+    }

126-131: Avoid background click-through when help modal is open.

Removing pointer-events-none from the outer overlay prevents interacting with the page behind while the ActionModal is on top.

-            classOverlay={`bg-black bg-opacity-50 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}
+            classOverlay="bg-black bg-opacity-50"
-            className={`z-[100] !p-0 md:!p-6 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}
+            className={`z-[100] !p-0 md:!p-6 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}

If ActionModal’s overlay fully covers the viewport, this change is sufficient; otherwise consider adding inert/aria-hidden to the underlying container when the help modal is open.

Also applies to: 128-129


142-159: Set type="button" on non-submit buttons.

Prevents unintended form submission if wrapped by a form.

-                                    <button
+                                    <button
+                                        type="button"
                                         className="btn-stroke h-10"
@@
-                                    <button
+                                    <button
+                                        type="button"
                                         className="btn-purple h-10"
@@
-                            <button
+                            <button
+                                type="button"
                                 className="btn-purple h-14 w-full rounded-none border-b border-n-1"
@@
-                            <button
+                            <button
+                                type="button"
                                 onClick={() => {

Also applies to: 162-174, 200-209


115-123: Replace brittle src.includes('tos') checks with a parsed URL helper.

String includes can misfire; parse the URL once and reuse.

-    const router = useRouter()
+    const router = useRouter()
+    const isTosFlow = useMemo(() => {
+        try {
+            const u = new URL(src)
+            return u.pathname.includes('/tos') || u.searchParams.get('flow') === 'tos'
+        } catch {
+            return src.includes('tos')
+        }
+    }, [src])
@@
-                if (src.includes('tos')) {
+                if (isTosFlow) {
                     onClose('manual')
                     return
                 }
@@
-                                    if (enableConfirmationPrompt && !src.includes('tos')) {
+                                    if (enableConfirmationPrompt && !isTosFlow) {
                                         setShowCloseConfirmMessage(true)
                                     } else {
                                         onClose('manual')
                                     }

Also applies to: 166-171, 23-24

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0f45b54 and ccf384d.

📒 Files selected for processing (1)
  • src/components/Global/IframeWrapper/index.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/Global/IframeWrapper/index.tsx (2)
src/components/Global/Icons/Icon.tsx (2)
  • IconName (62-120)
  • Icon (189-198)
src/components/0_Bruddle/Button.tsx (2)
  • ButtonVariant (7-16)
  • Button (76-267)
⏰ 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/IframeWrapper/index.tsx (1)

181-185: Update iframe allow to include both camera and microphone

Persona’s Embedded Flow iframe must have permissions for both video and audio capture. The SDK itself generates an iframe with allow="camera;microphone"(docs.withpersona.com). No clipboard-write permission is required for document uploads.

Please update in src/components/Global/IframeWrapper/index.tsx (around lines 181–185):

-   allow="camera;"
+   allow="camera; microphone"

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/components/Global/IframeWrapper/index.tsx (1)

200-209: Good accessibility fix: span → button.

Switching to a semantic button improves keyboard and a11y. LGTM.

🧹 Nitpick comments (3)
src/components/Global/IframeWrapper/index.tsx (3)

25-30: Handle clipboard failures (permissions/HTTP contexts).

Wrap clipboard write in try/catch to avoid silent failures and optionally surface a toast.

-    const handleCopy = (textToCopy: string) => {
-        navigator.clipboard.writeText(textToCopy).then(() => {
-            setCopied(true)
-            setTimeout(() => setCopied(false), 2000)
-        })
-    }
+    const handleCopy = async (textToCopy: string) => {
+        try {
+            await navigator.clipboard.writeText(textToCopy)
+            setCopied(true)
+            setTimeout(() => setCopied(false), 2000)
+        } catch (err) {
+            console.error('Clipboard write failed', err)
+            // TODO: show user feedback / fallback
+        }
+    }

114-125: DRY up close-confirm logic and avoid brittle "includes('tos')".

The same rule appears twice and relies on substring matching. Centralize the check and parse URL instead.

-            onClose={() => {
-                if (!enableConfirmationPrompt) {
-                    onClose('manual')
-                    return
-                }
-                if (src.includes('tos')) {
-                    onClose('manual')
-                    return
-                }
-                setShowCloseConfirmMessage(true)
-            }}
+            onClose={() => {
+                if (!shouldConfirmClose) {
+                    onClose('manual')
+                    return
+                }
+                setShowCloseConfirmMessage(true)
+            }}
-                                onClick={() => {
-                                    // only show confirmation for kyc step, otherwise close immediately
-                                    if (enableConfirmationPrompt && !src.includes('tos')) {
-                                        setShowCloseConfirmMessage(true)
-                                    } else {
-                                        onClose('manual')
-                                    }
-                                }}
+                                onClick={() => {
+                                    if (shouldConfirmClose) {
+                                        setShowCloseConfirmMessage(true)
+                                    } else {
+                                        onClose('manual')
+                                    }
+                                }}

Add supporting code outside ranges:

const isTosFlow = (u: string) => {
    try {
        const url = new URL(u, typeof window !== 'undefined' ? window.location.origin : undefined)
        return url.pathname.includes('/tos') || url.searchParams.get('flow') === 'tos'
    } catch {
        return u.includes('tos') // fallback
    }
}
const shouldConfirmClose = enableConfirmationPrompt && !isTosFlow(src)

Also applies to: 166-174


177-186: Layout nit: avoid fixed 80%/20% split to reduce double-scroll issues.

Use flex: let the iframe flex-1 and keep actions as shrink-0.

-                    <div className="h-full w-full flex-grow overflow-scroll">
+                    <div className="h-full w-full flex-grow overflow-hidden flex flex-col">
...
-                        <iframe
+                        <iframe
                             key={src}
                             src={src}
                             allow="camera;"
-                            style={{ width: '100%', height: '80%', border: 'none' }}
-                            className="rounded-md"
+                            style={{ width: '100%', border: 'none' }}
+                            className="rounded-md flex-1 min-h-0"
                             sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-top-navigation-by-user-activation"
                         />
-                        <div className="flex h-1/5 w-full flex-col items-center justify-center gap-4 px-5">
+                        <div className="flex w-full flex-col items-center justify-center gap-4 px-5 py-4 shrink-0">

Also applies to: 186-211

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ccf384d and 98dd834.

📒 Files selected for processing (1)
  • src/components/Global/IframeWrapper/index.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/Global/IframeWrapper/index.tsx (2)
src/components/Global/Icons/Icon.tsx (2)
  • IconName (62-120)
  • Icon (189-198)
src/components/0_Bruddle/Button.tsx (2)
  • ButtonVariant (7-16)
  • Button (76-267)
⏰ 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 (4)
src/components/Global/IframeWrapper/index.tsx (4)

1-1: Mark as a client component (required for hooks/useRouter).

If this lives under Next.js App Router, add the directive to avoid runtime errors with hooks and window/navigator usage.

+ 'use client'
  import { useEffect, useMemo, useState } from 'react'

181-185: Revisit sandbox permissions (least privilege).

allow-same-origin + allow-scripts removes origin isolation. If the vendor doesn’t require it, drop allow-same-origin to tighten the sandbox. Confirm with the provider before changing.

-                            sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-top-navigation-by-user-activation"
+                            sandbox="allow-scripts allow-forms allow-popups allow-modals allow-top-navigation-by-user-activation"

84-84: Nice: fixed stale closures in modalDetails deps.

Including src and router prevents outdated copy links and routes.


126-131: Properly disabling background interactions while help modal is open.

pointer-events handling + preventClose on both modals is consistent. LGTM.

Also applies to: 221-225

Copy link
Contributor

@Hugo0 Hugo0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these changes are SUPER helpful!

Some smaller issues, but brief smoke testing worked and code lgtm

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good simple simple component

const handleCopy = (textToCopy: string) => {
navigator.clipboard.writeText(textToCopy).then(() => {
setCopied(true)
setTimeout(() => setCopied(false), 2000)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neat

classOverlay={`bg-black bg-opacity-50 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}
video={false}
className="z-[1000001] !p-0 md:!p-6"
className={`z-[100] !p-0 md:!p-6 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warn: we go from z-1000001 to z-100 here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, because we wanted the confirm modal to come on top of this modal thats why reduced z-index here and given higher z-index to the other modal

iconContainerClassName={modalDetails.iconContainerClassName}
modalPanelClassName="max-w-full pointer-events-auto"
ctaClassName="grid grid-cols-1 gap-3"
modalClassName="!z-[10001] pointer-events-auto"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: this is z-10001, and the other z-100. Please clean up

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, because we wanted the confirm modal to come on top of this modal thats why reduced z-index here and given higher z-index to the other modal

key={src}
src={src}
allow="camera;"
style={{ width: '100%', height: '80%', border: 'none' }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Whats the logic in reducing the height to 80?
  2. very low prio, but on desktop it looks a bit sketch (see discord immage) image.png

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, mini coding nit: Might make sense to have iframe height/dimension as a constsant top of file

setShowCloseConfirmMessage(false)
}}
>
Close
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: why do we still have the close button if we hve stop verification below? was this in the designs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue

})
}

const modalDetails = useMemo(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HUGE memo. break down?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memo here is preventing the ActionModal component from re-rendering when modalDetails changes. I added this because ModalDetails contains complex objects with functions inside it.

Comment on lines +73 to +74
variant: 'purple' as ButtonVariant,
shadowSize: '4' as const,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought: we really shouldn't be needing to set shadowsize individually on each button

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can default to 4

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/Global/IframeWrapper/index.tsx (1)

104-116: Surface the confirmation modal on close attempts (don’t no-op).

When enableConfirmationPrompt is true and not a TOS flow, onClose currently does nothing. Trigger the confirmation ActionModal instead so the user gets feedback.

Apply:

         <Modal
             visible={visible}
             onClose={() => {
                 if (!enableConfirmationPrompt) {
                     onClose('manual')
                     return
                 }
                 if (src.includes('tos')) {
                     onClose('manual')
                     return
                 }
+                // Show confirmation instead of silently ignoring close
+                setModalVariant('stop-verification')
+                setIsHelpModalOpen(true)
             }}
♻️ Duplicate comments (2)
src/components/Global/IframeWrapper/index.tsx (2)

85-101: Validate postMessage origin and source; bind to iframe window.

Any window can currently post “complete” or “signedAgreementId” and close this modal. Validate event.source against the iframe contentWindow and event.origin against the src origin. Also attach a ref to the iframe.

Apply:

-    useEffect(() => {
-        const handleMessage = (event: MessageEvent) => {
-            const data = event.data
+    const iframeRef = useRef<HTMLIFrameElement>(null)
+    const allowedOrigin = useMemo(() => {
+        try {
+            return new URL(src, typeof window !== 'undefined' ? window.location.origin : undefined).origin
+        } catch {
+            return undefined
+        }
+    }, [src])
+
+    useEffect(() => {
+        const handleMessage = (event: MessageEvent) => {
+            if (iframeRef.current && event.source !== iframeRef.current.contentWindow) return
+            if (allowedOrigin && event.origin !== allowedOrigin) return
+            const data = event.data
             if (data?.name === 'complete' && data?.metadata?.status === 'completed') {
                 onClose('completed')
             }
             // @dev note: kinda hacky, but tos modal takes too long to close using websocket, so we use the signedAgreementId to close it
             // persona fires this event when the user clicks the "accept" button within the iframe
             if (data?.signedAgreementId) {
                 onClose('tos_accepted')
             }
         }
 
-        window.addEventListener('message', handleMessage)
-        return () => window.removeEventListener('message', handleMessage)
-    }, [onClose])
+        window.addEventListener('message', handleMessage)
+        return () => window.removeEventListener('message', handleMessage)
+    }, [onClose, allowedOrigin])

And attach the ref to the iframe at Lines 129-136 (see below).


1-1: Import useRef for secure postMessage handling (missing).

You’re adding window message listeners and embedding an iframe but not keeping a ref to it; this prevents proper source/origin validation. Import useRef to support a secure implementation.

Apply:

-import { useEffect, useMemo, useState } from 'react'
+import { useEffect, useMemo, useRef, useState } from 'react'
🧹 Nitpick comments (4)
src/components/Global/IframeWrapper/index.tsx (4)

137-150: Ensure primary CTA is type="button".

Prevents accidental form submission if nested in a form.

Apply:

-                            <Button
+                            <Button
+                                type="button"
                                 variant={'purple'}
                                 className={`max-w-md`}
                                 onClick={() => {
                                     setModalVariant('stop-verification')
                                     setIsHelpModalOpen(true)
                                 }}

151-160: Button semantics: add type and improve a11y name.

Add type="button". Consider aria-label if inner text changes visually.

Apply:

-                            <button
+                            <button
+                                type="button"
                                 onClick={() => {
                                     setModalVariant('trouble')
                                     setIsHelpModalOpen(true)
                                 }}
                                 className="flex items-center gap-1"
                             >
                                 <Icon name="peanut-support" size={16} />
                                 <p className="text-xs font-medium underline">Having trouble?</p>
                             </button>

165-176: z-index policy: consolidate to tokens and avoid magic numbers.

ActionModal uses !z-[10001] while the parent modal uses z-[100]. Define a shared z layer scale (e.g., z-modal:1000, z-submodal:1100) to prevent future stacking bugs.

Apply:

-                modalClassName="!z-[10001] pointer-events-auto"
+                modalClassName="z-[1100] pointer-events-auto"

And align the parent modal className z-[100] to a named step (e.g., z-[1000]) project-wide.


129-161: Performance/layout: avoid nested scroll + percentage heights.

The 80% iframe + h-1/5 section inside an overflow-scroll container can cause awkward nested scrolling on mobile. Consider a column layout with fixed bottom actions and overflow-hidden on the container; set the iframe area to flex-grow.

Proposed restructure:

-                <div className="flex h-full flex-col gap-2 p-0">
-                    <div className="h-full w-full flex-grow overflow-scroll">
-                        <iframe ... style={{ width:'100%', height:'80%', ...}} />
-                        <div className="flex h-1/5 w-full ..."> ... </div>
-                    </div>
-                </div>
+                <div className="flex h-full flex-col p-0 overflow-hidden">
+                    <div className="flex-1 min-h-0 overflow-auto">
+                        <iframe ... style={{ width:'100%', height:'100%', border:'none' }} />
+                    </div>
+                    <div className="flex w-full items-center justify-center gap-4 px-5 py-4 shrink-0">
+                        {/* CTAs */}
+                    </div>
+                </div>

Also applies to: 165-177

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 98dd834 and 3866f6e.

📒 Files selected for processing (1)
  • src/components/Global/IframeWrapper/index.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/Global/IframeWrapper/index.tsx (2)
src/components/Global/Icons/Icon.tsx (2)
  • IconName (62-120)
  • Icon (189-198)
src/components/0_Bruddle/Button.tsx (2)
  • ButtonVariant (7-16)
  • Button (76-267)
⏰ 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

Comment on lines +18 to 23
const [isHelpModalOpen, setIsHelpModalOpen] = useState(false)
const [modalVariant, setModalVariant] = useState<'stop-verification' | 'trouble'>('trouble')
const [copied, setCopied] = useState(false)
const [isVerificationStarted, setIsVerificationStarted] = useState(false)
const router = useRouter()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Reset transient state on close/src change.

When the modal is closed or src changes, keep UX predictable by resetting isVerificationStarted/help/copy state. Otherwise reopening may skip the start screen or show stale “Copied!”.

Apply:

 const IframeWrapper = ({ src, visible, onClose, closeConfirmMessage }: IFrameWrapperProps) => {
   const enableConfirmationPrompt = closeConfirmMessage !== undefined
   const [isHelpModalOpen, setIsHelpModalOpen] = useState(false)
   const [modalVariant, setModalVariant] = useState<'stop-verification' | 'trouble'>('trouble')
   const [copied, setCopied] = useState(false)
   const [isVerificationStarted, setIsVerificationStarted] = useState(false)
   const router = useRouter()
+
+  // Reset per session
+  useEffect(() => {
+    if (!visible) {
+      setIsHelpModalOpen(false)
+      setIsVerificationStarted(false)
+      setCopied(false)
+      setModalVariant('trouble')
+    }
+  }, [visible])
+
+  // If the flow URL changes mid-session, return to the start step
+  useEffect(() => {
+    setIsVerificationStarted(false)
+    setIsHelpModalOpen(false)
+    setCopied(false)
+    setModalVariant('trouble')
+  }, [src])
📝 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.

Suggested change
const [isHelpModalOpen, setIsHelpModalOpen] = useState(false)
const [modalVariant, setModalVariant] = useState<'stop-verification' | 'trouble'>('trouble')
const [copied, setCopied] = useState(false)
const [isVerificationStarted, setIsVerificationStarted] = useState(false)
const router = useRouter()
const IframeWrapper = ({ src, visible, onClose, closeConfirmMessage }: IFrameWrapperProps) => {
const enableConfirmationPrompt = closeConfirmMessage !== undefined
const [isHelpModalOpen, setIsHelpModalOpen] = useState(false)
const [modalVariant, setModalVariant] = useState<'stop-verification' | 'trouble'>('trouble')
const [copied, setCopied] = useState(false)
const [isVerificationStarted, setIsVerificationStarted] = useState(false)
const router = useRouter()
// Reset per session when the modal is closed
useEffect(() => {
if (!visible) {
setIsHelpModalOpen(false)
setIsVerificationStarted(false)
setCopied(false)
setModalVariant('trouble')
}
}, [visible])
// Reset state if the iframe src changes mid-session
useEffect(() => {
setIsVerificationStarted(false)
setIsHelpModalOpen(false)
setCopied(false)
setModalVariant('trouble')
}, [src])
// ...rest of the component
}
🤖 Prompt for AI Agents
In src/components/Global/IframeWrapper/index.tsx around lines 18 to 23,
transient modal state (isVerificationStarted, copied, modalVariant) is not reset
when the help modal is closed or when the iframe src changes, causing stale UI
on reopen; add a useEffect that runs when isHelpModalOpen changes to false or
when the src prop changes and inside it reset setIsVerificationStarted(false),
setCopied(false), and setModalVariant('trouble') (keep isHelpModalOpen control
unchanged) so the modal always opens in the initial state.

Comment on lines +24 to +29
navigator.clipboard.writeText(textToCopy).then(() => {
setCopied(true)
setTimeout(() => setCopied(false), 2000)
})
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden clipboard copy (errors, stable identity).

Add error handling and memoize with useCallback to avoid linter warnings and stale closures in modalDetails.

Apply:

-    const handleCopy = (textToCopy: string) => {
-        navigator.clipboard.writeText(textToCopy).then(() => {
-            setCopied(true)
-            setTimeout(() => setCopied(false), 2000)
-        })
-    }
+    const handleCopy = useCallback(async (textToCopy: string) => {
+        try {
+            await navigator.clipboard.writeText(textToCopy)
+            setCopied(true)
+            setTimeout(() => setCopied(false), 2000)
+        } catch {
+            // TODO: surface a toast/error if available
+            setCopied(false)
+        }
+    }, [])

Also add handleCopy to the modalDetails deps (see below).

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +31 to 83
if (modalVariant === 'trouble') {
return {
title: 'Having trouble verifying?',
description:
'If the verification isn’t loading here, you can finish it in your browser. Just copy this link and open it there.',
icon: 'info' as IconName,
iconContainerClassName: 'bg-primary-1',
ctas: [
{
text: 'Copy link',
icon: copied ? 'check' : ('copy' as IconName),
onClick: () => {
handleCopy(src)
},
variant: 'purple' as ButtonVariant,
shadowSize: '4' as const,
},
{
text: 'Chat with support',
icon: 'peanut-support' as IconName,
onClick: () => router.push('/support'),
variant: 'transparent' as ButtonVariant,
className: 'underline text-sm font-medium w-full fill-none',
},
],
}
}
}, [visible, src])

return {
title: 'Stop verification?',
description: 'If you exit now, your verification won’t be completed and you’ll need to start again later.',
icon: 'info' as IconName,
iconContainerClassName: 'bg-secondary-1',
ctas: [
{
text: 'Stop verification',
onClick: () => {
setIsHelpModalOpen(false)
onClose('manual')
},
variant: 'purple' as ButtonVariant,
shadowSize: '4' as const,
},
{
text: 'Continue verifying',
onClick: () => setIsHelpModalOpen(false),
variant: 'transparent' as ButtonVariant,
className: 'underline text-sm font-medium w-full',
},
],
}
}, [modalVariant, copied, src, router])

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix useMemo deps and button types; minor a11y polish.

  • Include handleCopy to satisfy exhaustive-deps and ensure fresh handler.
  • Add type="button" to prevent accidental form submits.

Apply:

-    }, [modalVariant, copied, src, router])
+    }, [modalVariant, copied, src, router, handleCopy])

And within the returned CTAs:

-                        onClick: () => {
+                        onClick: () => {
                             handleCopy(src)
                         },
+                        type: 'button',
📝 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.

Suggested change
const modalDetails = useMemo(() => {
if (modalVariant === 'trouble') {
return {
title: 'Having trouble verifying?',
description:
'If the verification isn’t loading here, you can finish it in your browser. Just copy this link and open it there.',
icon: 'info' as IconName,
iconContainerClassName: 'bg-primary-1',
ctas: [
{
text: 'Copy link',
icon: copied ? 'check' : ('copy' as IconName),
onClick: () => {
handleCopy(src)
},
variant: 'purple' as ButtonVariant,
shadowSize: '4' as const,
},
{
text: 'Chat with support',
icon: 'peanut-support' as IconName,
onClick: () => router.push('/support'),
variant: 'transparent' as ButtonVariant,
className: 'underline text-sm font-medium w-full fill-none',
},
],
}
}
}, [visible, src])
return {
title: 'Stop verification?',
description: 'If you exit now, your verification won’t be completed and you’ll need to start again later.',
icon: 'info' as IconName,
iconContainerClassName: 'bg-secondary-1',
ctas: [
{
text: 'Stop verification',
onClick: () => {
setIsHelpModalOpen(false)
onClose('manual')
},
variant: 'purple' as ButtonVariant,
shadowSize: '4' as const,
},
{
text: 'Continue verifying',
onClick: () => setIsHelpModalOpen(false),
variant: 'transparent' as ButtonVariant,
className: 'underline text-sm font-medium w-full',
},
],
}
}, [modalVariant, copied, src, router])
const modalDetails = useMemo(() => {
if (modalVariant === 'trouble') {
return {
title: 'Having trouble verifying?',
description:
'If the verification isn’t loading here, you can finish it in your browser. Just copy this link and open it there.',
icon: 'info' as IconName,
iconContainerClassName: 'bg-primary-1',
ctas: [
{
text: 'Copy link',
icon: copied ? 'check' : ('copy' as IconName),
onClick: () => {
handleCopy(src)
},
type: 'button',
variant: 'purple' as ButtonVariant,
shadowSize: '4' as const,
},
{
text: 'Chat with support',
icon: 'peanut-support' as IconName,
onClick: () => router.push('/support'),
variant: 'transparent' as ButtonVariant,
className: 'underline text-sm font-medium w-full fill-none',
},
],
}
}
return {
title: 'Stop verification?',
description: 'If you exit now, your verification won’t be completed and you’ll need to start again later.',
icon: 'info' as IconName,
iconContainerClassName: 'bg-secondary-1',
ctas: [
{
text: 'Stop verification',
onClick: () => {
setIsHelpModalOpen(false)
onClose('manual')
},
variant: 'purple' as ButtonVariant,
shadowSize: '4' as const,
},
{
text: 'Continue verifying',
onClick: () => setIsHelpModalOpen(false),
variant: 'transparent' as ButtonVariant,
className: 'underline text-sm font-medium w-full',
},
],
}
}, [modalVariant, copied, src, router, handleCopy])
🤖 Prompt for AI Agents
src/components/Global/IframeWrapper/index.tsx around lines 31 to 83: the useMemo
misses handleCopy in its dependency array and several CTA button objects lack
explicit type attributes which can cause accidental form submissions and stale
closures; update the dependency array to include handleCopy (i.e.,
[modalVariant, copied, src, router, handleCopy]) and add type: 'button' to every
CTA button object returned in both branches (trouble and stop) to ensure correct
button behavior and accessibility.

Comment on lines 117 to 122
video={false}
className="z-[1000001] !p-0 md:!p-6"
className={`z-[100] !p-0 md:!p-6 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}
classButtonClose="hidden"
preventClose={true}
hideOverlay={false}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid pointer-events hacks; use aria-hidden/inert for underlying modal.

Disabling pointer events on overlay/panel can allow clicks to bleed to the page and harms a11y. Prefer marking the underlying container inert/aria-hidden when the ActionModal is open.

Apply:

-            classOverlay={`bg-black bg-opacity-50 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}
+            classOverlay="bg-black bg-opacity-50"
-            className={`z-[100] !p-0 md:!p-6 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}
+            className="z-[100] !p-0 md:!p-6"
             classButtonClose="hidden"
             preventClose={true}
             hideOverlay={false}
         >
-            {!isVerificationStarted ? (
+            <div aria-hidden={isHelpModalOpen} {...(isHelpModalOpen ? { inert: '' } : {})}>
+            {!isVerificationStarted ? (
                 <StartVerificationView onStartVerification={() => setIsVerificationStarted(true)} />
             ) : (
                 <div className="flex h-full flex-col gap-2 p-0">

And close the wrapper div just before the ActionModal:

-            <ActionModal
+            </div>
+            <ActionModal
📝 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.

Suggested change
classOverlay={`bg-black bg-opacity-50 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}
video={false}
className="z-[1000001] !p-0 md:!p-6"
className={`z-[100] !p-0 md:!p-6 ${isHelpModalOpen ? 'pointer-events-none' : ''}`}
classButtonClose="hidden"
preventClose={true}
hideOverlay={false}
<ActionModal
classOverlay="bg-black bg-opacity-50"
video={false}
className="z-[100] !p-0 md:!p-6"
classButtonClose="hidden"
preventClose={true}
hideOverlay={false}
>
<div
aria-hidden={isHelpModalOpen}
{...(isHelpModalOpen ? { inert: '' } : {})}
>
{!isVerificationStarted ? (
<StartVerificationView onStartVerification={() => setIsVerificationStarted(true)} />
) : (
<div className="flex h-full flex-col gap-2 p-0">
{/* …verification-in-progress UI… */}
</div>
)}
</div>
<ActionModal
// …help-modal props…
🤖 Prompt for AI Agents
In src/components/Global/IframeWrapper/index.tsx around lines 117 to 122, remove
the pointer-events CSS hacks on the overlay and panel and instead mark the
underlying content as inaccessible when the ActionModal is open: wrap the
underlying page/content in a container that receives aria-hidden="true" (or the
inert attribute where supported) when isHelpModalOpen is true, ensure the
ActionModal is rendered outside/after that container (close the wrapper div just
before rendering the ActionModal), and remove the classOverlay/className
pointer-events-none toggles so clicks and focus cannot bleed through and screen
readers will ignore the hidden content.

Comment on lines +129 to +136
key={src}
src={src}
allow="camera;"
style={{ width: '100%', height: '80%', border: 'none' }}
className="rounded-md"
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-top-navigation-by-user-activation"
/>
<div className="flex h-1/5 w-full flex-col items-center justify-center gap-4 px-5">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add iframe ref, title, and review permissions.

  • Attach ref for secure messaging.
  • Add title for screen readers.
  • Consider allowing microphone if the vendor needs it.

Apply:

-                        <iframe
+                        <iframe
+                            ref={iframeRef}
                             key={src}
                             src={src}
-                            allow="camera;"
+                            title="Identity verification"
+                            allow="camera; microphone;"
                             style={{ width: '100%', height: '80%', border: 'none' }}
                             className="rounded-md"
                             sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-top-navigation-by-user-activation"
                         />
📝 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.

Suggested change
<iframe
key={src}
src={src}
allow="camera;"
style={{ width: '100%', height: '80%', border: 'none' }}
className="rounded-md"
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-top-navigation-by-user-activation"
/>
<iframe
ref={iframeRef}
key={src}
src={src}
title="Identity verification"
allow="camera; microphone;"
style={{ width: '100%', height: '80%', border: 'none' }}
className="rounded-md"
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-top-navigation-by-user-activation"
/>
🤖 Prompt for AI Agents
In src/components/Global/IframeWrapper/index.tsx around lines 129 to 136, the
iframe is missing a ref, title, and microphone permission; create a React ref
(e.g. const iframeRef = useRef<HTMLIFrameElement | null>(null)) and attach it to
the iframe for secure messaging/postMessage use, add a descriptive title prop
for screen readers (e.g. title="Vendor content" or prop-driven title), and
update the allow attribute to include "microphone" (e.g. "camera; microphone;")
while keeping the existing sandbox attributes; ensure the ref is used where
postMessage or event handling occurs and remains null-safe.

@Hugo0 Hugo0 merged commit 4d95c40 into peanut-wallet-dev Aug 29, 2025
6 checks passed
jjramirezn added a commit that referenced this pull request Sep 4, 2025
* feat: handle send link claims to bank account for peanut users (#1078)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* remove duplicate debounce code and use `useDebounce` hook instead (#1079)

* Landing page v2.1 (#1089)

* lpv2.1 part 1

* Add exchange widget

* add and integrate exchange API

* add yourMoney component bg

* update landing countries svg

* integrate frankfurter API

* fixes and improvements

* decrease hero section height

* allow max 2 decimal places

* Add `/exchange` route

* fix: overlay

* make destination amount editable and bugg fixes

* some fixes & currency improvements

* crucial commit

* fix checkmark, font size and weight

---------

Co-authored-by: Hugo Montenegro <h@hugo0.com>

* [TASK-13186] refactor: use networkName instead of axelarChainName (#1095)

* refactor: use networkName instead of axelarChainName

* fix: types

* fix: onramp currency (#1096)

* fix: stretched favicon (#1099)

* [TASK-13971] fix: scientific notation in eip681 parsing (#1097)

* fix: scientific notation in eip681 parsing

* fix: qr handling tests

* fix: peanut sdk mock

* pull iban hotfix (#1100)

* fix: claim flow bugs (#1102)

* fix: cross chain claim

* fix: full name issue on confirm bank claim view

* fix: back navigation on desktop views

* Fix back button not working on /profile (#1101)

* Fix back button not working

* fix public profile page

* extract internal navigation logic to utility function

* fix: send link claims to us bank accounts (#1108)

* fix: usa bank account claims

* fix: show bank account details in confirm claim view

* Sync Landing page changes (#1111)

* reduce clouds size and update font

* fix: hero section responsiveness issue

* fix: formatting errors

* add currency animation

* fix: us bank claims after kyc for logged in users (#1112)

* fix: trim account form inputs for spaces (#1114)

* [TASK-14107] fix: don't allow claiming on xChain if route is not found (#1115)

* fix: don't allow claiming on xChain if route is not found

* fix(claim): use correct decimals for min receive amount

* feat: handle redirect uri when on unsupported browsers (#1117)

* feat: handle redirect uri when on unsupported browsers

* fix: confirm bank claim ui rows for iban guest claim

* remove animation (#1118)

* Prod to staging (#1124)

* HOTFIX - IBAN country detection and incorrect bank acc details (#1094)

* Fix: Iban country detection and incorrect bank acc details

* Fix: update IBAN country validation to use correct locale string comparison

* add validations for US and mexican bank accounts

* fix typo

* fix claim flow and create a reusable function for getting 3 letter code

* fix country code mismatch

* fix: show error below input field

* remove unnecessary checks

* remove unnecessary CLABE check

* Prod LP v2.1 (#1098)

* feat: lpv2.1

* fix: gigaclouds, font and exchange widget

* fixes and improvements

* remove duplicate export

* remove unused component

* Fix: Landing page hero section responsiveness issue (#1107)

* fix: hero section responsiveness issue

* fix: stars position

* fix height on desktop

* remove unused code

* fix margins (#1113)

* [TASK-14052] Prod release 105 (#1122)

* feat: handle send link claims to bank account for peanut users (#1078)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* remove duplicate debounce code and use `useDebounce` hook instead (#1079)

* Landing page v2.1 (#1089)

* lpv2.1 part 1

* Add exchange widget

* add and integrate exchange API

* add yourMoney component bg

* update landing countries svg

* integrate frankfurter API

* fixes and improvements

* decrease hero section height

* allow max 2 decimal places

* Add `/exchange` route

* fix: overlay

* make destination amount editable and bugg fixes

* some fixes & currency improvements

* crucial commit

* fix checkmark, font size and weight

---------

Co-authored-by: Hugo Montenegro <h@hugo0.com>

* [TASK-13186] refactor: use networkName instead of axelarChainName (#1095)

* refactor: use networkName instead of axelarChainName

* fix: types

* fix: onramp currency (#1096)

* fix: stretched favicon (#1099)

* [TASK-13971] fix: scientific notation in eip681 parsing (#1097)

* fix: scientific notation in eip681 parsing

* fix: qr handling tests

* fix: peanut sdk mock

* pull iban hotfix (#1100)

* fix: claim flow bugs (#1102)

* fix: cross chain claim

* fix: full name issue on confirm bank claim view

* fix: back navigation on desktop views

* Fix back button not working on /profile (#1101)

* Fix back button not working

* fix public profile page

* extract internal navigation logic to utility function

* fix: send link claims to us bank accounts (#1108)

* fix: usa bank account claims

* fix: show bank account details in confirm claim view

* Sync Landing page changes (#1111)

* reduce clouds size and update font

* fix: hero section responsiveness issue

* fix: formatting errors

* add currency animation

* fix: us bank claims after kyc for logged in users (#1112)

* fix: trim account form inputs for spaces (#1114)

* [TASK-14107] fix: don't allow claiming on xChain if route is not found (#1115)

* fix: don't allow claiming on xChain if route is not found

* fix(claim): use correct decimals for min receive amount

* feat: handle redirect uri when on unsupported browsers (#1117)

* feat: handle redirect uri when on unsupported browsers

* fix: confirm bank claim ui rows for iban guest claim

* remove animation (#1118)

* fix: formatting

---------

Co-authored-by: Kushagra Sarathe <76868364+kushagrasarathe@users.noreply.github.com>
Co-authored-by: Mohd Zishan <72738005+Zishan-7@users.noreply.github.com>
Co-authored-by: Hugo Montenegro <h@hugo0.com>

---------

Co-authored-by: Mohd Zishan <72738005+Zishan-7@users.noreply.github.com>
Co-authored-by: Kushagra Sarathe <76868364+kushagrasarathe@users.noreply.github.com>
Co-authored-by: Hugo Montenegro <h@hugo0.com>

* fix: dates in receipts (#1105)

* [TASK-13865] fix: add tx info on receipt (#1109)

* fix: add tx info on receipt

* feat: use address explorer url for depositor address

* fix(history): check befroe creating address explorer url

* Fix: logged in users have to re-login after installing PWA (#1103)

* store `LOCAL_STORAGE_WEB_AUTHN_KEY` in cookies

* ensure backward compatibility

* refactor: move syncLocalStorageToCookie call into useEffect for better lifecycle management

* feat: links v2.1 req fulfilment flows (#1085)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* feat: req fulfillment exchange flow

* fix: header title

* feat: req fulfillment using connected external wallet

* fix: navigation and ui

* fix: file name

* feat: abstract reusbale components from onramp flow for bank fulfilment

* feat: handle onramp creation for request fulfilment

* feat: reusable verification component

* feat: handle bank req fulfilment for peanut users

* fix: show all supported countries in req/claim bank flow

* feat: show google-pay/apple-pay based on users device

* fix: resolve pr review comments

* fix: exhange rate hook fallback value

* fix: resolve pr comments

* Feat: Collect tg username (#1110)

* feat: collect tg username

* update animations

* fix api route

* add thinking peanut gif

* fix typescript errors

* fix typo and reset telegramHandle field on logout

* fix: spacing and describe regex rules

* add missing export

* feat: add sound in success views (#1127)

* feat: handle history ui changes for links v2.1 (#1106)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* feat: req fulfillment exchange flow

* fix: header title

* feat: req fulfillment using connected external wallet

* fix: navigation and ui

* fix: file name

* feat: abstract reusbale components from onramp flow for bank fulfilment

* feat: handle onramp creation for request fulfilment

* feat: reusable verification component

* feat: handle bank req fulfilment for peanut users

* fix: show all supported countries in req/claim bank flow

* feat: show google-pay/apple-pay based on users device

* feat: handle bank send link claim hisotry for peanut users

* feat: handle history ui changes for request fulfillment using bank accounts

* fix: resolve pr review comments

* fix: exhange rate hook fallback value

* fix: resolve pr comments

* fix: review comments

* feat: badges updates (#1119)

* feat: badges updates and hook to check for interactions

* feat: handle badges for receipts and drawer header

* feat: handle badges on request and send flow

* feat: tooltip for badges

* fix: tooltip positioning

* fix: associate a external wallet claim to user if logged in (#1126)

* fix: associate a external wallet claim to user if logged in

* chore: fix comments

* [TASK-14113] fix: handle rpc outage when creating sendlinks (#1120)

* HOTFIX - IBAN country detection and incorrect bank acc details (#1094)

* Fix: Iban country detection and incorrect bank acc details

* Fix: update IBAN country validation to use correct locale string comparison

* add validations for US and mexican bank accounts

* fix typo

* fix claim flow and create a reusable function for getting 3 letter code

* fix country code mismatch

* fix: show error below input field

* remove unnecessary checks

* remove unnecessary CLABE check

* Prod LP v2.1 (#1098)

* feat: lpv2.1

* fix: gigaclouds, font and exchange widget

* fixes and improvements

* remove duplicate export

* remove unused component

* Fix: Landing page hero section responsiveness issue (#1107)

* fix: hero section responsiveness issue

* fix: stars position

* fix height on desktop

* remove unused code

* fix margins (#1113)

* fix: handle rpc outage when creating sendlinks

* fix: formatting

* fix: parallelize geting deposit index

---------

Co-authored-by: Mohd Zishan <72738005+Zishan-7@users.noreply.github.com>

* Integrate Daimo Pay (#1104)

* add daimo pay

* minor improvements

* cleanup and add success state

* resolve dependency issues

* fix: formatting

* fix: recent methods redirection

* add functions for daimo payment in request fulfilment flow

* Integrate daimo in request fulfilment flow

* remove hardcoded address

* add separate arbitrum usdc flow for deposits

* Add risk modal

* fix overlay blur

* Enhance loading state indication in payment process

* Add payer's address in deposit history entry

* Add validation

* add error handling

* remove action and move logic to API route

* fix errors

* fix: request flow

* fix: validation

* fixes

* add daimo flow in country specific method

* fix: slider not working on first attempt

* filter supported networks

* create reusable daimo button

* remove space

* remove route.ts file and move logic to server actions

* fix: infinite loading edge case

* update api and remove delay

* fix: layout shift

* fix: shadow

* update function name

* fix: success receipt (#1129)

* fix: roboto font not working (#1130)

* fix: allow cancel link from the claim page

* fix: allow canceling links from the shared receipt (#1134)

* fix: send flow cta (#1133)

* fix: send flow ctas

* fix: success sound on send flow

* fix: disabled btn on req pay flow

* Fix Daimo bugs (#1132)

* fix: bugs

* fix cross chain deposit details not correct

* fix: request screen UI

* add loading state

* remove old daimo button

* fix: missing dependencies and dead code

* add try catch finally block

* remove clear Daimo errors inside the balance-check effect

* fix copy

* minor fixes

* move ACTION_METHODS to constants file to remove circular dependency

* fix: circular dependency

* fix ts error

* update daimo version

* [TASK-14095] feat: add fallback transport to viem clients (#1131)

* feat: add fallback transport to viem clients

Use viem fallback transport to handle RPC errors and fallback to other
providers.

* style: Apply prettier formatting

* test: add fallback to viem mock

* fix: external claim links history ui + badges fix (#1136)

* fix: external claim links history ui + badges fix

* fix: resolve codderrabbit suggestions

* fix: coderrabbit comment on state stale

* Fix: disable add money button on default state + disable sound on IOS (#1145)

* fix: add money success screen shows usernmae

* disable add money button in default state

* disable sound on IOS

* Fix: daimo bugs part2 (#1149)

* fix: black screen on IOS

* fix: sucess screen showed without paying - add money flow

* fix currency and double $ in  txn history

* fix: x-chan token size and add API to get missing token icons

* fix: req fulfilment

* add default value to tokenData

* fix: move useeffect above transaction null check

* format amount

* fix: space between currency and amount (#1135)

* Lock token to USDC arb for peanut ens username (#1128)

* Lock token to USDC arb for peanut ens username

* add comment

* revert variable declaration for sanitizedValue in GeneralRecipientInput component

* fix add regex to strip only from the end

* [TASK-13900] Feat/kyc modal changes (#1137)

* fix: pointer events

* fix: modal btns not working on mobile

* add missing dependency

* remove close button

* Chore/prod to dev 106 (#1152)

* HOTFIX - IBAN country detection and incorrect bank acc details (#1094)

* Fix: Iban country detection and incorrect bank acc details

* Fix: update IBAN country validation to use correct locale string comparison

* add validations for US and mexican bank accounts

* fix typo

* fix claim flow and create a reusable function for getting 3 letter code

* fix country code mismatch

* fix: show error below input field

* remove unnecessary checks

* remove unnecessary CLABE check

* Prod LP v2.1 (#1098)

* feat: lpv2.1

* fix: gigaclouds, font and exchange widget

* fixes and improvements

* remove duplicate export

* remove unused component

* Fix: Landing page hero section responsiveness issue (#1107)

* fix: hero section responsiveness issue

* fix: stars position

* fix height on desktop

* remove unused code

* fix margins (#1113)

* [TASK-14052] Prod release 105 (#1122)

* feat: handle send link claims to bank account for peanut users (#1078)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* remove duplicate debounce code and use `useDebounce` hook instead (#1079)

* Landing page v2.1 (#1089)

* lpv2.1 part 1

* Add exchange widget

* add and integrate exchange API

* add yourMoney component bg

* update landing countries svg

* integrate frankfurter API

* fixes and improvements

* decrease hero section height

* allow max 2 decimal places

* Add `/exchange` route

* fix: overlay

* make destination amount editable and bugg fixes

* some fixes & currency improvements

* crucial commit

* fix checkmark, font size and weight

---------

Co-authored-by: Hugo Montenegro <h@hugo0.com>

* [TASK-13186] refactor: use networkName instead of axelarChainName (#1095)

* refactor: use networkName instead of axelarChainName

* fix: types

* fix: onramp currency (#1096)

* fix: stretched favicon (#1099)

* [TASK-13971] fix: scientific notation in eip681 parsing (#1097)

* fix: scientific notation in eip681 parsing

* fix: qr handling tests

* fix: peanut sdk mock

* pull iban hotfix (#1100)

* fix: claim flow bugs (#1102)

* fix: cross chain claim

* fix: full name issue on confirm bank claim view

* fix: back navigation on desktop views

* Fix back button not working on /profile (#1101)

* Fix back button not working

* fix public profile page

* extract internal navigation logic to utility function

* fix: send link claims to us bank accounts (#1108)

* fix: usa bank account claims

* fix: show bank account details in confirm claim view

* Sync Landing page changes (#1111)

* reduce clouds size and update font

* fix: hero section responsiveness issue

* fix: formatting errors

* add currency animation

* fix: us bank claims after kyc for logged in users (#1112)

* fix: trim account form inputs for spaces (#1114)

* [TASK-14107] fix: don't allow claiming on xChain if route is not found (#1115)

* fix: don't allow claiming on xChain if route is not found

* fix(claim): use correct decimals for min receive amount

* feat: handle redirect uri when on unsupported browsers (#1117)

* feat: handle redirect uri when on unsupported browsers

* fix: confirm bank claim ui rows for iban guest claim

* remove animation (#1118)

* fix: formatting

---------

Co-authored-by: Kushagra Sarathe <76868364+kushagrasarathe@users.noreply.github.com>
Co-authored-by: Mohd Zishan <72738005+Zishan-7@users.noreply.github.com>
Co-authored-by: Hugo Montenegro <h@hugo0.com>

* fix: bank claim flow runtime error (#1138)

* hotfix: make iban non optional (#1139)

* fix: bank claim flow runtime error

* fix: dont have iban as optional

* fix: merge conflicts

* fix: merge external account with bank details (#1140)

* fix: add id to external account (#1142)

* added tg footer (#1144)

* Hotfix : add missing countries - claim as guest flow (#1146)

* fix: add missing countries

* remove duplicate comment

* fix: show error on dynamic bank account form (#1147)

* fix: Invalid IBAN for UK (#1151)

---------

Co-authored-by: Mohd Zishan <72738005+Zishan-7@users.noreply.github.com>
Co-authored-by: Kushagra Sarathe <76868364+kushagrasarathe@users.noreply.github.com>
Co-authored-by: Hugo Montenegro <h@hugo0.com>
Co-authored-by: Hugo Montenegro <hugo@peanut.to>

* [TASK-13950] Fix: incorrect token amount on second withdraw (#1150)

* fix: incorrect token amount on second withdraw

* move `resetTokenContextProvider()` to unmount callback

* fix: transaction explorer url for deposits

* fix: history skeleton copy

* save token and chain details for cross chain req-fulfilments (#1154)

* fix: send links history ui for senders pov when claimed to bank accounts (#1156)

* fix: sort action list methods

* fix: send links claimed to bank accounts history ui for senders pov

* fix: issues for request link paying with bank (#1158)

- Specify recipient when creating onramp for request fulfillment
- Use correct amount depending on currency

* fix: stop cleaning error by bic field (#1159)

We now always clear before starting submission and also bic field will
always show, so that logic is not needed anymore.

* fix: claim country currency and amount, fallback to $  (#1164)

* feat: show local bank currency incase of bank claims

* fix: activity rows for sender's send link history

* fix: verification modal when claiming

* fix: state issue when new user tries to claim to bank

* fix: request pay copy (#1165)

* fix: close kyc modal btn (#1166)

* Fix testing github action (#1167)

* chore: remove prettier action

When commiting it clashes with signature verification rules

* chore: update test action setup version

* fix: install first

* fix: actually make sure that cancelledDate is a Date (#1170)

* fix: icon and margin (#1171)

* Hide pay with wallet button in Daimo component (#1172)

* hide pay with wallet button

* improve targeted css approach

* Fix: Daimo bug and activity receipt bug (#1175)

* sligify chain name

* fix: stale state issue

* hide row if tokenData is not present

* Fix/conflicts (#1177)

* HOTFIX - IBAN country detection and incorrect bank acc details (#1094)

* Fix: Iban country detection and incorrect bank acc details

* Fix: update IBAN country validation to use correct locale string comparison

* add validations for US and mexican bank accounts

* fix typo

* fix claim flow and create a reusable function for getting 3 letter code

* fix country code mismatch

* fix: show error below input field

* remove unnecessary checks

* remove unnecessary CLABE check

* Prod LP v2.1 (#1098)

* feat: lpv2.1

* fix: gigaclouds, font and exchange widget

* fixes and improvements

* remove duplicate export

* remove unused component

* Fix: Landing page hero section responsiveness issue (#1107)

* fix: hero section responsiveness issue

* fix: stars position

* fix height on desktop

* remove unused code

* fix margins (#1113)

* [TASK-14052] Prod release 105 (#1122)

* feat: handle send link claims to bank account for peanut users (#1078)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* remove duplicate debounce code and use `useDebounce` hook instead (#1079)

* Landing page v2.1 (#1089)

* lpv2.1 part 1

* Add exchange widget

* add and integrate exchange API

* add yourMoney component bg

* update landing countries svg

* integrate frankfurter API

* fixes and improvements

* decrease hero section height

* allow max 2 decimal places

* Add `/exchange` route

* fix: overlay

* make destination amount editable and bugg fixes

* some fixes & currency improvements

* crucial commit

* fix checkmark, font size and weight

---------

Co-authored-by: Hugo Montenegro <h@hugo0.com>

* [TASK-13186] refactor: use networkName instead of axelarChainName (#1095)

* refactor: use networkName instead of axelarChainName

* fix: types

* fix: onramp currency (#1096)

* fix: stretched favicon (#1099)

* [TASK-13971] fix: scientific notation in eip681 parsing (#1097)

* fix: scientific notation in eip681 parsing

* fix: qr handling tests

* fix: peanut sdk mock

* pull iban hotfix (#1100)

* fix: claim flow bugs (#1102)

* fix: cross chain claim

* fix: full name issue on confirm bank claim view

* fix: back navigation on desktop views

* Fix back button not working on /profile (#1101)

* Fix back button not working

* fix public profile page

* extract internal navigation logic to utility function

* fix: send link claims to us bank accounts (#1108)

* fix: usa bank account claims

* fix: show bank account details in confirm claim view

* Sync Landing page changes (#1111)

* reduce clouds size and update font

* fix: hero section responsiveness issue

* fix: formatting errors

* add currency animation

* fix: us bank claims after kyc for logged in users (#1112)

* fix: trim account form inputs for spaces (#1114)

* [TASK-14107] fix: don't allow claiming on xChain if route is not found (#1115)

* fix: don't allow claiming on xChain if route is not found

* fix(claim): use correct decimals for min receive amount

* feat: handle redirect uri when on unsupported browsers (#1117)

* feat: handle redirect uri when on unsupported browsers

* fix: confirm bank claim ui rows for iban guest claim

* remove animation (#1118)

* fix: formatting

---------

Co-authored-by: Kushagra Sarathe <76868364+kushagrasarathe@users.noreply.github.com>
Co-authored-by: Mohd Zishan <72738005+Zishan-7@users.noreply.github.com>
Co-authored-by: Hugo Montenegro <h@hugo0.com>

* fix: bank claim flow runtime error (#1138)

* hotfix: make iban non optional (#1139)

* fix: bank claim flow runtime error

* fix: dont have iban as optional

* fix: merge conflicts

* fix: merge external account with bank details (#1140)

* fix: add id to external account (#1142)

* added tg footer (#1144)

* Hotfix : add missing countries - claim as guest flow (#1146)

* fix: add missing countries

* remove duplicate comment

* fix: show error on dynamic bank account form (#1147)

* fix: Invalid IBAN for UK (#1151)

---------

Co-authored-by: Mohd Zishan <72738005+Zishan-7@users.noreply.github.com>
Co-authored-by: Juan José Ramírez <70615692+jjramirezn@users.noreply.github.com>
Co-authored-by: Hugo Montenegro <h@hugo0.com>
Co-authored-by: Hugo Montenegro <hugo@peanut.to>

---------

Co-authored-by: Mohd Zishan <72738005+Zishan-7@users.noreply.github.com>
Co-authored-by: Hugo Montenegro <h@hugo0.com>
Co-authored-by: Juan José Ramírez <70615692+jjramirezn@users.noreply.github.com>
Co-authored-by: Juan José Ramírez <artjjrn@gmail.com>
Co-authored-by: Hugo Montenegro <hugo@peanut.to>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants