Skip to content

fix: disable 'pay now' button until stripe form is loaded#134

Open
tomrndom wants to merge 3 commits intomainfrom
fix/stripe-form-load-button
Open

fix: disable 'pay now' button until stripe form is loaded#134
tomrndom wants to merge 3 commits intomainfrom
fix/stripe-form-load-button

Conversation

@tomrndom
Copy link
Copy Markdown
Contributor

@tomrndom tomrndom commented Oct 17, 2025

ref: https://app.clickup.com/t/86b73bfnu

Signed-off-by: Tomás Castillo tcastilloboireau@gmail.com

Summary by CodeRabbit

  • New Features

    • Added internationalized labels for all action buttons (Back, Get Ticket, Next, Pay, Loading).
    • Payment flow now reports readiness so the pay action shows appropriate label/state and is disabled until ready.
  • Style

    • Improved disabled button styling with explicit not-allowed cursor for clearer feedback.

Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
@tomrndom tomrndom requested a review from smarcet October 17, 2025 00:45
Comment thread src/components/button-bar/index.js Outdated
Comment thread src/components/stripe-form/index.js Outdated
Copy link
Copy Markdown
Collaborator

@smarcet smarcet left a comment

Choose a reason for hiding this comment

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

@tomrndom please review comments

Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 21, 2026

📝 Walkthrough

Walkthrough

Adds i18n translations for button labels and wires Stripe PaymentElement readiness through a new STRIPE_READY action and prop plumbing so UI enables/disables payment actions based on Stripe readiness.

Changes

Cohort / File(s) Summary
Button UI & i18n
src/components/button-bar/index.js, src/i18n/en.json
Replaced hard-coded button labels with translated keys (bar_button.*) and added the new translation block in English. button-bar now accepts stripeReady to control payment button state/label.
Stripe readiness plumbing
src/components/stripe-form/index.js, src/components/stripe-component/index.js, src/components/payment/index.js
Added onStripeReady prop, attach PaymentElement ready listener in StripeForm to call it, and thread onStripeReady from Payment → StripeProvider → StripeForm.
State & actions
src/actions.js, src/reducer.js, src/components/registration-lite.js
Introduced STRIPE_READY action and setStripeReady action creator; added stripeReady to reducer state (reset on step change) and mapped stripeReady/setStripeReady through RegistrationLite to child components.
Styles
src/components/button-bar/index.module.scss
Added disabled state styling for buttons inside .actions (cursor: not-allowed !important).
Manifest
package.json
Minor manifest change (small modifications to package metadata).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as RegistrationLite / ButtonBar
    participant Payment as PaymentComponent
    participant Provider as StripeProvider
    participant StripeForm
    participant Redux

    User->>UI: opens payment step
    UI->>Payment: render PaymentComponent (onStripeReady=setStripeReady)
    Payment->>Provider: render StripeProvider (onStripeReady)
    Provider->>StripeForm: render StripeForm (onStripeReady)
    StripeForm->>StripeForm: attach PaymentElement 'ready' listener
    StripeForm->>Provider: onStripeReady()
    Provider->>Redux: dispatch setStripeReady()
    Redux-->>UI: update stripeReady=true
    UI->>User: enable Pay button / show "pay_now" label
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I hopped through keys and tiny strings,
Translated buttons, ready wings.
When Stripe is set and humming bright,
The pay button wakes — what pure delight! 🐇✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the changeset: disabling the 'pay now' button until the Stripe form loads, which is reflected in the stripeReady state management and button disable logic across multiple components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/stripe-form-load-button

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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

Copy link
Copy Markdown

@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

🤖 Fix all issues with AI agents
In `@src/components/button-bar/index.js`:
- Line 41: The button in ButtonBar is currently hard-disabled when step ===
STEP_PAYMENT which conflicts with StripeForm's DOM manipulation; change
ButtonBar (component name ButtonBar in src/components/button-bar/index.js) to
accept a boolean prop like isPaymentReady and set the payment button's disabled
attribute to !isPaymentReady (only for the branch where step === STEP_PAYMENT
and id "payment-form-btn"), then wire that prop from the parent or Redux state
(or from StripeForm via lifting state) instead of toggling the DOM directly in
stripe-form/index.js; also remove or replace the direct DOM enable/disable in
StripeForm (stripe-form/index.js, the logic around lines 78-84) so React fully
controls the button state.
🧹 Nitpick comments (1)
src/components/stripe-form/index.js (1)

74-84: Add cleanup for the PaymentElement ready listener.

Without removing the handler, remounts or element changes can register multiple listeners. Prefer on + off with a named handler.

♻️ Suggested cleanup
-            if (pe) {
-                pe.on("ready", () => {
+            if (pe) {
+                const handleReady = () => {
                     const btn = document.getElementById("payment-form-btn");
                     if (btn) {
                         btn.disabled = false;
                         btn.textContent = T.translate("bar_button.pay_now");
                     }
-                });
+                };
+                pe.on("ready", handleReady);
+                return () => pe.off("ready", handleReady);
             }

Comment thread src/components/button-bar/index.js Outdated
{step === STEP_PAYMENT && <button className={`${styles.button} button`} id="payment-form-btn" type="submit" form="payment-form">Pay Now</button>}
{step === STEP_PERSONAL_INFO && ticketType?.cost === 0 && <button className={`${styles.button} button`} type="submit" form="personal-info-form">{T.translate("bar_button.get_ticket")}</button>}
{step === STEP_PERSONAL_INFO && ticketType?.cost > 0 && <button className={`${styles.button} button`} type="submit" form="personal-info-form">{T.translate("bar_button.next")}</button>}
{step === STEP_PAYMENT && <button className={`${styles.button} button`} id="payment-form-btn" type="submit" disabled form="payment-form">{T.translate("bar_button.loading")}</button>}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the button-bar component at the specified location
cat -n src/components/button-bar/index.js | head -80

Repository: fntechgit/summit-registration-lite

Length of output: 3662


🏁 Script executed:

# Search for StripeForm component to understand how it interacts with the button
fd -t f "StripeForm" --search-path .

Repository: fntechgit/summit-registration-lite

Length of output: 60


🏁 Script executed:

# Look for files that might contain StripeForm (case-insensitive)
fd -t f -i stripe .

Repository: fntechgit/summit-registration-lite

Length of output: 126


🏁 Script executed:

# Search for DOM manipulations on payment-form-btn or similar elements
rg "payment-form-btn|getElementById.*payment|querySelector.*payment" -B 2 -A 2

Repository: fntechgit/summit-registration-lite

Length of output: 1651


🏁 Script executed:

# Search for direct DOM mutations using disabled property
rg "\.disabled\s*=" -B 3 -A 3

Repository: fntechgit/summit-registration-lite

Length of output: 2361


🏁 Script executed:

# Check for form element manipulation in JavaScript
rg "form\[" -B 2 -A 2 | head -50

Repository: fntechgit/summit-registration-lite

Length of output: 60


🏁 Script executed:

# Get more context from stripe-form component to see how DOM manipulations fit in
cat -n src/components/stripe-form/index.js | head -150

Repository: fntechgit/summit-registration-lite

Length of output: 6461


🏁 Script executed:

# Check the full stripe-form to understand lifecycle and timing
wc -l src/components/stripe-form/index.js

Repository: fntechgit/summit-registration-lite

Length of output: 117


Move button disabled state to React props instead of hard-coding it in the template.

The button is rendered with disabled={true} (hard-coded), but StripeForm directly manipulates the DOM to enable it when payment is ready (line 78-84 in stripe-form/index.js). Any re-render of button-bar while on STEP_PAYMENT will reset the button back to disabled, overwriting StripeForm's changes and leaving the button stuck disabled even though payment is ready. This creates unpredictable behavior when parent state changes.

Pass isPaymentReady as a prop from parent or Redux state, and wire it from StripeForm to ensure the button state is always driven by React, not by competing DOM manipulations.

🤖 Prompt for AI Agents
In `@src/components/button-bar/index.js` at line 41, The button in ButtonBar is
currently hard-disabled when step === STEP_PAYMENT which conflicts with
StripeForm's DOM manipulation; change ButtonBar (component name ButtonBar in
src/components/button-bar/index.js) to accept a boolean prop like isPaymentReady
and set the payment button's disabled attribute to !isPaymentReady (only for the
branch where step === STEP_PAYMENT and id "payment-form-btn"), then wire that
prop from the parent or Redux state (or from StripeForm via lifting state)
instead of toggling the DOM directly in stripe-form/index.js; also remove or
replace the direct DOM enable/disable in StripeForm (stripe-form/index.js, the
logic around lines 78-84) so React fully controls the button state.

Comment thread src/components/stripe-form/index.js Outdated
Copy link
Copy Markdown
Collaborator

@smarcet smarcet left a comment

Choose a reason for hiding this comment

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

@tomrndom please review comments

Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/registration-lite.js`:
- Around line 495-496: The Pay button is blocked by a Stripe-specific flag
stripeReady in ButtonBar; change this to a provider-agnostic readiness signal:
rename stripeReady to paymentReady and update providers to call the ready
callback (e.g., have LawpayForm invoke the same onReady/ready handler) or modify
ButtonBar to enable the button based on provider type (check current provider
id/type) instead of !stripeReady; update all references (stripeReady →
paymentReady) including the Stripe provider's ready callback and any prop names
passed to ButtonBar so non-Stripe providers can set readiness and the Pay button
enables correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ce0dad4c-873b-4cbf-8001-60e976efe8ff

📥 Commits

Reviewing files that changed from the base of the PR and between 2d8793d and 11b4d4f.

📒 Files selected for processing (7)
  • src/actions.js
  • src/components/button-bar/index.js
  • src/components/payment/index.js
  • src/components/registration-lite.js
  • src/components/stripe-component/index.js
  • src/components/stripe-form/index.js
  • src/reducer.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/button-bar/index.js
  • src/components/stripe-form/index.js

Comment on lines +495 to 496
stripeReady={stripeReady}
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate ButtonBar implementation =="
button_file="$(fd "index.js" src/components/button-bar | head -n 1 || true)"
if [[ -z "${button_file}" ]]; then
  echo "ButtonBar file not found under src/components/button-bar"
  exit 0
fi
echo "Found: ${button_file}"

echo
echo "== Inspect ButtonBar disabled logic and stripeReady usage =="
rg -n -C4 "stripeReady|disabled|STEP_PAYMENT|PAYMENT_PROVIDER|onClick|pay" "${button_file}"

echo
echo "== Confirm props provided by RegistrationLite =="
rg -n -C3 "<ButtonBarComponent|stripeReady|provider=" src/components/registration-lite.js

Repository: fntechgit/summit-registration-lite

Length of output: 4627


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find stripeReady initialization and state management =="
rg -n "stripeReady.*=" src/components/registration-lite.js | head -20

echo
echo "== Find STEP_PAYMENT usage in registration-lite.js =="
rg -n "STEP_PAYMENT" src/components/registration-lite.js | head -20

echo
echo "== Look for payment provider logic and flow =="
rg -n -B5 -A5 "changeStep.*STEP_PAYMENT\|provider.*STEP_PAYMENT\|payTicket" src/components/registration-lite.js | head -50

echo
echo "== Check if stripeReady is initialized based on provider =="
rg -n -B10 "setStripeReady" src/components/registration-lite.js | head -30

Repository: fntechgit/summit-registration-lite

Length of output: 411


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find where step changes to STEP_PAYMENT =="
rg -n -B3 -A3 "STEP_PAYMENT" src/components/registration-lite.js

echo
echo "== Search for payment component usage in registration-lite.js =="
rg -n -C5 "payment-component\|PaymentComponent\|step === STEP_PERSONAL_INFO" src/components/registration-lite.js | head -80

echo
echo "== Look for provider conditional logic =="
rg -n "provider.*==\|provider.*Stripe" src/components/registration-lite.js | head -20

Repository: fntechgit/summit-registration-lite

Length of output: 999


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search for validatePromoCode implementation and step transitions =="
rg -n "validatePromoCode" src/components/registration-lite.js -A5 -B2 | head -80

echo
echo "== Look for all step changes in the file =="
rg -n "changeStep\|setStep\|step =" src/components/registration-lite.js | head -30

echo
echo "== Check entire registration-lite file structure (first 200 lines) =="
head -200 src/components/registration-lite.js | tail -100

Repository: fntechgit/summit-registration-lite

Length of output: 1580


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find actions/validatePromoCode =="
fd "index.js" src/actions | head -1 | xargs -I {} sh -c 'echo "Searching in: {}"; rg -n "validatePromoCode" {} -A20 | head -60'

echo
echo "== Alternative: look for actions files =="
find src/actions -name "*.js" -type f 2>/dev/null | head -5

echo
echo "== Search validatePromoCode across actions directory =="
rg -n "validatePromoCode" src/actions/ -A10 | head -80

Repository: fntechgit/summit-registration-lite

Length of output: 230


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Explore src/ directory structure =="
find src -type d -name "*action*" -o -name "*reducer*" 2>/dev/null | head -10

echo
echo "== List all JS files in src/ =="
find src -maxdepth 2 -name "*.js" -type f 2>/dev/null | head -30

echo
echo "== Search for validatePromoCode definition across entire src =="
rg -n "export.*validatePromoCode\|const validatePromoCode\|function validatePromoCode" src/ 2>/dev/null | head -20

echo
echo "== Search for where step transitions happen =="
rg -n "STEP_PAYMENT\|STEP_PERSONAL_INFO" src/ | grep -v "node_modules\|registration-lite.js" | head -30

Repository: fntechgit/summit-registration-lite

Length of output: 579


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find validatePromoCode in actions.js =="
rg -n "validatePromoCode" src/actions.js -A30 | head -80

echo
echo "== Find step transitions in actions.js =="
rg -n "STEP_PAYMENT\|STEP_PERSONAL_INFO\|changeStep" src/actions.js | head -30

echo
echo "== Look for provider-specific logic in actions.js =="
rg -n "provider\|Stripe" src/actions.js | head -30

Repository: fntechgit/summit-registration-lite

Length of output: 1852


🏁 Script executed:

#!/bin/bash
set -euo zipefail

echo "== Get full validatePromoCode implementation (lines 196-260) =="
sed -n '196,260p' src/actions.js

echo
echo "== Search for changeStep action =="
rg -n "changeStep|CHANGE_STEP" src/actions.js -A5 | head -40

echo
echo "== Search for step changes related to payment =="
rg -n "dispatch.*step\|STEP_PAYMENT\|SET_STEP" src/actions.js | head -30

Repository: fntechgit/summit-registration-lite

Length of output: 131


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Get full validatePromoCode implementation (lines 196-260) =="
sed -n '196,260p' src/actions.js

echo
echo "== Search for changeStep action =="
rg -n "changeStep|CHANGE_STEP" src/actions.js -A5 | head -40

echo
echo "== Search for step changes related to payment =="
rg -n "dispatch.*step\|STEP_PAYMENT\|SET_STEP" src/actions.js | head -30

Repository: fntechgit/summit-registration-lite

Length of output: 4399


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Get reserveTicket implementation around line 326 =="
sed -n '255,380p' src/actions.js

echo
echo "== Search for other step changes to STEP_PAYMENT =="
rg -n "changeStep.*STEP_PAYMENT" src/actions.js

Repository: fntechgit/summit-registration-lite

Length of output: 5184


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find payTicketWithProvider implementation =="
rg -n "payTicketWithProvider" src/actions.js -A30 | head -100

echo
echo "== Check stripeReady in reducer =="
rg -n "stripeReady\|STRIPE_READY" src/reducer.js -B3 -A3 | head -60

echo
echo "== Find setStripeReady action =="
rg -n "setStripeReady\|SET_STRIPE_READY" src/actions.js -B2 -A5 | head -40

Repository: fntechgit/summit-registration-lite

Length of output: 2426


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check stripeReady initialization in reducer =="
rg -n "stripeReady" src/reducer.js -B5 -A5

echo
echo "== Find SET_STRIPE_READY or similar constants =="
rg -n "STRIPE_READY" src/

echo
echo "== Look for Stripe provider setup in PaymentComponent or payment logic =="
rg -n "setStripeReady" src/components/registration-lite.js -B5 -A5

Repository: fntechgit/summit-registration-lite

Length of output: 3152


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find where STRIPE_READY is dispatched (line 519) =="
sed -n '510,530p' src/actions.js

echo
echo "== Search for setStripeReady and STRIPE_READY dispatch =="
rg -n "STRIPE_READY\|dispatch.*STRIPE_READY" src/actions.js -B5 -A2

echo
echo "== Check if PaymentComponent or payment provider calls onStripeReady =="
rg -n "onStripeReady" src/

Repository: fntechgit/summit-registration-lite

Length of output: 453


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find PaymentComponent file =="
find src -name "*.js" | xargs grep -l "onStripeReady" | head -5

echo
echo "== Check where PaymentComponent is imported =="
rg -n "import.*PaymentComponent\|from.*payment" src/components/registration-lite.js

echo
echo "== Search for PaymentComponent definition in codebase =="
find src -type f -name "*.js" | xargs grep -l "export.*PaymentComponent\|const PaymentComponent" 2>/dev/null | head -5

Repository: fntechgit/summit-registration-lite

Length of output: 303


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Examine PaymentComponent implementation =="
cat src/components/payment/index.js | head -100

echo
echo "== Search for onStripeReady usage in payment component =="
rg -n "onStripeReady\|provider" src/components/payment/index.js | head -40

echo
echo "== Check StripeComponent and how it uses onStripeReady =="
rg -n "onStripeReady" src/components/stripe-form/index.js -B5 -A5 | head -50

Repository: fntechgit/summit-registration-lite

Length of output: 4013


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check LawpayForm implementation for ready callback =="
head -100 src/components/lawpay-form/index.js

echo
echo "== Search for any ready/onReady callback in lawpay-form =="
rg -n "onReady\|ready\|onError" src/components/lawpay-form/index.js | head -20

echo
echo "== Verify ButtonBar disabled logic one more time =="
sed -n '38,47p' src/components/button-bar/index.js

Repository: fntechgit/summit-registration-lite

Length of output: 3434


Pay button remains disabled for non-Stripe providers (e.g., LawPay) at the payment step.

The disabled={!stripeReady} check on the Pay button (ButtonBar line 41) blocks all payment providers, but stripeReady is only set by the Stripe provider's ready callback. LawpayForm does not trigger any ready callback, leaving the button permanently disabled for LawPay payments.

The variable name and gating logic are Stripe-specific and should be provider-agnostic. Either:

  • Rename stripeReady to paymentReady and have all payment providers (Stripe, LawPay, etc.) trigger the callback when ready, or
  • Check the provider type in ButtonBar's disabled condition instead of relying on a Stripe-only flag.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/registration-lite.js` around lines 495 - 496, The Pay button
is blocked by a Stripe-specific flag stripeReady in ButtonBar; change this to a
provider-agnostic readiness signal: rename stripeReady to paymentReady and
update providers to call the ready callback (e.g., have LawpayForm invoke the
same onReady/ready handler) or modify ButtonBar to enable the button based on
provider type (check current provider id/type) instead of !stripeReady; update
all references (stripeReady → paymentReady) including the Stripe provider's
ready callback and any prop names passed to ButtonBar so non-Stripe providers
can set readiness and the Pay button enables correctly.

@smarcet smarcet requested review from gcutrini and smarcet April 23, 2026 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants