Search code examples
javascriptvaporleaf

Javascript function in vapor 3 leaf - Help Need


I have a Javascript function in a leaf page using Vapor 3 the function should trigger a post to an api to save a customers card detials and return a token representing that card. I would normally do this in swift on our vapor server but to be PCI complient we are not allowed to take the customers credit card detials onto our server they must go directly to Sum Up (payment provider) I have no experiance with javascript and after lots of googling this it the fucntion I came up with.

    <script>
            function savecard() {

                var name = document.getElementById("nameonCard").value
                var cardNo = document.getElementById("cardNumber").value
                var expiry_year = document.getElementById("expiryMonth").value
                var expiry_month = document.getElementById("expiryYear").value
                var cvv = document.getElementById("cvc").value
                var body = `{"type":"card","card":{"name":"${name}","number":"${cardNo}", "expiry_month": "${expiry_month}", "expiry_year": "${expiry_year}","cvv": "${cvv}"}}`
                return fetch("https://api.sumup.com/v0.1/customers/" + #(sumCustId) + "/payment-instruments", {
                  method: "POST"
                  headers: {
                    "Authorization": "Basic " + #(auth),
                    "Content-Type": "application/json"
                  },
                  data: body,
                })
                .then(function(response){
                      document.getElementById("response").value = response.text()
                      return response.text();
                })
                .then(function(data){
                    console.log(data)//text version
                    var data_obj = JSON.parse(data);
                    document.getElementById("data_obj").value = data_obj
                    return data_obj
                })
            }
        </script>

I don't appear to be getting anything back but I'm not sure where I am going wrong, any help is much appreciated.

Here is the entire leaf page.

<!doctype html>
<html lang="en">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

        <title>Pay for Membership</title>
        <body>
            <div class="card bg-dark text-white h-100">
                <img class="card-img bg-dark img-fluid" src="https://images.unsplash.com/photo-1575151772039-542722abbf63?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format" alt="Card image">
                    <div class="card-img-overlay">
                        <div class="card-deck">
                        <div class="card bg-transparent border-warning align-self-start ">
                        <div class="card-header">
                            <h4 class="card-title text-center">Order Summary</h4>
                        </div>
                        <div class="card-body">
                            <ul>
                                #for(sum in orderSum){
                                    #if(isLast == false){
                                    <li class="list-group-item bg-transparent d-flex justify-content-between align-items-centert">#noam(sum)
                                    <span class="badge badge-info badge-pill text-right align-self-center">#am(sum)</span>
                                    </li>
                                    }
                                }
                            </ul>
                        </div>
                        <div class="card-footer text-center">
                            #for(sum in orderSum){
                                #if(isLast){
                                    <h5>#(sum)</h5>
                                }
                            }
                        </div>
                        </div>
                        <div class="card bg-dark border-warning">
                            <div class="card-header">
                                <h4 class="card-title">Payment Details</h4>
                            </div>
                            <div class="card-body">
                                <form method="post" action="/completedsumupmember" id="paymentForm">
                                <div class="row form-group" hidden>
                                <input type="number" class="form-control" id="amount" name="amount" value =#(amount) hidden>
                                <input type="text" class="form-control" id="currency" name="currency" value =#(currency) hidden>
                                <input type="text" class="form-control" id="orderId" name="orderId" value =#(orderId) hidden>
                                <input type="text" class="form-control" id="desc" name="desc" value =#(desc) hidden>
                                <input type="text" class="form-control" id="type" name="type" value =#(type) hidden>
                                <input type="text" class="form-control" id="orgId" name="orgId" value =#(orgId) hidden>
                                <input type="text" class="form-control" id="payToEmail" name="payToEmail" value =#(payToEmail) hidden>
                                <input type="text" class="form-control" id="auth" name="auth" value =#(auth) hidden>
                                <input type="hidden" class="form-control" id="response" name="response" value ="" hidden>
                                <input type="hidden" class="form-control" id="data_obj" name="data_obj" value ="" hidden>
                                <input type="text" class="form-control" id="customerId" name="customerId" value =#(sumCustId) hidden>
                            </div>
                            <div class="row form-group">
                                <div class = "col-md">
                                    <label for="nameonCard">Name on the Card</label>
                                    <input type="text" class="form-control" id="nameonCard" name="nameonCard" placeholder="John Smith" required>
                                </div>
                            </div>
                            <div class ="row form-group">
                                <div class ="col-lg">
                                    <label for="cardNumber">Card Number</label>
                                    <input type="number" class="form-control" id="cardNumber" name="cardNumber" placeholder="1111 2222 3333 4444" required>
                            </div>
                            </div>
                                <div class = "row form-group">
                                    <div class = "col-md">
                                        <label for="expiryMonth">Expriy Month</label>
                                        <input type="text" class="form-control" id="expiryMonth" name="expiryMonth" placeholder="mm" required>
                                    </div>
                                    <div class = "col-md">
                                        <label for="expiry">Expriy Year</label>
                                        <input type="text" class="form-control" id="expiryYear" name="expiryYear" placeholder="yy" required>
                                    </div>
                                    <div class = "col-md">
                                        <label for="cvc">CVV</label>
                                        <input type="text" class="form-control" id="cvc" name="cvc" placeholder="000" required>
                                    </div>
                                </div>
                                <div class="card-footer text-center">
                                    <button class="btn btn-warning btn-block" type="submit" onclick="savecard()">Pay Now</button>
                                </div>
                                </form>
                            </div>


                        </div>
                    </div>
                    </div>


            <!-- Optional JavaScript -->
            <!-- jQuery first, then Popper.js, then Bootstrap JS -->
            <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
            <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
            <script>
                function savecard() {

                    console.log('do something ')
                    var name = document.getElementById("nameonCard").value
                    var cardNo = document.getElementById("cardNumber").value
                    var expiry_year = document.getElementById("expiryMonth").value
                    var expiry_month = document.getElementById("expiryYear").value
                    var cvv = document.getElementById("cvc").value
                    var body = `{"type":"card","card":{"name":"${name}","number":"${cardNo}", "expiry_month": "${expiry_month}", "expiry_year": "${expiry_year}","cvv": "${cvv}"}}`
                    return fetch("https://api.sumup.com/v0.1/customers/" + #(sumCustId) + "/payment-instruments", {
                      method: "POST"
                      headers: {
                        "Authorization": "Basic " + #(auth),
                        "Content-Type": "application/json"
                      },
                      data: body,
                    })
                    .then(function(response){
                          document.getElementById("response").value = response.text()
                          return response.text();
                    })
                    .then(function(data){
                        console.log(data)//text version
                        var data_obj = JSON.parse(data);
                        document.getElementById("data_obj").value = data_obj
                        return data_obj
                    })
                }
            </script>
        </body>
    </html> 

I have finally managed to get a function that works, which is below.

    <script>
        function savecard() {
            let customerId = document.getElementById("customerId").value;
            let url = "https://api.sumup.com/v0.1/customers/" + customerId + "/payment-instruments"
            let auth = " Basic " + document.getElementById("auth").value;
            alert(auth);

            let cardBody = {
                type:"card",
                card: {
                name: document.getElementById("nameonCard").value,
                cardNo: document.getElementById("cardNumber").value,
                expiry_year: document.getElementById("expiryMonth").value,
                expiry_month: document.getElementById("expiryYear").value,
                cvv: document.getElementById("cvc").value
                }
                };
            alert(cardBody.card.name);
            let options = {
                //mode: 'no-cors',
                method: 'POST',
                body: JSON.stringify(cardBody),
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': auth
                }
            }

            fetch(url, options)
            .then(res => res.json())
            .then(res => alert(res))
            .catch(err => alert(`Error with message: ${err}`));;
        }
    </script> 

However I am now getting an error in the catch

SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data

Seems like this is a simple typo, but I've been looking at it to long to see what it is.


Solution

  • In the end this worked. I thin by placing it in the head of the leaf file and removing any leaf tags fixed the issues. Instead of using leaf tags I added hidden form inputs with the values set by the leaf tag then accessed that value in the function.

    <script>
            function savecard() {
                let customerId = document.getElementById("customerId").value; // for testing hard code value in form
                let url = "https://api.sumup.com/v0.1/customers/" + customerId + "/payment-instruments"
                let auth = " Basic " + document.getElementById("auth").value; // for testing hard code value in form
    
    
                let cardBody = {
                    type:"card",
                    card: {
                    name: document.getElementById("nameonCard").value,
                    cardNo: document.getElementById("cardNumber").value,
                    expiry_year: document.getElementById("expiryMonth").value,
                    expiry_month: document.getElementById("expiryYear").value,
                    cvv: document.getElementById("cvc").value
                    }
                    };
    
                let headers = {
                    'Authorization': auth,
                    'Content-Type': 'application/json'
                     }
                let options = {
                    //mode: 'no-cors',
                    method: 'POST',
                    body: JSON.stringify(cardBody), //
                    headers: headers
                }
    
                fetch(url, options)
                .then(res => res.json())
                    var token = res.token
                    document.getElementById("token").value = token
                    .then(res => console.log(res))
                .catch(err => alert(`Error with message: ${err}`));;
    
                document.getElementById("paymentForm").submit()
            }
        </script>
    

    Hopefully that helps someone.