Score:0

Stripe Custom PHP & JavaScript Stripe Integrations: form refuses to load

cn flag

I'm attempting to create a webpage for my startup, which is subscription-based. We have Stripe in live mode, and are essentially storing cards for future use, allowing us to have different payment options available when creating new subscriptions. Subscriptions will then be assigned to a device (similar to the way Office 365 assigns licenses to users).

When a user signs up, our code automatically creates a Stripe customer ID with Stripe and stores it on the backend. We then have a settings page, which contains a section for "Payment Methods", which dynamically loads them server-side, and allowing new payment methods to be added by clicking a "+" button in the same area. The "+" button is set to onclick="addPaymentOption()", which calls this nifty piece of code (Clipped for relevancy):

function addPaymentOption(){
    //initiated by front end, loads stripe payment form
    
    const attachto = document.getElementById("payment-dash");
    const ppw_t = document.createElement("li");
    ppw_t.setAttribute("id", "payment_add_form_cover");
    ppw_t.setAttribute("style", "border-top: 1px solid #262626; margin-top: 6px;");
    ppw_t.innerHTML = '<h3>Add a Payment method</h3>';
    const ppw = document.createElement("div");
    ppw.setAttribute("id", "payment_add_form");
    ppw.setAttribute("style", "padding: 6px; max-width: 400px; margin: 0px auto;");
    ppw.innerHTML = '<form id="payment-form" action=""><div id="payment-element"></div><button id="submit" type="submit" style="width:100%;">Save card details</button><div id="error-message"></div></form><form id="address-element"><div id="address-element"></div></form>';
    attachto.appendChild(ppw_t);
    ppw_t.appendChild(ppw);
    (async () => {
        const response = await fetch('/settings/payments/secret'); //<-- Renders client secret in backend, in JSON format.
        const { client_secret: clientSecret } = await response.json();

        const options = {
            clientSecret: clientSecret
        };
        const stripe = Stripe('pk_live_51Mm3X7HIvvDoRmVUJay6Ib7MFBZgXvRtwwSosMh34h5GqCHZ0EKtnehc05DxFMfkggp2tzi6nu7ekNQnYyknMeC300T2iYxOHU');
        console.log(clientSecret);
        
        const elements = stripe.elements(options);
        
        
        const paymentElement = elements.create('payment'); // <-- create payment element
        
        paymentElement.mount('#payment-element');
        
        loadStripe();
        
    })();
}
function loadStripe(){
    const form = document.getElementById('payment-form');
        
        form.addEventListener('submit', async (event) => {
            event.preventDefault();
    
            const {error} = await stripe.confirmSetup({
                //`Elements` instance that was used to create the Payment Element
                elements,
                confirmParams: {
                    return_url: 'https://**********.com/settings/payments',
                }
            });
    
            if (error) {
                // This point will only be reached if there is an immediate error when
                // confirming the payment. Show error to your customer (for example, payment
                // details incomplete)
                const messageContainer = document.querySelector('#error-message');
                messageContainer.textContent = error.message;
            } else {
                // Your customer will be redirected to your `return_url`. For some payment
                // methods like iDEAL, your customer will be redirected to an intermediate
                // site first to authorize the payment, then redirected to the `return_url`.
            }
        });
}

The HTML where the code references (clipped for relevancy) is:

<ul class="Dashboard" id="payment-dash">
                    <li>
                        <contextmenu>
                            <ol>
                                <li onclick="addSubscription()">+</li>
                                <li onclick="doHelp()">?</li>
                            </ol>
                        </contextmenu>
                        <img src="/assets/img/ui/pay/subscriptions.png" alt=""/>
                        <h3>Subscriptions</h3>
                        <ul class="DashboardSub">
                            <li>
                                <header>
                                    <img src="/assets/img/static/lock_logo.png"/>
                                    <h4>Subscription #1</h4>
                                </header>
                                <span>Monthly cost: $12.99<br/>Linked to: <i>Device name</i></span>
                                
                                <opts><a href="#">Remove</a> | <a href="#">Assign</a></opts>
                            </li>
                            <li>
                                <header>
                                    <img src="/assets/img/static/lock_logo.png"/>
                                    <h4>Device #1</h4>
                                </header>
                                <span>Monthly cost: $12.99<br/>Linked to: <i>Device name</i></span>
                                
                                <opts><a href="#">Remove</a> | <a href="#">Assign</a></opts>
                            </li>
                            <li>
                                <header>
                                    <img src="/assets/img/static/lock_logo.png"/>
                                    <h4>Device #1</h4>
                                </header>
                                <span>Monthly cost: $12.99<br/>Linked to: <i>Device name</i></span>
                                
                                <opts><a href="#">Remove</a> | <a href="#">Assign</a></opts>
                            </li>
                            <li>
                                <header>
                                    <img src="/assets/img/icons/static/guardian-gpt.png"/>
                                    <h4>AI Family</h4>
                                </header>
                                <span>Monthly cost: $5.99<br/></span>
                                
                                <opts><a href="#">Remove</a></opts>
                            </li>
                            <div>
                                <b>Monthly total</b>: $42.99
                            </div>
                        </ul>
                    </li>
                    <li>
                        <contextmenu>
                            <ol>
                                <li onclick="addPaymentOption()">+</li>
                                <li>?</li>
                            </ol>
                        </contextmenu>
                        <img src="/assets/img/ui/pay/payment_methods.png" alt=""/>
                        <h3>Payment Methods</h3>
                        
                        <ul class="DashboardSub" id="payments">
                            <li>
                                <header>
                                    <img src="/assets/img/ui/pay/mc.png"/>
                                    <h4>Mastercard *1234</h4>
                                </header>
                                <span>Expires in 2025<br/>Last use: </span>
                                
                                <opts><a href="#">Remove</a> | <a href="#">Set Default</a></opts>
                            </li>
                            <li>
                                <header>
                                    <img src="/assets/img/ui/pay/visa.png"/>
                                    <h4>Mastercard *1234</h4>
                                </header>
                                <span>Expires in 2025<br/>Last use: </span>
                                
                                <opts><a href="#">Remove</a> | <a href="#">Set Default</a></opts>
                            </li>
                            <li>
                                <header>
                                    <img src="/assets/img/ui/pay/amex.png"/>
                                    <h4>Mastercard *1234</h4>
                                </header>
                                <span>Expires in 2025<br/>Last use: </span>
                                
                                <opts><a href="#">Remove</a> | <a href="#">Set Default</a></opts>
                            </li>
                            <li>
                                <header>
                                    <img src="/assets/img/ui/pay/discover.png"/>
                                    <h4>Mastercard *1234</h4>
                                </header>
                                <span>Expires in 2025<br/>Last use: </span>
                                
                                <opts><a href="#">Remove</a> | <a href="#">Set Default</a></opts>
                            </li>
                            <li>
                                <header>
                                    <img src="/assets/img/ui/pay/ach_pay.png"/>
                                    <h4>Bank Acct. *1234</h4>
                                </header>
                                <span>Expires in 2025<br/>Pre-auth: </span>
                                <opts><a href="#">Remove</a> | <a href="#">Set Default</a></opts>
                            </li>
                        </ul>
                    </li>
                    <li>
                        <img src="/assets/img/ui/pay/history.png" alt=""/>
                        <h3>Payment History</h3>
                        <table>
                            <tr>
                                <td><b>Subscriptions</b></td>
                                <td>4</td>
                            </tr>
                            <tr>
                                <td><b>Last Payment</b></td>
                                <td><b>$45.<sup>00</sup>.</td>
                            </tr>
                        </table>
                    </li>
                    <li>
                        <img src="/assets/img/ui/pay/cancel.png" alt=""/>
                        <h3>Cancel Service</h3>
                        <table>
                            <tr>
                                <td><b>Subscriptions</b></td>
                                <td>4</td>
                            </tr>
                            <tr>
                                <td><b>Last Payment</b></td>
                                <td><b>$45.<sup>00</sup>.</td>
                            </tr>
                        </table>
                    </li>
                </ul>

Also, the code for /secrets is:

if(isLoggedIn()){
                $customer_id = fetchstripeid();
                $intent = $stripe->setupIntents->create(
                [
                  'customer' => $customer_id,
                  'payment_method_types' => ['card_present'],
                ]);
                echo json_encode(array('client_secret' => $intent->client_secret));
                ob_flush();flush();
                die();
            }

A few revisions ago, it would properly create the form elements for credit card info and billing ZIP, but the "Save card details" button would disappear. I rearranged the code because it appeared that the element was being loaded and unloaded. Then, a few revisions later, the "Save card details" button loads into the form, but the credit card entry form elements refuse to load. All of the time, it gave me little to no error messages in the console.

Does anyone see something obvious here I'm missing? Is something loading before or after it's supposed to? My Stripe experience is limited, maybe there's a concept I don't get here?

I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.