fix: disable 'pay now' button until stripe form is loaded#134
fix: disable 'pay now' button until stripe form is loaded#134
Conversation
Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
📝 WalkthroughWalkthroughAdds 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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Comment |
There was a problem hiding this comment.
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 PaymentElementreadylistener.Without removing the handler, remounts or element changes can register multiple listeners. Prefer
on+offwith 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); }
| {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>} |
There was a problem hiding this comment.
🧩 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 -80Repository: 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 2Repository: fntechgit/summit-registration-lite
Length of output: 1651
🏁 Script executed:
# Search for direct DOM mutations using disabled property
rg "\.disabled\s*=" -B 3 -A 3Repository: fntechgit/summit-registration-lite
Length of output: 2361
🏁 Script executed:
# Check for form element manipulation in JavaScript
rg "form\[" -B 2 -A 2 | head -50Repository: 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 -150Repository: 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.jsRepository: 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.
Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
There was a problem hiding this comment.
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
📒 Files selected for processing (7)
src/actions.jssrc/components/button-bar/index.jssrc/components/payment/index.jssrc/components/registration-lite.jssrc/components/stripe-component/index.jssrc/components/stripe-form/index.jssrc/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
| stripeReady={stripeReady} | ||
| /> |
There was a problem hiding this comment.
🧩 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.jsRepository: 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 -30Repository: 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 -20Repository: 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 -100Repository: 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 -80Repository: 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 -30Repository: 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 -30Repository: 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 -30Repository: 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 -30Repository: 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.jsRepository: 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 -40Repository: 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 -A5Repository: 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 -5Repository: 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 -50Repository: 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.jsRepository: 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
stripeReadytopaymentReadyand 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.
ref: https://app.clickup.com/t/86b73bfnu
Signed-off-by: Tomás Castillo tcastilloboireau@gmail.com
Summary by CodeRabbit
New Features
Style