@questps/react-upp-js
v1.3.0
Published
Quest React payment library for UPP
Readme
React Unified Payment Platform (UPP) components
This project contains React components for UPP.
Installation
To install this component run npm i @questps/react-upp-js.
Test cards
The following card numbers are not real, they are testing only. Use these numbers with any CCV and any expiry in the future.
Mastercard approved 5123 4567 8901 2346
Visa approved 4005 5500 0000 0001
Visa declined 4557 0123 4567 8902
Documentation
The payment component can be found at: https://questps.github.io/react-upp-js/ .
Quick example
"use client";
import "@questps/react-upp-js/css/creditCardToken.css";
import { useRef, useState } from "react";
export default function Home() {
const [error, setError] = useState<string>();
const getToken = useRef<CreditCardTokenCallback>();
const submitToken = async () => {
setError(undefined);
const creditCardToken = await getToken.current!();
// Perform the payment
};
return (
<main>
<div>
<CreditCardToken
uppPublicToken="your UPP token"
environment="sandbox"
getToken={i => {
getToken.current = i;
}}
handleInvalid={setError}
handleSubmit={submitToken}
singleUse={true}
autoFocus
/>
</div>
{error && <div style={{ color: "red" }}>{error}</div>}
<div className="actions">
<button type="button" onClick={submitToken}>
Pay
</button>
</div>
</main>
);
}Full example

This code is a complete end to end example - (it contains the server code and the widget). This example can be found in the "/example" folder of this repository.
Create a React application
npx create-next-app exampleChange the file "app/globals.css" to the following:
main { display: flex; flex-direction: column; gap: 1rem; margin: 0 auto; width: 100%; max-width: 500px; text-align: center; } button { background: #007bff; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; } .actions { text-align: center; } .paymentResult { margin: auto 10rem; padding: 2rem; text-align: center; } .paymentResult.approved { border: 1px solid green; } .paymentResult.declined { border: 1px solid red; }Add a new file "app/server.ts" with the following:
"use server"; import { headers } from "next/headers"; const UPP_API_URL = process.env.UPP_API_URL!; const UPP_PRIVATE_TOKEN = process.env.UPP_PRIVATE_TOKEN!; async function uppFetch(url: string, options: RequestInit & { json?: any }) { const newOptions = { ...options }; if (options.json) newOptions.body = JSON.stringify(options.json); const result = await fetch(`${UPP_API_URL}${url}`, { headers: { Authorization: `Bearer ${UPP_PRIVATE_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify(options.json), ...options, }); const body = await result.json(); return { ok: result.ok, body }; } export async function payWithServer(customerToken: string): Promise<any> { const formattedAddress = { firstName: "John", lastName: "Smith", line1: "123 Swanston Street", city: "Melbourne", state: "VIC", postCode: "3000", countryCode: "au", }; // This should be a UUID but to avoid a dependancy in example source we are using random const transactionReference = Math.floor(Math.random() * 1e10).toString(); const authResult = await uppFetch("/v1/transactions", { json: { transactionType: "purchase", amount: 1, currency: "aud", // This assumes a reverse proxy is used to forward the client's IP address clientIpAddress: headers().get("x-forwarded-for"), customerToken, transactionReference, provider: "financialCard", saleType: "website", items: [ { type: "sku", itemReference: "1", name: "Flowers", amount: 1, quantity: 1, }, ], billing: formattedAddress, shipping: { isPickup: false, address: formattedAddress, }, shopper: { firstName: "John", lastName: "Smith", }, }, method: "POST", }); if (authResult.body.approved !== undefined) return authResult.body; const completeResult = await uppFetch(`/v1/transactions/${transactionReference}/complete`, { method: "POST", }); return completeResult.body; }Change the file "app/page.tsx" to the following:
"use client"; import { CreditCardToken, CreditCardTokenCallback } from "@questps/react-upp-js"; import "@questps/react-upp-js/css/creditCardToken.css"; import { useRef, useState } from "react"; import { payWithServer } from "./server"; export default function Home() { const [error, setError] = useState<string>(); const [paymentResult, setPaymentResult] = useState<any>(); const getToken = useRef<CreditCardTokenCallback>(); // This function is called when the user clicks the submit button or presses enter on the credit card token form const submitToken = async () => { setError(undefined); const creditCardToken = await getToken.current!(); setPaymentResult(await payWithServer(creditCardToken)); }; if (paymentResult) { const isApproved = paymentResult.approved === true; return ( <div className={`paymentResult ${isApproved ? "approved" : "declined"}`}> Your transaction was {isApproved ? "APPROVED" : "DECLINED"} </div> ); } return ( <main> <div> <CreditCardToken uppPublicToken={process.env.NEXT_PUBLIC_UPP_TOKEN!} environment="sandbox" getToken={i => { getToken.current = i; }} handleInvalid={setError} handleSubmit={submitToken} singleUse={true} autoFocus /> </div> {error && <div style={{ color: "red" }}>{error}</div>} <div className="actions"> <button type="button" onClick={submitToken}> Pay </button> </div> </main> ); }Create a ".env" file with the following contents (replacing anything between < > symbols)
NEXT_PUBLIC_UPP_TOKEN=<you public token> UPP_API_URL=<the UPP host (either: https://payments.sandbox.upp.qps.io or https://payments.upp.qps.io)> UPP_PRIVATE_TOKEN=<your private token>
