@code-collective/booking-widget 1.0.15 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +20 -12
- package/dist/booking-widget.js +179 -185
- package/dist/booking-widget.min.js +6 -6
- package/dist/booking-widget.umd.cjs +2 -2
- package/package.json +1 -1
- package/src/lib/CheckoutModal.svelte +4 -1
- package/src/lib/CheckoutPanel.svelte +22 -1
- package/src/lib/PaymentPage.svelte +13 -3
- package/src/lib/api.ts +1 -28
- package/src/lib/checkout-payment-flow.svelte.ts +101 -105
- package/src/lib/generated-types.ts +0 -82
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,44 @@ The version in `package.json` had drifted behind npm (the repo said 1.0.7 while
|
|
|
4
4
|
1.0.8 and 1.0.9 shipped without an entry here. This file starts at the point that caused a consumer a real
|
|
5
5
|
detour.
|
|
6
6
|
|
|
7
|
+
## 1.0.16
|
|
8
|
+
|
|
9
|
+
Peach now owns payment retries. A declined card never reaches the widget or the checkout API at all - Peach
|
|
10
|
+
re-prompts inside its own embedded form and the shopper returns only once they have paid or given up - so the
|
|
11
|
+
widget no longer reports declines, no longer asks the server to go and read Peach's status, and no longer
|
|
12
|
+
renders a decline screen of its own.
|
|
13
|
+
|
|
14
|
+
- **Removed** `reportPaymentFailure()` and `resolvePayment()` from `BookingApi`/`ApiClient`. The endpoints
|
|
15
|
+
behind them (`POST /v1/checkout/cart/payment-failure`, `POST /v1/checkout/cart/resolve-payment`) are gone
|
|
16
|
+
from the checkout API. Anything calling them directly must drop the call; there is nothing to replace it
|
|
17
|
+
with, because there is no longer a client-reported outcome for the server to record.
|
|
18
|
+
- **Changed** the cart status response is now `{ cartStatus, confirmResult }`. `paymentOutcome`, `resolvedBy`
|
|
19
|
+
and `resultCode` are gone - the browser reads the cart's own status and nothing else.
|
|
20
|
+
- **Changed** a Peach SDK `error` or `expired` callback now releases the checkout through
|
|
21
|
+
`abandonPayment()`, the same call a cancel already used, so Try Again always mints a brand-new Peach
|
|
22
|
+
checkout rather than reopening one Peach has finished with.
|
|
23
|
+
- **Fixed** a cart the server's stuck-payment sweep expired is terminal in the widget. It used to keep
|
|
24
|
+
polling a cart that could never change until the poll's own 90s window ran out, and a reload landed the
|
|
25
|
+
shopper back on a card form for a cart that no longer existed.
|
|
26
|
+
- **Fixed** a card Peach ultimately declined used to leave the shopper on the verifying spinner for its full
|
|
27
|
+
90 seconds and then on the pending screen, never offered Try Again, for a cart that could never change.
|
|
28
|
+
Peach fires its completed callback for a rejected transaction as well as a charged one; the widget now reads
|
|
29
|
+
the result code it carries and resolves straight to Payment Failed with Try Again. It deliberately does not
|
|
30
|
+
ask the server: Peach's checkout-level status answers "transaction pending" for a rejected transaction, so
|
|
31
|
+
it is only good for confirming a success. A code the widget cannot read is still treated as a possible
|
|
32
|
+
charge and polled, since showing "Payment Failed" over a charged card is the worse error.
|
|
33
|
+
- **Changed** Pay Now is accepted on a cart still awaiting confirmation, minting a new checkout over the dead
|
|
34
|
+
one. Nothing about the cart changes - that is what makes Try Again work after a decline. The new checkout
|
|
35
|
+
reuses the cart's merchant order ID, so Peach's dashboard still shows one order per basket however many
|
|
36
|
+
times the shopper retried; editing the basket is what mints a new order ID.
|
|
37
|
+
- **Unchanged** every export, custom-element attribute, `bwOptions` key and `bw:*` event name.
|
|
38
|
+
|
|
39
|
+
## 1.0.13, 1.0.14, 1.0.15
|
|
40
|
+
|
|
41
|
+
Published without entries here. 1.0.13 and 1.0.14 carried a CSS regression - the checkout modal's own styles
|
|
42
|
+
(cart card, pay bar, buttons) were silently missing from the built widget after a CSS split - and **1.0.15
|
|
43
|
+
fixes it**. Anyone pinned to 1.0.13 or 1.0.14 should upgrade.
|
|
44
|
+
|
|
7
45
|
## 1.0.12
|
|
8
46
|
|
|
9
47
|
Published from the branch that carries this work, which 1.0.10 was not. 1.0.11 was prepared but never
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Drop in a script tag and use the custom elements directly. No framework or npm i
|
|
|
9
9
|
```html
|
|
10
10
|
<head>
|
|
11
11
|
<link rel="stylesheet"
|
|
12
|
-
href="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.
|
|
12
|
+
href="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.15/dist/booking-widget.min.css"
|
|
13
13
|
integrity="sha384-LDthHLROtZeufKbWmAhXBsAFLqqhkZjWFd8gWU+Ez11qyg5ebj9vpFnvJuZcM3ft"
|
|
14
14
|
crossorigin="anonymous" />
|
|
15
15
|
</head>
|
|
@@ -20,14 +20,16 @@ Drop in a script tag and use the custom elements directly. No framework or npm i
|
|
|
20
20
|
<bw-checkout></bw-checkout>
|
|
21
21
|
|
|
22
22
|
<script
|
|
23
|
-
src="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.
|
|
24
|
-
integrity="sha384-
|
|
23
|
+
src="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.15/dist/booking-widget.min.js"
|
|
24
|
+
integrity="sha384-vbNVEDGKWm6wwoq+w8uD3mH8eye+XceceTkCL9vW6qd4YTK6WNqKK0Y0e7YiC541"
|
|
25
25
|
crossorigin="anonymous"></script>
|
|
26
26
|
</body>
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
> **Note:** Pin to a specific version (e.g. `@1.0.0`) when using SRI. The hashes change with every release. Run `npm run build:elements` to see the current hashes.
|
|
30
30
|
|
|
31
|
+
> **1.0.15** fixes a CSS regression from 1.0.13/1.0.14 where the checkout modal's own styles (cart card, pay bar, buttons) were silently missing from the built widget - anyone pinned to an affected version should upgrade.
|
|
32
|
+
|
|
31
33
|
The script auto-wires the elements together:
|
|
32
34
|
- Adding an item shows the cart and opens the checkout overlay
|
|
33
35
|
- Clicking checkout in the cart opens the overlay
|
|
@@ -76,8 +78,8 @@ Set `window.bwOptions` before the widget script loads:
|
|
|
76
78
|
editPages: '',
|
|
77
79
|
};
|
|
78
80
|
</script>
|
|
79
|
-
<script src="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.
|
|
80
|
-
integrity="sha384-
|
|
81
|
+
<script src="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.15/dist/booking-widget.min.js"
|
|
82
|
+
integrity="sha384-vbNVEDGKWm6wwoq+w8uD3mH8eye+XceceTkCL9vW6qd4YTK6WNqKK0Y0e7YiC541"
|
|
81
83
|
crossorigin="anonymous"></script>
|
|
82
84
|
```
|
|
83
85
|
|
|
@@ -111,13 +113,19 @@ window.addEventListener('bw:order-confirmed', (e) => {
|
|
|
111
113
|
|
|
112
114
|
### Payment outcomes
|
|
113
115
|
|
|
114
|
-
Peach's own charge and this gateway's confirmation of it are two separate steps - the charge succeeds immediately, but confirmation depends on a webhook that can lag by a few seconds. Confirmation is entirely server-driven: the widget never confirms a cart itself, it only polls the checkout API's status endpoint and renders whatever it reports.
|
|
116
|
+
Peach's own charge and this gateway's confirmation of it are two separate steps - the charge succeeds immediately, but confirmation depends on a webhook that can lag by a few seconds. Confirmation is entirely server-driven: the widget never confirms a cart itself, it only polls the checkout API's status endpoint and renders whatever it reports. A shopper who closes the tab mid-payment is still resolved correctly - nothing depends on their browser staying open.
|
|
117
|
+
|
|
118
|
+
**Peach owns the retries.** While it still has attempts left it re-prompts inside its own embedded form and shows its own error screen - its UI even counts them down ("4 of 5 card attempts remaining") - and the widget shows nothing over it. There is no retry counter of ours and no decline screen while that is happening.
|
|
119
|
+
|
|
120
|
+
When Peach finally hands back without a charge, the widget resolves immediately to Payment Failed with a Try Again button. It does not ask the checkout API what happened: Peach's checkout-level status endpoint answers "transaction pending" for a checkout whose transaction was rejected, so it is only good for confirming a success. Try Again returns to the contact form, and the next Pay Now mints a brand-new Peach checkout over the dead one - the cart itself is never moved. A new *checkout* is unavoidable (Peach's SDK will not re-render one it has unmounted), but the **merchant order ID is reused**, so every attempt at one basket stays searchable as a single order in Peach's dashboard. Changing the basket is what earns a new order ID, since Peach freezes a checkout's amount at creation.
|
|
121
|
+
|
|
122
|
+
The checkout modal reflects the outcome as distinct result screens, and stays open until the shopper dismisses it themselves (Done/Close) rather than closing automatically:
|
|
115
123
|
|
|
116
124
|
| Outcome | Shown when | Shopper can retry payment? |
|
|
117
125
|
|---|---|---|
|
|
118
126
|
| Payment Successful | Charge succeeded and confirmed | -- |
|
|
119
|
-
| Still Checking Your Payment (pending) | No final answer
|
|
120
|
-
| Payment Failed (not charged) | Peach
|
|
127
|
+
| Still Checking Your Payment (pending) | No final answer within the poll's window - typically a charge whose webhook is slow | No - a "Check Again" button re-checks on demand instead |
|
|
128
|
+
| Payment Failed (not charged) | Peach handed back without a charge - a rejected transaction once its own retries were exhausted, an expired or errored checkout, or the shopper backing out; or a server-side sweep released a cart nobody came back to | Yes - nothing was charged, and Try Again mints a brand-new Peach checkout |
|
|
121
129
|
| Booking Incomplete (partial) | Charge succeeded but some cart items didn't confirm | No - the charge already happened; the shopper is told to contact support instead |
|
|
122
130
|
|
|
123
131
|
`bw:order-confirmed` only fires for the first outcome. A shopper who dismisses the "pending" screen before it resolves gets no order-confirmed event even though the payment may still confirm moments later via the webhook - build any "wait for confirmation" UI around the event, not around the modal closing.
|
|
@@ -126,7 +134,7 @@ Peach's own charge and this gateway's confirmation of it are two separate steps
|
|
|
126
134
|
|
|
127
135
|
A cart is created with a 15-minute idle window and a hard ceiling of 35 minutes from creation. Every action on the cart - adding an item, editing one, starting payment, reopening an abandoned payment attempt, and answering the "Are you still there?" prompt - resets the idle window to a full 15 minutes from that moment, but never past the ceiling. `cart.idleExpiresAt` is therefore always the cart's real deadline, and `cart.absoluteExpiresAt` is the ceiling it can never move beyond. If a supplier hold behind one of the items cannot be extended, the cart's deadline is left where it was, so the cart never outlives the holds it fronts.
|
|
128
136
|
|
|
129
|
-
At two minutes remaining, an "Are you still there?" prompt appears. Unlike the rest of the widget's UI it is page-wide: it renders above whatever the shopper is looking at, whether or not a `<bw-checkout>` is even open, since a merchant might embed only `<bw-configurator>`/`<bw-cart>` with no checkout element on the page at all. Answering "Yes, I'm still here" resets the idle window as above and fires `bw:cart-updated` with the extended cart. Once the idle deadline has already reached the ceiling - or an answer came back with the deadline unmoved because a supplier hold could not be extended - the prompt only warns and offers OK: there is no more time to be had. While a payment is in progress the cart is exempt from expiry and cannot be extended (Peach's own session cannot be either), so the prompt does not appear over the card form; if the payment is cancelled or fails and the cart reopens, the countdown resumes from the server's deadline. A page reload during payment is remembered: reopening checkout returns the shopper to the same card form, or offers to start over if Peach no longer accepts it.
|
|
137
|
+
At two minutes remaining, an "Are you still there?" prompt appears. Unlike the rest of the widget's UI it is page-wide: it renders above whatever the shopper is looking at, whether or not a `<bw-checkout>` is even open, since a merchant might embed only `<bw-configurator>`/`<bw-cart>` with no checkout element on the page at all. Answering "Yes, I'm still here" resets the idle window as above and fires `bw:cart-updated` with the extended cart. Once the idle deadline has already reached the ceiling - or an answer came back with the deadline unmoved because a supplier hold could not be extended - the prompt only warns and offers OK: there is no more time to be had. While a payment is in progress the cart is exempt from expiry and cannot be extended (Peach's own session cannot be either), so the prompt does not appear over the card form; if the payment is cancelled or fails and the cart reopens, the countdown resumes from the server's deadline. A cart left sitting on Peach's form past its hard ceiling is released by a server-side sweep, which asks Peach first and never releases one Peach reports as paid; the widget shows that as Payment Failed (not charged). A page reload during payment is remembered: reopening checkout returns the shopper to the same card form, or offers to start over if Peach no longer accepts it.
|
|
130
138
|
|
|
131
139
|
If the deadline passes unanswered, the widget checks with the server and, once the server confirms it has let the cart go, clears it: a "Your cart has expired" message replaces the prompt, `bw:cart-updated` fires with `cart: null`, and there is no way back into the expired cart - only a fresh one. The browser's clock only decides when to ask; a clock running ahead of the server's never throws away a live cart. If you compute your own "time remaining", read it from `cart.idleExpiresAt`.
|
|
132
140
|
|
|
@@ -357,12 +365,12 @@ const product = await getProduct(Astro.params.slug);
|
|
|
357
365
|
<bw-checkout checkout-key={product.checkoutKey}></bw-checkout>
|
|
358
366
|
|
|
359
367
|
<link rel="stylesheet"
|
|
360
|
-
href="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.
|
|
368
|
+
href="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.15/dist/booking-widget.min.css"
|
|
361
369
|
integrity="sha384-LDthHLROtZeufKbWmAhXBsAFLqqhkZjWFd8gWU+Ez11qyg5ebj9vpFnvJuZcM3ft"
|
|
362
370
|
crossorigin="anonymous" />
|
|
363
371
|
<script is:inline
|
|
364
|
-
src="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.
|
|
365
|
-
integrity="sha384-
|
|
372
|
+
src="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@1.0.15/dist/booking-widget.min.js"
|
|
373
|
+
integrity="sha384-vbNVEDGKWm6wwoq+w8uD3mH8eye+XceceTkCL9vW6qd4YTK6WNqKK0Y0e7YiC541"
|
|
366
374
|
crossorigin="anonymous"></script>
|
|
367
375
|
```
|
|
368
376
|
|