Skip to content

[TASK-14388] Feat/request on ramp improvements#1207

Merged
Zishan-7 merged 7 commits intopeanut-wallet-devfrom
feat/request-on-ramp-improvements
Sep 15, 2025
Merged

[TASK-14388] Feat/request on ramp improvements#1207
Zishan-7 merged 7 commits intopeanut-wallet-devfrom
feat/request-on-ramp-improvements

Conversation

@Zishan-7
Copy link
Contributor

This PR also contributes to TASK-14541

image

Rest of the changes are related to redirect flow- so cant paste SS

@Zishan-7 Zishan-7 requested a review from Hugo0 September 12, 2025 08:25
@vercel
Copy link

vercel bot commented Sep 12, 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 Sep 15, 2025 7:16am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 12, 2025

Walkthrough

Adds URL-driven entry into the bank fulfillment flow, introduces BankRequestType detection and new exports/hooks, consolidates user name fields into fullName, records bank step before guest KYC, adds preventClose to ActionModal, extends post‑signup actions, and includes a duplicated useEffect causing the bank-step logic to run twice.

Changes

Cohort / File(s) Summary of changes
Bank flow control & navigation
src/app/[...recipient]/client.tsx, src/components/Request/views/ReqFulfillBankFlowManager.tsx
Adds URL-driven navigation into the bank flow (advances to BankCountryList when step=bank and conditions met), integrates BankRequestType via useDetermineBankRequestType, exposes setShowRequestFulfilmentBankFlowManager and a renamed setter from the fulfillment flow hook, updates user-details submit to use data.fullName, and contains a duplicated useEffect causing the bank-step logic to run twice.
Fulfillment context & hooks API
src/context/.../RequestFulfillmentFlowContext..., src/hooks/useDetermineBankRequestType...
New exports added: RequestFulfillmentBankFlowStep, BankRequestType, and useDetermineBankRequestType; useRequestFulfillmentFlow return shape extended to include setShowRequestFulfilmentBankFlowManager and a mapped/renamed setter for the bank flow step.
User details fullName refactor
src/components/AddMoney/UserDetailsForm.tsx, src/components/Profile/views/IdentityVerification.view.tsx, src/app/(mobile-ui)/add-money/[country]/bank/page.tsx, src/components/Request/views/ReqFulFillBankFlowManager.tsx
Consolidates firstName/lastName into fullName across form type, defaults, inputs, validation and submit payloads (updateUserById now receives fullName).
Guest KYC and flow-step tracking
src/components/Common/ActionList.tsx, src/components/Kyc/index.tsx, src/components/Global/GuestVerificationModal.tsx
For GuestKycNeeded, records addParamStep('bank') before opening guest verification; passes new redirectToVerification prop into GuestVerificationModal; KYC flow now calls addParamStep('bank') on verify and saveRedirectUrl() after success.
Post-signup actions & modal behavior
src/components/Global/PostSignupActionManager/index.tsx, src/components/Global/ActionModal/index.tsx, src/components/Global/PostSignupActionManager/post-signup-action.consts.ts
Adds preventClose boolean prop to ActionModal and uses it to prevent outside-click closing in PostSignupActionManager; appends a new request-link entry to POST_SIGNUP_ACTIONS (pattern + CTA 'Send it!').

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • jjramirezn
  • kushagrasarathe

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "[TASK-14388] Feat/request on ramp improvements" succinctly identifies the primary focus of the changeset (request on‑ramp and bank/redirect flow improvements) and is directly related to the diffs in the PR, so it is not off‑topic or overly generic. The phrasing is acceptable for a feature PR though the "Feat/request" slash is unconventional and could be slightly clearer.
Description Check ✅ Passed The PR description states it contributes to TASK-14541, includes an image attachment, and notes that remaining changes relate to redirect flow, which is related to the changeset and satisfies the lenient description check. It is brief and lacks technical detail about specific files or public API changes, but it is not off‑topic.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ 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/request-on-ramp-improvements

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d64f395 and db531b8.

📒 Files selected for processing (1)
  • src/components/Request/views/ReqFulfillBankFlowManager.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Request/views/ReqFulfillBankFlowManager.tsx
⏰ 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

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

@notion-workspace
Copy link

@notion-workspace
Copy link

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 (2)
src/components/Request/views/ReqFulfillBankFlowManager.tsx (1)

147-156: Form initialData no longer matches updated UserDetailsForm shape (fullName only).

The form won’t prefill the name. Provide fullName instead of firstName/lastName.

-    const [firstName, ...lastNameParts] = (user?.user.fullName ?? '').split(' ')
-    const lastName = lastNameParts.join(' ')
-
-    const initialUserDetails: Partial<UserDetailsFormData> = useMemo(
-        () => ({
-            firstName: user?.user.fullName ? firstName : '',
-            lastName: user?.user.fullName ? lastName : '',
-            email: user?.user.email ?? '',
-        }),
-        [user?.user.fullName, user?.user.email, firstName, lastName]
-    )
+    const initialUserDetails: Partial<UserDetailsFormData> = useMemo(
+        () => ({
+            fullName: user?.user.fullName ?? '',
+            email: user?.user.email ?? '',
+        }),
+        [user?.user.fullName, user?.user.email]
+    )
src/components/Global/PostSignupActionManager/index.tsx (1)

33-39: Sanitize redirect before router.push to prevent open-redirect/navigation to external origins.

redirectUrl is pushed verbatim and can be absolute (e.g., “https://...”), enabling navigation off-site. Parse and enforce same-origin or require a leading “/”.

Apply:

-                    action: () => {
-                        router.push(redirectUrl)
-                        localStorage.removeItem('redirect')
-                        setShowModal(false)
-                    },
+                    action: () => {
+                        const safeUrl = toSafePath(redirectUrl)
+                        router.push(safeUrl)
+                        localStorage.removeItem('redirect')
+                        setShowModal(false)
+                    },

Add helper (same file, top-level):

function toSafePath(url: string): string {
    try {
        const u = new URL(url, window.location.origin)
        if (u.origin !== window.location.origin) return '/'
        return `${u.pathname}${u.search}${u.hash}`
    } catch {
        return typeof url === 'string' && url.startsWith('/') ? url : '/'
    }
}
🧹 Nitpick comments (7)
src/components/Kyc/index.tsx (1)

29-35: Save redirect before initiating KYC to avoid losing context on provider redirects.

If handleInitiateKyc() triggers a navigation, saving after success may be too late. Move saveRedirectUrl() before the initiation.

 const handleVerifyClick = async () => {
-    addParamStep('bank')
-    const result = await handleInitiateKyc()
-    if (result?.success) {
-        saveRedirectUrl()
-        onClose()
-    }
+    addParamStep('bank')
+    saveRedirectUrl()
+    const result = await handleInitiateKyc()
+    if (result?.success) {
+        onClose()
+    }
 }
src/components/AddMoney/UserDetailsForm.tsx (2)

95-103: Use native email input type for better UX and platform validation.

-                            {renderInput('email', 'E-mail', {
+                            {renderInput('email', 'E-mail', {
                                 required: 'Email is required',
                                 pattern: {
                                     value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
                                     message: 'Invalid email address',
                                 },
-                            })}
+                            }, 'email')}

39-47: Trim inputs before submit to avoid trailing/leading whitespace in name/email.

 useImperativeHandle(ref, () => ({
-    handleSubmit: handleSubmit(async (data) => {
+    handleSubmit: handleSubmit(async (data) => {
         setSubmissionError(null)
-        const result = await onSubmit(data)
+        const result = await onSubmit({
+            ...data,
+            fullName: data.fullName.trim(),
+            email: data.email.trim(),
+        })
         if (result?.error) {
             setSubmissionError(result.error)
         }
     }),
 }))
-                        onSubmit={(e) => {
+                        onSubmit={(e) => {
                             e.preventDefault()
-                            handleSubmit(async (data) => {
+                            handleSubmit(async (data) => {
                                 setSubmissionError(null)
-                                const result = await onSubmit(data)
+                                const result = await onSubmit({
+                                    ...data,
+                                    fullName: data.fullName.trim(),
+                                    email: data.email.trim(),
+                                })
                                 if (result?.error) {
                                     setSubmissionError(result.error)
                                 }
                             })()
                         }}

Also applies to: 82-91

src/components/Request/views/ReqFulfillBankFlowManager.tsx (1)

58-58: Remove stray debug log.

-    console.log('first')
src/components/Profile/views/IdentityVerification.view.tsx (1)

31-40: Remove unused name-splitting and clean dependencies.

These vars are no longer needed with fullName. Keeps lint quiet and memo accurate.

-    const [firstName, ...lastNameParts] = (user?.user.fullName ?? '').split(' ')
-    const lastName = lastNameParts.join(' ')
-
     const initialUserDetails: Partial<UserDetailsFormData> = useMemo(
         () => ({
             fullName: user?.user.fullName ?? '',
             email: user?.user.email ?? '',
         }),
-        [user?.user.fullName, user?.user.email, firstName, lastName]
+        [user?.user.fullName, user?.user.email]
     )
src/components/Global/PostSignupActionManager/post-signup-action.consts.ts (1)

15-15: Fix typo in comment.

“determing” → “determining”.

-        // this regex will match any path that resembles the request link, this helps in determing if the user is coming from a request link
+        // this regex will match any path that resembles the request link, this helps in determining if the user is coming from a request link
src/components/Global/PostSignupActionManager/index.tsx (1)

17-23: Tighten types for actionConfig.icon.

Use IconName instead of any to catch mismatches at compile time.

-    const [actionConfig, setActionConfig] = useState<{
+    const [actionConfig, setActionConfig] = useState<{
         cta: string
         title: string
         description: string
-        icon: any
+        icon: IconName
         action: () => void
     } | null>(null)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b37c3cc and 4da9484.

📒 Files selected for processing (8)
  • src/app/[...recipient]/client.tsx (3 hunks)
  • src/components/AddMoney/UserDetailsForm.tsx (3 hunks)
  • src/components/Common/ActionList.tsx (2 hunks)
  • src/components/Global/PostSignupActionManager/index.tsx (1 hunks)
  • src/components/Global/PostSignupActionManager/post-signup-action.consts.ts (1 hunks)
  • src/components/Kyc/index.tsx (2 hunks)
  • src/components/Profile/views/IdentityVerification.view.tsx (2 hunks)
  • src/components/Request/views/ReqFulfillBankFlowManager.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-20T09:08:19.266Z
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#1112
File: src/components/Claim/Link/views/BankFlowManager.view.tsx:336-343
Timestamp: 2025-08-20T09:08:19.266Z
Learning: In the KYC flow implementation, `setJustCompletedKyc` must be called after `await fetchUser()` in the `handleKycSuccess` callback. Setting `justCompletedKyc` before fetching the user would cause a re-fetching loop because `handleKycSuccess` is set in a useEffect inside the KYC hook, which would cause the UI flow to get stuck in one view.

Applied to files:

  • src/components/Kyc/index.tsx
🧬 Code graph analysis (3)
src/components/Kyc/index.tsx (1)
src/utils/general.utils.ts (1)
  • saveRedirectUrl (1214-1218)
src/components/Global/PostSignupActionManager/post-signup-action.consts.ts (1)
src/components/Global/Icons/Icon.tsx (1)
  • IconName (64-124)
src/app/[...recipient]/client.tsx (2)
src/context/RequestFulfillmentFlowContext.tsx (1)
  • useRequestFulfillmentFlow (102-108)
src/hooks/useDetermineBankRequestType.ts (1)
  • useDetermineBankRequestType (18-71)
⏰ 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 (7)
src/components/Kyc/index.tsx (1)

27-27: LGTM: step tracking hook integration is consistent.

useClaimLink().addParamStep('bank') aligns with the flow in ActionList and keeps URL-driven navigation cohesive.

src/components/Common/ActionList.tsx (2)

98-101: LGTM: bank-step URL param added before guest verification.

This matches the KYC modal behavior and keeps bank flow tracking consistent.


187-193: Confirm redirect behavior contract on GuestVerificationModal.

Passing redirectToVerification looks right; please verify the component defaults and that closing the modal still works without redirection in other call sites.

src/components/Request/views/ReqFulfillBankFlowManager.tsx (1)

117-121: KYC success callback ordering — verify against KYC hook expectations.

Per our past learning, if you use a justCompletedKyc flag, set it only after await fetchUser(). Confirm whether such a flag exists in this flow; if yes, ensure ordering to avoid refetch loops.

src/components/Profile/views/IdentityVerification.view.tsx (1)

49-51: LGTM: update payload now uses fullName directly.

src/components/Global/PostSignupActionManager/post-signup-action.consts.ts (1)

18-22: Copy and icon LGTM.

Title/description are consistent with the verification flow, CTA is clear, and 'check' is a valid IconName.

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

62-62: Confirm BaseModal enforces preventClose and ensure a visible exit when preventClose=true

  • ActionModal accepts and forwards preventClose and toggles the close-button via hideModalCloseButton (src/components/Global/ActionModal/index.tsx).
  • Repo search did not locate the Modal implementation imported from '@/components/Global/Modal' — cannot verify that preventClose blocks backdrop clicks and Escape or how classButtonClose is applied.
  • Verify BaseModal implements: (1) when preventClose=true, backdrop click and Escape are disabled; (2) when preventClose=true and there is only one CTA, an accessible close control remains (visible "X" or a secondary "Not now" CTA) to avoid trapping users.

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: 0

Caution

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

⚠️ Outside diff range comments (2)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (2)

244-254: initialUserDetails still uses first/last name — migrate to fullName to match form and payload

This will otherwise break TS types and prefill logic. Remove the split and provide fullName instead.

Apply:

-    const [firstName, ...lastNameParts] = (user?.user.fullName ?? '').split(' ')
-    const lastName = lastNameParts.join(' ')
-
     const initialUserDetails: Partial<UserDetailsFormData> = useMemo(
-        () => ({
-            firstName: user?.user.fullName ? firstName : '',
-            lastName: user?.user.fullName ? lastName : '',
-            email: user?.user.email ?? '',
-        }),
-        [user?.user.fullName, user?.user.email, firstName, lastName]
+        () => ({
+            fullName: user?.user.fullName ?? '',
+            email: user?.user.email ?? '',
+        }),
+        [user?.user.fullName, user?.user.email]
     )

281-287: Fix initialUserDetails shape — pass fullName (not firstName/lastName)

UserDetailsForm expects UserDetailsFormData = { fullName, email } but src/app/(mobile-ui)/add-money/[country]/bank/page.tsx builds initialUserDetails as { firstName, lastName, email }, so fullName will be undefined. Change the useMemo to return { fullName: user?.user.fullName ?? '', email: user?.user.email ?? '' } and update the same pattern in src/components/Request/views/ReqFulfillBankFlowManager.tsx and src/components/Profile/views/IdentityVerification.view.tsx.

🧹 Nitpick comments (5)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (5)

183-191: Use the thrown error message instead of relying on possibly stale hook error

onrampError may not reflect the current failure; prefer the caught error with a fallback.

-        } catch (error) {
-            setShowWarningModal(false)
-            if (onrampError) {
-                setError({
-                    showError: true,
-                    errorMessage: onrampError,
-                })
-            }
-        }
+        } catch (err: any) {
+            const message =
+                (err && err.message) || onrampError || 'Could not start onramp. Please try again.'
+            setError({ showError: true, errorMessage: message })
+        }

123-131: Add currency symbol to minimum-deposit validation error

Improves UX clarity across countries. Remember to update deps to avoid stale symbol.

-            if (amount && amount < minimumAmount) {
-                setError({ showError: true, errorMessage: `Minimum deposit is ${minimumAmount}.` })
+            if (amount && amount < minimumAmount) {
+                const currencyCode = selectedCountry ? getCurrencyConfig(selectedCountry.id, 'onramp').currency : undefined
+                const symbol = currencyCode ? getCurrencySymbol(currencyCode) : ''
+                setError({ showError: true, errorMessage: `Minimum deposit is ${symbol}${minimumAmount}.` })
                 return false
             }
-        [setError, minimumAmount]
+        [setError, minimumAmount, selectedCountry?.id]

333-342: Avoid double getCurrencyConfig calls

Minor perf/readability: compute once before JSX or memoize.

Example (outside JSX):

const onrampCurrency = useMemo(() => {
  if (!selectedCountry) return undefined
  const cfg = getCurrencyConfig(selectedCountry.id, 'onramp')
  return { code: cfg.currency, symbol: getCurrencySymbol(cfg.currency), price: 1 }
}, [selectedCountry?.id])

Then pass currency={onrampCurrency}.


36-38: Remove unused risk-acceptance state, or wire it into the modal

isRiskAccepted is set/reset but never read nor passed to OnrampConfirmationModal.

-    const [isRiskAccepted, setIsRiskAccepted] = useState<boolean>(false)
...
-        setIsRiskAccepted(false)
...
-        setIsRiskAccepted(false)

Also applies to: 195-197


102-109: Duplicate “advance to inputAmount” paths

Both the KYC-status effect and onKycSuccess move to inputAmount. Consolidate to a single path to avoid double state churn and edge races.

Would you prefer to rely solely on websocket status (and drop onKycSuccess), or keep onKycSuccess and remove the status watcher for step === 'kyc'?

Also applies to: 203-207

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4da9484 and d43fa70.

📒 Files selected for processing (1)
  • src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1094
File: src/utils/withdraw.utils.ts:181-191
Timestamp: 2025-08-14T14:42:54.411Z
Learning: The countryCodeMap in src/components/AddMoney/consts/index.ts uses uppercase 3-letter country codes as keys (like 'AUT', 'BEL', 'CZE') that map to 2-letter country codes, requiring input normalization to uppercase for proper lookups.

Applied to files:

  • src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
⏰ 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/app/(mobile-ui)/add-money/[country]/bank/page.tsx (1)

216-221: Switch to unified fullName in updateUserById — good change

Payload now aligns with the new single-name model.

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.

minor PR. has one unnecessary log line. I don't see anything critical

@Zishan-7 Zishan-7 merged commit 26cd12f into peanut-wallet-dev Sep 15, 2025
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Oct 16, 2025
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