Skip to content
Coastal Healthcare Advocates

Module: pay

Behavior for the payment page, pay.html.

The page takes a payment in two steps, both authored in the page:

  1. #pay-form — what the visitor is paying (an invoice by number, a fixed-price service, or another agreed amount), their name and email, and a Cloudflare Turnstile check that appears on their first edit. On submit it POSTs to /.netlify/functions/pay, which looks the amount up in Stripe and answers with a client secret (see netlify/functions/pay.mjs).
  2. #pay-step-payment — Stripe's Payment Element, mounted with that secret and styled from the site's own tokens and fonts, so card, Apple Pay and Google Pay sit inside the page's design. Card details go from the element to Stripe; this script never sees them.

The result ([data-pay-result]) and every error ([data-pay-error]) are authored in the page; this module only reveals the right one (The Three Layers Rule). The two things it writes are data, not copy: the amount and what it's for, returned by the function, and a decline reason from Stripe, each into an authored slot ([data-pay-slot]).

The button in an invoice email opens pay.html?invoice=CHA-1001. When the value looks like an invoice number it is put in the invoice field; the visitor still gives their name and email, and the function still checks the number against that email. The email address is never carried in the URL.

The invoice field carries its CHA- prefix as authored text beside the box, so the visitor types only the digits; wholeInvoiceNumber() puts the prefix back before the request, and takes a whole number pasted in just the same — including an older invoice's own prefix (MGK2PT28-0001), which stands the CHA- aside.

Stripe.js is loaded only when the payment step is reached, from https://js.stripe.com/endive/stripe.js (the release matching the function's Stripe-Version). A payment method that redirects comes back to this page with payment_intent_client_secret in the URL, and the result is read from that.

Source:

Members

(inner, constant) ENDPOINT

The function that prices the payment and returns a client secret.

Source:

(inner, constant) FONT_YSABEAU

The site's fonts, handed to the Payment Element by URL (it renders in Stripe's frame).

Source:

(inner, constant) INVOICE_PREFIX

The prefix every invoice we issue carries (Stripe numbers the account CHA-1001 and up).

Source:

(inner, constant) INVOICE_RE

A whole invoice number: Stripe's PREFIX-0001, the same shape netlify/functions/pay.mjs accepts.

Source:

(inner, constant) STRIPE_SRC

Stripe.js, version-pinned to the API release the function uses.

Source:

(inner, constant) TOKEN_WAIT_MS

How long a submit waits for a Turnstile token before going ahead without one.

Source:

(inner, constant) TURNSTILE_SRC

Cloudflare's Turnstile script, rendered explicitly into our placeholder.

Source:

(inner, constant) form

The form, or null on any other page. @type {HTMLFormElement|null}

Source:

Methods

(inner) appearance() → {Object}

The Payment Element's appearance, built from the site's tokens: the same inks, surface, line, focus ring and 8px field corners as the page's own form.

Source:
Returns:

A Stripe Elements appearance object.

Type
Object

(inner) fonts() → {Array.<Object>}

The fonts the Payment Element may use, as absolute URLs (it renders on Stripe's origin; netlify.toml sends the CORS header that allows this).

Source:
Returns:

Stripe Elements font sources.

Type
Array.<Object>

(inner) initPay(formEl) → {void}

Sets up the payment page.

Parameters:
Name Type Description
formEl HTMLFormElement

The [data-pay-form] form.

Source:
Returns:
Type
void

(inner) loadScript(src) → {Promise.<void>}

Loads a classic script once and resolves when it has run.

Parameters:
Name Type Description
src string

The script URL.

Source:
Returns:

Resolves on load, rejects on error.

Type
Promise.<void>

(inner) money(cents, currency) → {string}

Formats an amount in the smallest currency unit, for the summary slot.

Parameters:
Name Type Description
cents number

The amount, for example 22500.

currency string

The ISO currency, for example 'usd'.

Source:
Returns:

For example $225.00.

Type
string

(inner) token(name) → {string}

Reads a CSS custom property from <html>, so the Payment Element follows the theme the page is showing.

Parameters:
Name Type Description
name string

The property, for example '--ink'.

Source:
Returns:

Its computed value, trimmed.

Type
string

(inner) wholeInvoiceNumber(raw) → {string}

Turns what's in the invoice field into a whole invoice number.

The field shows CHA- beside it and asks for the digits alone, but a visitor who pastes the number from their email gets the same answer, with or without the dash, and an older invoice's own prefix is kept rather than replaced.

Parameters:
Name Type Description
raw string

The field's value as typed or pasted.

Source:
Returns:

The whole number in upper case, or the value unchanged when it isn't a number at all (the caller's test then fails it).

Type
string