-
Notifications
You must be signed in to change notification settings - Fork 0
2. HTML Webseite für einfachen PaymentRequest
Nun muss die payment_basic.html
mit einem beliebigen Editor geöffnet (Empfehlung: Atom).
In die Datei wird zunächst folgendes Grundgerüst kopiert:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>W3C Payment Request API Tutorial</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
margin: 0;
}
html {
font-family: sans-serif;
line-height: 1.4;
padding: 2em;
}
body > :not(:first-child) {
margin-top: 1.5em;
}
h1,
h2 {
line-height: 1.15;
}
.produkt {
max-width: 13em;
padding: 1em;
background: #fff;
}
.produkt> :not(:first-child) {
margin-top: 0.85em;
}
.produkt_bought {
padding: 1em;
background: #fff;
}
.data_list {
max-width: 100%;
}
.produkt_bought> :not(:first-child) {
margin-top: 0.85em;
}
.produkt_bought {
display: none;
}
.produkt_shadow {
position: relative;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
.produkt_shadow:after {
content: "";
position: absolute;
z-index: -1;
-webkit-box-shadow: 0 0 40px rgba(0, 0, 0, 0.8);
box-shadow: 0 0 40px rgba(0, 0, 0, 0.8);
bottom: 0px;
left: 10%;
right: 10%;
width: 80%;
height: 50%;
-moz-border-radius: 100%;
border-radius: 100%;
}
.produkt_meta {
display: flex;
align-items: center;
justify-content: space-between;
}
.produkt_button {
background-color: #008CBA;
color: #fff;
padding: 0.25em 1em;
text-decoration: none;
}
ul.nav {
margin:0;
padding:0;
list-style:none;
height:36px;
margin-top:20px;
font-family:Arial, Helvetica, sans-serif;
font-size:13px;
}
ul.nav li {
float:left;
}
ul.nav a {
display:block;
padding:0 28px;
color:#000;
text-decoration:none;
}
</style>
</head>
<body>
<h1>W3C Payment Request API Tutorial</h1>
<ul class="nav">
<li><a href="/">1. Basic</a></li>
<li><a href="/2">2. shippingAddress</a></li>
<li><a href="/3">3. Sale</a></li>
<li><a href="/4">4. reject Creditcards</a></li>
<li><a href="/5">5. Tax</a></li>
<li><a href="/6">6. reject shippingAddress</a></li>
</ul>
<p> Teil 1: Einfacher Payment Request </p>
<div class="produkt produkt_shadow" id="produkt">
<h2>Beispielprodukt</h2>
<p>Ich bin ein ganz tolles Produkt! Kauf mich!</p>
<div class="produkt_meta">
<strong class="produkt_preis">nur 49.99 €</strong>
<a href="#" id="produkt_button" class="produkt_button">Kaufen</a>
</div>
</div>
<div class="produkt_bought" id="produkt_bought">
<h2>Beispielprodukt gekauft!</h2>
<p>Sie haben das Beispielprodukt erfolgreich für 49,99 € gekauft.</p>
<p>Ihre Daten:</p>
<div id="data_list"></div>
</div>
<script>
</script>
</body>
</html>
Wir gehen die Datei jetzt Schritt für Schritt durch.
Zunächst werden die üblichen HTML-Tags und Metadaten gesetzt, dann der viewport
für die mobile Ansicht. Es folgt das CSS-Styling für die Seite und deren Elemente. Da dies nicht Teil des Tutorials ist, wird nicht weiter darauf eingegangen.
Danach folgt der HTML-Code für das Produkt. Das Produkt ist in einem div
-Element namens produkt
eingefasst, das eine Überschrift und Produktbeschreibung enthält. Ein weiteres Div ist dort für den Preis und den "Kaufen"-Button integriert. Weiter unten wird dann die spätere Ausgabe der persönlichen Daten und Zahlungsdaten in einem Div namens produkt_bought
definiert.
Es folgt der Javascript-Code, in dem wir schließlich den PaymentRequest zusammenbauen. Wir beginnen dort mit der Funktion handleProduktClick(e) {}
, die durch Klicken auf den Button "Kaufen" gestartet wird. Diese Funktion wird zwischen die Tags <script>
und </script>
gesetzt:
function handleProduktClick(e) {
e.preventDefault();
// Hier folgt der Code für den PaymentRequest
}
document.getElementById("produkt_button").addEventListener('click', handleProduktClick);
Der entsprechende Event Listener dafür wird direkt unterhalb der Funktion definiert mit document.getElementById("produkt_button").addEventListener('click', handleProduktClick)
.
Die Funktion handleProduktClick(e) {}
enthält den kompletten Code für den PaymentRequest. Wir definieren dort nun die Zahlungsmethode per Kreditkarte mit:
var creditCardPaymentMethod = {
supportedMethods: 'basic-card',
};
Dies bedeutet, dass wir alle Kreditkarten unterstützten wollen, also auch Prepaid-Kreditkarten, Kreditkarten von Visa, MasterCard etc. Die Variable ist bewusst so genannt, um später weitere Zahlungsmethoden anlegen zu können, die dann in dem Array supportedPaymentMethods
hinterlegt werden.
Bis jetzt sieht das Array wie folgt aus und wird unterhalb der creditCardPaymentMethod
definiert:
var supportedPaymentMethods = [creditCardPaymentMethod];
Weiter geht es mit den paymentDetails
, worin der Gesamtpreis, die Währung, der Einzelpreis und der Name des Produktes eingetragen werden. Diese Informationen sind später auch im PaymentRequest sichtbar.
var paymentDetails = {
total: {
label: 'Beispielprodukt',
amount: {
currency: 'EUR',
value: 49.99
}
}
};
Es folgt schließlich die Definition der Variable paymentRequest
, die eines Instanz des PaymentRequests mit obiger Konfiguration definiert.
var paymentRequest = new PaymentRequest(supportedPaymentMethods, paymentDetails);
Danach wird der PaymentRequest zusammengebaut. Das PaymentRequest-Fenster wird mit der show()
-Funktion angezeigt und es wird definiert, was im Erfolgs- bzw. Fehlerfall passieren soll. show()
definiert einen Promise, der im Erfolgsfall das Objekt paymentResponse
enthält, mit allen Daten, die der Nutzer in das PaymentRequest-Fenster eingegeben hat (das JSON.parse()
wandelt die Antwort vom Server als String
in ein JSON
-Objekt um). Sollte es einen Fehler bei der Rückgabe des paymentResponse
geben, wird im PaymentRequest-Fenster der entsprechende Fehler angezeigt return paymentResponse.complete('fail');
. Sollte der Benutzer das Fenster schließen oder ein sonstiger Fehler auftreten, wird in den Bereich .catch(err => {})
gesprungen und der Fehler in der Konsole ausgegeben.
Den folgenden Code unterhalb der Definition der paymentRequest
-Instanz einfügen:
paymentRequest
.show()
.then(paymentResponse => {
return verifyPaymentWithBackend(paymentResponse).then((success) => {
if (success) {
showPaymentResponse(JSON.parse(success));
return paymentResponse.complete('success');
} else {
return paymentResponse.complete('fail');
}
});
})
.catch(err => {
console.log('Error:', err);
});
Die Funktion verifyPaymentWithBackend(paymentResponse)
ist dazu da, die eingegebenen Daten des Benutzers im PaymentRequest-Fenster an den Server zu schicken. Dies funktioniert durch ein XMLHTTPREQUEST, das die Daten an die vorher definierte Ressource /payment
sendet. Sollte, wie bei einem POST (siehe REST) üblich, der Statuscode 201 zurückkommen, wurde die Ressource erfolgreich angelegt und die Daten zur Zahlung in der Datenbank gespeichert. Um den Erfolgsfall an den PaymentRequest zurückzugeben, "resolven" wir den Promise und geben als Parameter die Antwort des Servers mit, um die Daten später anzeigen zu können. Im Fehlerfall gibt der Resolve ein false
zurück, um eine Fehlermeldung im PaymentRequest auszulösen.
Den folgenden Code unterhalb der Definition des paymentRequest
einfügen:
function verifyPaymentWithBackend(data) {
return new Promise((resolve, reject) => {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function() {
if (xmlhttp.status == 201) {
resolve(xmlhttp.responseText);
} else {
resolve(false)
}
};
xmlhttp.open("POST", "/payment");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify(data));
});
}
Schließlich wird die Funktion showPaymentResponse(data)
definiert, die einige UI-Elemente verändert, um eine erfolgreiche Zahlung darzustellen. Um das Tutorial nicht unnötig kompliziert werden zu lassen, wurde auf eine Single-Page Application z.B. mit vue.js verzichtet. Ebenso existiert keine Nutzer-Authentifizierung, um eine Zahlung später einem bestimmten Benutzer zuzuordnen.
In der showPaymentResponse(data)
wird der Text vom Produkt-Button von "Kaufen" in "Gekauft" geändert, außerdem dessen Hintergrund verändert und der Event Listener entfernt, um einen weiteren Kauf bis zum erneuten Laden der Seite zu verhindern. In der data_list
wird anschließend das JSON-Objekt vom Server zurückgegeben, das die eingegebenen Daten des Benutzers enthält (Umwandlung von String
in JSON
mit JSON.stringify()
, um den Inhalt in der Variable data_list
anzeigen zu können.
Den folgenden Code unterhalb der Definition des verifyPaymentWithBackend(data)
-Funktion einfügen:
function showPaymentResponse(data) {
document.getElementById("produkt_button").innerHTML = 'Gekauft';
document.getElementById("produkt_button").style.backgroundColor = "#4CAF50";
document.getElementById("produkt_button").removeEventListener('click', handleProduktClick);
document.getElementById("produkt_bought").style.display = "block";
document.getElementById("data_list").innerHTML = JSON.stringify(data);
}
Wenn die payment_basic.html
entsprechend definiert wurde, kann unter der URL localhost:8080
die Seite idealerweise im Browser Google Chrome aufgerufen werden.
Hier der komplette Inhalt nochmal:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>W3C Payment Request API Tutorial</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
margin: 0;
}
html {
font-family: sans-serif;
line-height: 1.4;
padding: 2em;
}
body > :not(:first-child) {
margin-top: 1.5em;
}
h1,
h2 {
line-height: 1.15;
}
.produkt {
max-width: 13em;
padding: 1em;
background: #fff;
}
.produkt> :not(:first-child) {
margin-top: 0.85em;
}
.produkt_bought {
padding: 1em;
background: #fff;
}
.data_list {
max-width: 100%;
}
.produkt_bought> :not(:first-child) {
margin-top: 0.85em;
}
.produkt_bought {
display: none;
}
.produkt_shadow {
position: relative;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
.produkt_shadow:after {
content: "";
position: absolute;
z-index: -1;
-webkit-box-shadow: 0 0 40px rgba(0, 0, 0, 0.8);
box-shadow: 0 0 40px rgba(0, 0, 0, 0.8);
bottom: 0px;
left: 10%;
right: 10%;
width: 80%;
height: 50%;
-moz-border-radius: 100%;
border-radius: 100%;
}
.produkt_meta {
display: flex;
align-items: center;
justify-content: space-between;
}
.produkt_button {
background-color: #008CBA;
color: #fff;
padding: 0.25em 1em;
text-decoration: none;
}
ul.nav {
margin:0;
padding:0;
list-style:none;
height:36px;
margin-top:20px;
font-family:Arial, Helvetica, sans-serif;
font-size:13px;
}
ul.nav li {
float:left;
}
ul.nav a {
display:block;
padding:0 28px;
color:#000;
text-decoration:none;
}
</style>
</head>
<body>
<h1>W3C Payment Request API Tutorial</h1>
<ul class="nav">
<li><a href="/">1. Basic</a></li>
<li><a href="/2">2. shippingAddress</a></li>
<li><a href="/3">3. Sale</a></li>
<li><a href="/4">4. reject Creditcards</a></li>
<li><a href="/5">5. Tax</a></li>
<li><a href="/6">6. reject shippingAddress</a></li>
</ul>
<p> Teil 1: Einfacher Payment Request </p>
<div class="produkt produkt_shadow" id="produkt">
<h2>Beispielprodukt</h2>
<p>Ich bin ein ganz tolles Produkt! Kauf mich!</p>
<div class="produkt_meta">
<strong class="produkt_preis">nur 49.99 €</strong>
<a href="#" id="produkt_button" class="produkt_button">Kaufen</a>
</div>
</div>
<div class="produkt_bought" id="produkt_bought">
<h2>Beispielprodukt gekauft!</h2>
<p>Sie haben das Beispielprodukt erfolgreich für 49,99 € gekauft.</p>
<p>Ihre Daten:</p>
<div id="data_list"></div>
</div>
<script>
function handleProduktClick(e) {
e.preventDefault();
var creditCardPaymentMethod = {
supportedMethods: 'basic-card',
};
var supportedPaymentMethods = [creditCardPaymentMethod];
var paymentDetails = {
total: {
label: 'Beispielprodukt',
amount: {
currency: 'EUR',
value: '49.99'
}
}
};
var paymentRequest = new PaymentRequest(supportedPaymentMethods, paymentDetails);
paymentRequest
.show()
.then(paymentResponse => {
return verifyPaymentWithBackend(paymentResponse).then((success) => {
if (success) {
showPaymentResponse(JSON.parse(success));
return paymentResponse.complete('success');
} else {
return paymentResponse.complete('fail');
}
});
})
.catch(err => {
console.log('Error:', err);
});
};
function showPaymentResponse(data) {
document.getElementById("produkt_button").innerHTML = 'Gekauft';
document.getElementById("produkt_button").style.backgroundColor = "#4CAF50";
document.getElementById("produkt_button").removeEventListener('click', handleProduktClick);
document.getElementById("produkt_bought").style.display = "block";
document.getElementById("data_list").innerHTML = JSON.stringify(data);
}
function verifyPaymentWithBackend(data) {
return new Promise((resolve, reject) => {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function() {
if (xmlhttp.status == 201) {
resolve(xmlhttp.responseText);
} else {
resolve(false)
}
};
xmlhttp.open("POST", "/payment");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify(data));
});
}
document.getElementById("produkt_button").addEventListener('click', handleProduktClick)
</script>
</body>
</html>