@lockerverse/react 0.2.132 → 0.2.133-dev.1
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/README.md +158 -26
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
# `@lockerverse/react`
|
|
2
2
|
|
|
3
|
-
Tree-shakable React UI for Lockerverse
|
|
3
|
+
Tree-shakable React UI for Lockerverse payments, signup, auctions, and public Events. The Core SDK is installed automatically as a normal package dependency.
|
|
4
|
+
|
|
5
|
+
This README ships with the package and describes that release. For an installed
|
|
6
|
+
project, use its local README, `package.json` exports, and public `.d.ts` files.
|
|
7
|
+
Online examples can describe a newer release. Do not import private `dist`
|
|
8
|
+
modules or copy API details from a different SDK version.
|
|
9
|
+
|
|
10
|
+
## Usage guide
|
|
11
|
+
|
|
12
|
+
- [Install](#install) and [payment quick start](#use)
|
|
13
|
+
- [Configuration and environment](#configuration-and-environment)
|
|
14
|
+
- [Server rendering](#server-rendering) and [resource identity](#resource-identity)
|
|
15
|
+
- [Custom product UI](#custom-product-ui) and [live availability](#live-product-availability)
|
|
16
|
+
- [Donate launcher](#donate-launcher)
|
|
17
|
+
- [Signup](#signup)
|
|
18
|
+
- [Styling](#styling)
|
|
19
|
+
- [Payment outcomes](#payment-outcomes) and [recovery](#payment-recovery)
|
|
20
|
+
- [Auctions](#auctions) and [direct auction pages](#direct-auction-pages)
|
|
21
|
+
- [Public event listings](#public-event-listings)
|
|
22
|
+
|
|
23
|
+
For custom non-React clients, use the README shipped with `@lockerverse/sdk`.
|
|
4
24
|
|
|
5
25
|
## Install
|
|
6
26
|
|
|
@@ -35,8 +55,6 @@ export function Checkout() {
|
|
|
35
55
|
metadata={{ source: "community-site" }}
|
|
36
56
|
onPaymentComplete={(payment: LockerversePaymentCompletion) => {
|
|
37
57
|
console.info("Payment complete", payment.checkoutId);
|
|
38
|
-
console.info("Customer", payment.email);
|
|
39
|
-
console.info("Authoritative items", payment.lineItems);
|
|
40
58
|
}}
|
|
41
59
|
onPaymentUncertain={({ paymentReference, reason }) => {
|
|
42
60
|
console.info("Payment needs status recovery", paymentReference, reason);
|
|
@@ -165,6 +183,38 @@ cadence and configures Stripe Elements for a subscription:
|
|
|
165
183
|
Recurring checkout accepts one fixed Product. It does not accept quantities,
|
|
166
184
|
custom amounts, or multiple Products.
|
|
167
185
|
|
|
186
|
+
### Live product availability
|
|
187
|
+
|
|
188
|
+
Use the live `widget.catalog` for names, prices, and limits. Find the requested
|
|
189
|
+
product by its `listingId` or `slug`; do not keep a separate static price list.
|
|
190
|
+
Amounts are integer cents. Format them with `catalog.payment.currency`, not a
|
|
191
|
+
currency field on the product.
|
|
192
|
+
|
|
193
|
+
Before enabling a new purchase, check the selected product's `minimumQuantity`,
|
|
194
|
+
`maximumQuantity`, and `inventoryQuantity`; nullable limits mean no limit.
|
|
195
|
+
For custom amounts, use `getLockerverseMinimumCustomAmountCents(product)` from
|
|
196
|
+
`@lockerverse/sdk/checkout` to include the SDK minimum and the product minimum.
|
|
197
|
+
Also check:
|
|
198
|
+
|
|
199
|
+
- The matching `catalog.availability.listings` entry: `status`,
|
|
200
|
+
`maxPurchasableQuantity`, and `remainingQuantity`.
|
|
201
|
+
- Each `catalog.availability.sharedLimits` entry whose `listingIds` includes
|
|
202
|
+
the selected product's listing: `status` and `remainingQuantity`. Add the
|
|
203
|
+
quantities of all selected listings in that shared group before checking its
|
|
204
|
+
remaining quantity.
|
|
205
|
+
|
|
206
|
+
A missing listing availability entry means no listing-specific limit was
|
|
207
|
+
reported. Other product and shared limits still apply. These checks help the
|
|
208
|
+
host show an unavailable state; the authoritative quote decides whether the
|
|
209
|
+
selection can be purchased. Show loading, retry, and empty states. Keep an
|
|
210
|
+
unresolved payment available for recovery even if a new purchase is unavailable.
|
|
211
|
+
|
|
212
|
+
If an existing button already selects one product, open its checkout directly.
|
|
213
|
+
Use the donate launcher when the visitor needs a product picker. For a custom
|
|
214
|
+
dialog, use an accessible title, close button, focus handling, and mobile scroll
|
|
215
|
+
area. Keep recovery state in an owner that remains mounted when the dialog
|
|
216
|
+
closes. Closing a dialog does not complete or cancel a payment.
|
|
217
|
+
|
|
168
218
|
## Donate launcher
|
|
169
219
|
|
|
170
220
|
`LockerverseDonateLauncher` turns an existing payment widget into a native
|
|
@@ -238,8 +288,19 @@ export function Signup() {
|
|
|
238
288
|
|
|
239
289
|
Pass `googlePlacesApiKey` to enable US address suggestions when the signup asks for an address. Manual address entry always remains available.
|
|
240
290
|
|
|
241
|
-
|
|
242
|
-
|
|
291
|
+
## Configuration and environment
|
|
292
|
+
|
|
293
|
+
Production is the default. Payment, signup, auction, and Events hooks accept
|
|
294
|
+
`apiBaseUrl` and `environment` together. A custom URL requires an explicit
|
|
295
|
+
environment; `environment: "development"` also requires a URL. Include `/api`
|
|
296
|
+
in the API base URL. Do not infer the environment from the host website's URL.
|
|
297
|
+
Use the public community and resource slugs from the intended integration.
|
|
298
|
+
Signup uses `signupSlug`; payment uses `widgetSlug`.
|
|
299
|
+
|
|
300
|
+
The backend supplies the Stripe publishable key and connected account. Do not
|
|
301
|
+
hard-code either value or pass a secret key. The default Stripe loader handles
|
|
302
|
+
initialization. If a host supplies `stripeLoader={loadStripe}`, preserve all
|
|
303
|
+
loader arguments, including the connected-account options.
|
|
243
304
|
|
|
244
305
|
```tsx
|
|
245
306
|
const widget = useLockerverseWidget({
|
|
@@ -255,6 +316,25 @@ const widget = useLockerverseWidget({
|
|
|
255
316
|
/>
|
|
256
317
|
```
|
|
257
318
|
|
|
319
|
+
## Server rendering
|
|
320
|
+
|
|
321
|
+
Use the host framework's client component or client-only boundary for browser
|
|
322
|
+
payment UI. Keep browser storage access in an effect, not at module scope or
|
|
323
|
+
during server rendering. For TanStack Router, import `ClientOnly` from
|
|
324
|
+
`@tanstack/react-router` and put the component that owns checkout inside it:
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
import { ClientOnly } from "@tanstack/react-router";
|
|
328
|
+
|
|
329
|
+
<ClientOnly fallback={<p>Loading checkout...</p>}>
|
|
330
|
+
<Checkout />
|
|
331
|
+
</ClientOnly>
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
The host supplies this boundary; TanStack Router is not an SDK dependency.
|
|
335
|
+
Wait for saved recovery state to load before mounting payment. Remount the
|
|
336
|
+
recovery owner when its resource or recovery key changes.
|
|
337
|
+
|
|
258
338
|
## Styling
|
|
259
339
|
|
|
260
340
|
Auction checkout, payment, and signup use common email, phone, field-error, and checkbox controls. Payment and signup share the custom-field renderer. Phone fields use the lightweight payment/signup country list, normalization, and Valibot format validation. The shared phone control is imported directly, with no separate phone chunk or metadata library. Each flow keeps its existing field configuration and backend rules.
|
|
@@ -303,31 +383,83 @@ An authoritative `failed` result is retryable and the next submit receives a new
|
|
|
303
383
|
|
|
304
384
|
To abandon a locked attempt and intentionally start a new checkout, the host must remount `LockerversePayment` with a new React `key` after resolving the payment status through its own workflow.
|
|
305
385
|
|
|
306
|
-
|
|
386
|
+
### Payment recovery
|
|
307
387
|
|
|
308
|
-
|
|
309
|
-
|
|
388
|
+
Persist `onPaymentRecoveryChange` synchronously before navigation and pass the
|
|
389
|
+
saved value back through `resumePayment` after a refresh. Do not defer the save
|
|
390
|
+
to an effect. A recovery record has only `paymentReference: string` and
|
|
391
|
+
`connectedAccountId: string | null`; it contains no Stripe secret. Scope its
|
|
392
|
+
storage key to the environment, community, widget, and selection.
|
|
310
393
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const recovery = savedRecovery
|
|
314
|
-
? (JSON.parse(savedRecovery) as LockerversePaymentRecovery)
|
|
315
|
-
: null;
|
|
394
|
+
This hook reads storage after mount, validates the saved record, and keeps an
|
|
395
|
+
in-memory record if storage is unavailable:
|
|
316
396
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
397
|
+
```tsx
|
|
398
|
+
import { useEffect, useState } from "react";
|
|
399
|
+
import type { LockerversePaymentRecovery } from "@lockerverse/react/payment";
|
|
400
|
+
|
|
401
|
+
function usePaymentRecovery(recoveryKey: string) {
|
|
402
|
+
const [recovery, setRecovery] = useState<LockerversePaymentRecovery | null>(null);
|
|
403
|
+
const [loaded, setLoaded] = useState(false);
|
|
404
|
+
|
|
405
|
+
useEffect(() => {
|
|
406
|
+
try {
|
|
407
|
+
const raw = sessionStorage.getItem(recoveryKey);
|
|
408
|
+
const saved: unknown = raw ? JSON.parse(raw) : null;
|
|
409
|
+
if (
|
|
410
|
+
saved !== null && typeof saved === "object" &&
|
|
411
|
+
"paymentReference" in saved && typeof saved.paymentReference === "string" &&
|
|
412
|
+
"connectedAccountId" in saved &&
|
|
413
|
+
(saved.connectedAccountId === null || typeof saved.connectedAccountId === "string")
|
|
414
|
+
) {
|
|
415
|
+
setRecovery({
|
|
416
|
+
paymentReference: saved.paymentReference,
|
|
417
|
+
connectedAccountId: saved.connectedAccountId,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
} catch {
|
|
421
|
+
// Invalid or unavailable storage must not break checkout.
|
|
325
422
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
423
|
+
setLoaded(true);
|
|
424
|
+
}, [recoveryKey]);
|
|
425
|
+
|
|
426
|
+
function saveRecovery(next: LockerversePaymentRecovery | null) {
|
|
427
|
+
setRecovery(next);
|
|
428
|
+
try {
|
|
429
|
+
if (next) sessionStorage.setItem(recoveryKey, JSON.stringify(next));
|
|
430
|
+
else sessionStorage.removeItem(recoveryKey);
|
|
431
|
+
} catch {
|
|
432
|
+
// Keep the in-memory record if storage is unavailable.
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return { loaded, recovery, saveRecovery };
|
|
437
|
+
}
|
|
329
438
|
```
|
|
330
439
|
|
|
440
|
+
Use it in the payment owner, keyed by the recovery key. Render checkout only
|
|
441
|
+
after `loaded` is true:
|
|
442
|
+
|
|
443
|
+
```tsx
|
|
444
|
+
const { loaded, recovery, saveRecovery } = usePaymentRecovery(recoveryKey);
|
|
445
|
+
|
|
446
|
+
return loaded ? (
|
|
447
|
+
<LockerversePayment
|
|
448
|
+
selection={selection}
|
|
449
|
+
resumePayment={recovery}
|
|
450
|
+
onPaymentRecoveryChange={saveRecovery}
|
|
451
|
+
widget={widget}
|
|
452
|
+
/>
|
|
453
|
+
) : <p>Loading checkout...</p>;
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Retain the record on `onPaymentUncertain` and let the component recover the
|
|
457
|
+
same payment. Do not create a replacement charge for an unknown result.
|
|
458
|
+
`onPaymentComplete` confirms success; its `paymentRequired` distinguishes a
|
|
459
|
+
paid purchase from a no-charge order. This browser callback does not grant paid
|
|
460
|
+
access; access checks require server verification. Keep private contact and
|
|
461
|
+
payment data out of URLs, analytics, logs, and public metadata.
|
|
462
|
+
|
|
331
463
|
Malformed host selections and invalid custom tips render customer-safe validation messages and do not call the Lockerverse API. Product selection remains owned by the host application.
|
|
332
464
|
|
|
333
465
|
## Auctions
|
|
@@ -389,8 +521,8 @@ export function AuctionPage() {
|
|
|
389
521
|
}
|
|
390
522
|
```
|
|
391
523
|
|
|
392
|
-
Production is the default.
|
|
393
|
-
|
|
524
|
+
Production is the default. For development, set both `apiBaseUrl` and
|
|
525
|
+
`environment: "development"` as shown in [configuration](#configuration-and-environment). Auction data supplies the
|
|
394
526
|
publishable key and connected account for Stripe initialization. The backend
|
|
395
527
|
must include the auction `payment` configuration to use built-in checkout.
|
|
396
528
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lockerverse/react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.133-dev.1",
|
|
4
4
|
"description": "Tree-shakable React payment and signup UI for Lockerverse",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
"embla-carousel-react": "8.6.0",
|
|
128
128
|
"lucide-react": "0.536.0",
|
|
129
129
|
"valibot": "1.4.2",
|
|
130
|
-
"@lockerverse/sdk": "0.2.
|
|
130
|
+
"@lockerverse/sdk": "0.2.133-dev.1"
|
|
131
131
|
},
|
|
132
132
|
"devDependencies": {
|
|
133
133
|
"@size-limit/file": "13.0.3",
|