diff --git a/paymentrequest/index.d.ts b/paymentrequest/index.d.ts new file mode 100644 index 0000000000..50ef94e1e6 --- /dev/null +++ b/paymentrequest/index.d.ts @@ -0,0 +1,93 @@ +// Type definitions for PaymentRequest +// Project: https://www.w3.org/TR/payment-request/ +// Definitions by: Adam Cmiel +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +interface PaymentRequest extends EventTarget { + new (methodData: PaymentMethodData[], details: PaymentDetails, options?: PaymentOptions): PaymentRequest; + show(): PromiseLike; + abort(): PromiseLike; + shippingAddress?: PaymentAddress; + shippingOption?: string; + onshippingaddresschange: PaymentUpdateEventListener; + onshippingoptionchange: PaymentUpdateEventListener; +} + +interface PaymentMethodData { + supportedMethods: string[]; + data?: Object; +} + +interface PaymentCurrencyAmount { + currency: string; + value: string; +} + +interface PaymentDetails { + total: PaymentItem; + displayItems?: PaymentItem[]; + shippingOptions?: PaymentShippingOption[]; + modifiers?: PaymentDetailsModifier[]; +} + +interface PaymentDetailsModifier { + supportedMethods: string[]; + total?: PaymentItem; + additionalDisplayItems: PaymentItem[]; +} + +interface PaymentOptions { + requestShipping: boolean; + requestPayerEmail: boolean; + requestPayerPhone: boolean; +} + +interface PaymentItem { + label: string; + amount: PaymentCurrencyAmount +} + +interface PaymentAddress { + country: string; + addressLine: string[]; + region: string; + city: string; + dependentLocality: string; + postalCode: string; + sortingCode: string; + languageCode: string; + organization: string; + recipient: string; + careOf: string; + phone: string; +} + +interface PaymentShippingOption { + id: string; + label: string; + amount: PaymentCurrencyAmount; +} + +interface PaymentResponse { + methodName: string; + details: Object; + shippingAddress?: PaymentAddress; + shippingOption?: string; + payerEmail?: string; + payerPhone?: string; + + complete(result?: '' | 'success' | 'fail'): PromiseLike; +} + +interface PaymentUpdateEventListener extends EventListener { + (evt: PaymentRequestUpdateEvent): void; +} + +interface PaymentRequestUpdateEvent extends Event { + updateWith(d: PromiseLike): void; +} + +interface Window { + PaymentRequest?: PaymentRequest; +} + diff --git a/paymentrequest/paymentrequest-tests.ts b/paymentrequest/paymentrequest-tests.ts new file mode 100644 index 0000000000..2297d30a71 --- /dev/null +++ b/paymentrequest/paymentrequest-tests.ts @@ -0,0 +1,111 @@ +/// + +/// Code examples derived from +/// https://developers.google.com/web/fundamentals/discovery-and-monetization/payment-request/ + +function makeRequest() { + if (!window.PaymentRequest) { + return Promise.reject(new Error("PaymentRequest not available")) + } + + const methodData = [ + { + supportedMethods: ["visa", "mastercard"] + } + ] + + const details: PaymentDetails = { + displayItems: [ + { + label: "Original donation amount", + amount: { currency: "USD", value : "65.00" }, // US$65.00 + }, + { + label: "Friends and family discount", + amount: { currency: "USD", value : "-10.00" }, // -US$10.00 + } + ], + total: { + label: "Total", + amount: { currency: "USD", value : "55.00" }, // US$55.00 + } + } + + const options = { + requestShipping: true, + requestPayerEmail: true, + requestPayerPhone: true + } + + const request = new window.PaymentRequest(methodData, details, options) + request.addEventListener("shippingaddresschange", (e: any) => { + e.updateWith(((details, addr) => { + if (addr.country === 'US') { + var shippingOption = { + id: '', + label: '', + amount: {currency: 'USD', value: '0.00'}, + selected: true + }; + if (addr.region === 'US') { + shippingOption.id = 'us'; + shippingOption.label = 'Standard shipping in US'; + shippingOption.amount.value = '0.00'; + details.total.amount.value = '55.00'; + } else { + shippingOption.id = 'others'; + shippingOption.label = 'International shipping'; + shippingOption.amount.value = '10.00'; + details.total.amount.value = '65.00'; + } + if (details.displayItems.length === 2) { + details.displayItems.splice(1, 0, shippingOption); + } else { + details.displayItems.splice(1, 1, shippingOption); + } + + details.shippingOptions = [shippingOption]; + } else { + details.shippingOptions = []; + } + return Promise.resolve(details); + })(details, request.shippingAddress)); + }) + + return request.show() +} + +async function processPayment(): Promise { + let paymentResponse; + try { + paymentResponse = await makeRequest() + } catch (error) { + location.href = '/checkout'; + return; + } + + var paymentData = { + // payment method string + method: paymentResponse.methodName, + // payment details as you requested + details: paymentResponse.details, + // shipping address information + address: paymentResponse.shippingAddress, + // shipping option + shippingOption: paymentResponse.shippingOption + } + + // make call to backend to process payment data + const ok = await Promise.resolve(true) + + if (ok) { + paymentResponse.complete("success") + } else { + paymentResponse.complete("fail") + } +} + +function onShippingAddressChange(e: any) { +} + +document.querySelector("#pay").addEventListener("click", processPayment) diff --git a/paymentrequest/tsconfig.json b/paymentrequest/tsconfig.json new file mode 100644 index 0000000000..68113a806a --- /dev/null +++ b/paymentrequest/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "noImplicitAny": true, + "strictNullChecks": false, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "paymentrequest-tests.ts" + ] +}