SqPaymentForm to Web Payments SDK for Laravel?

Is there a “for dummies” on how to do this? This is NOT simple, like it was to setup the square payment form. In my old code, I have the following in my head:

<script type="text/javascript" src="https://js.squareup.com/v2/paymentform"></script>
        <!-- link to the custom styles for SqPaymentForm -->
        <style>

            body, html {
                background-color: #F7F8F9;
                color: #373F4A;
                font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
                font-weight: normal;
                height: 100%;
            }

            button {
                border: 0;
                font-weight: 500;
            }

            fieldset {
                margin: 0;
                padding: 0;
                border: 0;
            }

            #form-container {
                position: relative;
                width: 380px;
                margin: 0 auto;
                top: 50%;
                transform: translateY(-50%);
            }

            .third {
                float: left;
                width: calc((100% - 32px) / 3);
                padding: 0;
                margin: 0 16px 16px 0;
            }

            .third:last-of-type {
                margin-right: 0;
            }

            /* Define how SqPaymentForm iframes should look */
            .sq-input {
                height: 56px;
                box-sizing: border-box;
                border: 1px solid #E0E2E3;
                background-color: white;
                border-radius: 6px;
                display: inline-block;
                -webkit-transition: border-color .2s ease-in-out;
                -moz-transition: border-color .2s ease-in-out;
                -ms-transition: border-color .2s ease-in-out;
                transition: border-color .2s ease-in-out;
            }

            /* Define how SqPaymentForm iframes should look when they have focus */
            .sq-input--focus {
                border: 1px solid #4A90E2;
            }

            /* Define how SqPaymentForm iframes should look when they contain invalid values */
            .sq-input--error {
                border: 1px solid #E02F2F;
            }

            #sq-card-number {
                margin-bottom: 16px;
            }

            /* Customize the "Pay with Credit Card" button */
            .button-credit-card {
                width: 100%;
                height: 56px;
                margin-top: 10px;
                background: #4A90E2;
                border-radius: 6px;
                cursor: pointer;
                display: block;
                color: #FFFFFF;
                font-size: 16px;
                line-height: 24px;
                font-weight: 700;
                letter-spacing: 0;
                text-align: center;
                -webkit-transition: background .2s ease-in-out;
                -moz-transition: background .2s ease-in-out;
                -ms-transition: background .2s ease-in-out;
                transition: background .2s ease-in-out;
            }

            .button-credit-card:hover {
                background-color: #4281CB;
            }

        </style>
        <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
        <meta name="csrf-token" content="{{ csrf_token() }}">

The body code ended up like this (I had followed the Walkthrough for SqPaymentForm):

<!-- Begin Payment Form -->
        <div id="form-container row">
            <div id="sq-card-number"></div>
            <div class="third" id="sq-expiration-date"></div>
            <div class="third" id="sq-cvv"></div>
            <div class="third" id="sq-postal-code"></div>
            <button id="sq-creditcard" class="button-credit-card" onclick="onGetCardNonce(event)">Pay ${{number_format($payment->due_amt, 2)}}</button>
        </div>
        <!-- end #form-container -->
        <!-- End Payment Form -->

and the footer of my page:

{{--    Square payment form javascript    --}}
        <script type="text/javascript">

            const idempotency_key = uuidv4();

            // Create and initialize a payment form object
            const paymentForm = new SqPaymentForm({
                // Initialize the payment form elements

                //TODO: Replace with your sandbox application ID
                applicationId: "{MY_APPLICATION_ID}",
                inputClass: 'sq-input',
                autoBuild: false,
                // Customize the CSS for SqPaymentForm iframe elements
                inputStyles: [{
                    fontSize: '16px',
                    lineHeight: '24px',
                    padding: '16px',
                    placeholderColor: '#a0a0a0',
                    backgroundColor: 'transparent',
                }],
                // Initialize the credit card placeholders
                cardNumber: {
                    elementId: 'sq-card-number',
                    placeholder: 'Card Number'
                },
                cvv: {
                    elementId: 'sq-cvv',
                    placeholder: 'CVV'
                },
                expirationDate: {
                    elementId: 'sq-expiration-date',
                    placeholder: 'MM/YY'
                },
                postalCode: {
                    elementId: 'sq-postal-code',
                    placeholder: 'Zip Code'
                },
                // SqPaymentForm callback functions
                callbacks: {
                    /*
                    * callback function: cardNonceResponseReceived
                    * Triggered when: SqPaymentForm completes a card nonce request
                    */
                    cardNonceResponseReceived: function (errors, nonce, cardData) {
                        if (errors) {
                            // Log errors from nonce generation to the browser developer console.
                            console.error('Encountered errors:');
                            errors.forEach(function (error) {
                                console.error('  ' + error.message);
                            });
                            alert('Encountered errors, check browser developer console for more details');
                            return;
                        }
                        //TODO: Replace alert with code in step 2.1
                        fetch('{{ $payment->id }}', {
                            method: 'POST',
                            headers: {
                                'Accept': 'application/json',
                                'Content-Type': 'application/json',
                                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                            },
                            body: JSON.stringify({
                                nonce: nonce,
                                idempotency_key: {{ $payment->id }},
                                patient_id: {{ $payment->patient_id }},
                                location_id: "{MY_LOCATION_ID}"
                            })
                        })
                            .catch(err => {
                                alert('Network error: ' + err);
                            })
                            .then(response => {
                                if (!response.ok) {
                                    return response.json().then(
                                        errorInfo => Promise.reject(errorInfo));
                                }
                                return response.json();
                            })
                            .then(data => {
                                console.log(data);
                                // display alert showing payment completed successfully
                                // alert('Payment completed successfully!\n  Auth code: '+ data['auth_code'] + '\n');
                                // when alert closes, redirect to IHC receipt page
                                window.location.href=data['url'];
                            })
                            .catch(err => {
                                console.error(err);
                                alert('Payment failed!\n' + err['message']);
                            });

                    }
                }
            });
            paymentForm.build();

            //Generate a random UUID as an idempotency key for the payment request
            // length of idempotency_key should be less than 45
            function uuidv4() {
                return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
                    return v.toString(16);
                });
            }

            // onGetCardNonce is triggered when the "Pay $1.00" button is clicked
            function onGetCardNonce(event) {
                // Don't submit the form until SqPaymentForm returns with a nonce
                event.preventDefault();
                // Request a nonce from the SqPaymentForm object
                paymentForm.requestCardNonce();
            }
        </script>```

I figure I need to replace the body of the document with:
    <form id="payment-form">
        <div id="card-container"></div>
        <button id="card-button" type="button">Pay $1.00</button>
    </form>
    <div id="payment-status-container"></div>
    <!-- End Payment Form -->

and the header, should have:
    <!-- link to the custom styles for SqPaymentForm -->
    <script>
        {{-- Initialize Web Payments SDK varialbes --}}
        const appId = '{{ env('SQUARE_APPLICATION_ID') }}';
        const locationId = '{{ env('SQUARE_LOCATION') }}';

        // Initialize Card payment method by calling Payments.card()
        // method and attaching the payment method to the DOM with card.attach() method
        async function initializeCard(payments) {
            const card = await payments.card();
            await card.attach('#card-container');
            return card;
        }

        document.addEventListener('DOMContentLoaded', async function () {
            if (!window.Square) {
                throw new Error('Square.js failed to load properly');
            }
            const payments = window.Square.payments(appId, locationId);
            let card;
            try {
                card = await initializeCard(payments);
            } catch (e) {
                console.error('Initializing Card failed', e);
                return;
            }

            // Step 5.2: create card payment
            async function handlePaymentMethodSubmission(event, paymentMethod) {
                event.preventDefault();

                try {
                    // disable the submit button as we await tokenization and make a
                    // payment request.
                    cardButton.disabled = true;
                    const token = await tokenize(paymentMethod);
                    const paymentResults = await createPayment(token);
                    displayPaymentResults('SUCCESS');

                    console.debug('Payment Success', paymentResults);
                } catch (e) {
                    cardButton.disabled = false;
                    displayPaymentResults('FAILURE');
                    console.error(e.message);
                }
            }

            const cardButton = document.getElementById(
                'card-button'
            );
            cardButton.addEventListener('click', async function (event) {
                await handlePaymentMethodSubmission(event, card);
            });


        });

    </script>

I don't have anything at the end in the footer.  What else am I missing to get this thing working?  I already tried to follow the migration page and that was a shit-show.  Frustrated is an understatement.  When I try to use the sandbox, it doesn't display the payment form and gives me an https error in the console `Unhandled Promise Rejection: WebSdkEmbedError: Web Payments SDK can only be embedded on sites that use HTTPS`

Someone please help!  I'm happy to write something up if someone can help me make this work.

:wave: Is the environment you’re using to test the Web Payments SDK using https or is it using localhost? The form fields won’t show unless your using https or localhost. :slightly_smiling_face:

It’s using 127.0.01. So I just change that to day localhost instead and it should work? Awesome!

Yeah, that should render the form fields. :slightly_smiling_face:

I finally had a chance to sit down and try again using localhost. I’m getting the payment form to load, but am getting an error 419 when trying to get a response.

I do have a csrf tag in the head of the page, just like i had in the web payments sdk. what’s going on?