@owlmeans/web-payment 0.1.18-rc.10 → 0.1.18-rc.11
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 +30 -1
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/web-payment/SKILL.md +88 -13
- package/build/@/components/ui/card.d.ts +10 -0
- package/build/@/components/ui/card.d.ts.map +1 -0
- package/build/@/components/ui/card.js +25 -0
- package/build/@/components/ui/card.js.map +1 -0
- package/build/@/components/ui/progress.d.ts +5 -0
- package/build/@/components/ui/progress.d.ts.map +1 -0
- package/build/@/components/ui/progress.js +11 -0
- package/build/@/components/ui/progress.js.map +1 -0
- package/build/capability-list.d.ts +7 -0
- package/build/capability-list.d.ts.map +1 -0
- package/build/capability-list.js +24 -0
- package/build/capability-list.js.map +1 -0
- package/build/copy.d.ts +14 -0
- package/build/copy.d.ts.map +1 -0
- package/build/copy.js +51 -0
- package/build/copy.js.map +1 -0
- package/build/entitlement.d.ts +26 -0
- package/build/entitlement.d.ts.map +1 -0
- package/build/entitlement.js +42 -0
- package/build/entitlement.js.map +1 -0
- package/build/hooks.d.ts +0 -4
- package/build/hooks.d.ts.map +1 -1
- package/build/hooks.js +3 -30
- package/build/hooks.js.map +1 -1
- package/build/i18n/be.json +1 -1
- package/build/i18n/de.json +1 -1
- package/build/i18n/en.json +1 -1
- package/build/i18n/es.json +1 -1
- package/build/i18n/pl.json +1 -1
- package/build/i18n/ru.json +1 -1
- package/build/i18n/uk.json +1 -1
- package/build/index.d.ts +5 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +5 -0
- package/build/index.js.map +1 -1
- package/build/limit-meter.d.ts +7 -0
- package/build/limit-meter.d.ts.map +1 -0
- package/build/limit-meter.js +26 -0
- package/build/limit-meter.js.map +1 -0
- package/build/plan-card.d.ts +7 -0
- package/build/plan-card.d.ts.map +1 -0
- package/build/plan-card.js +29 -0
- package/build/plan-card.js.map +1 -0
- package/build/poll.d.ts +7 -0
- package/build/poll.d.ts.map +1 -0
- package/build/poll.js +28 -0
- package/build/poll.js.map +1 -0
- package/build/selectors.d.ts +18 -0
- package/build/selectors.d.ts.map +1 -0
- package/build/selectors.js +78 -0
- package/build/selectors.js.map +1 -0
- package/build/types.d.ts +75 -1
- package/build/types.d.ts.map +1 -1
- package/package.json +9 -7
- package/src/@/components/ui/card.tsx +93 -0
- package/src/@/components/ui/progress.tsx +44 -0
- package/src/@/globals.css +10 -0
- package/src/capability-list.tsx +50 -0
- package/src/copy.tsx +62 -0
- package/src/entitlement.ts +56 -0
- package/src/hooks.ts +3 -35
- package/src/i18n/be.json +1 -1
- package/src/i18n/de.json +1 -1
- package/src/i18n/en.json +1 -1
- package/src/i18n/es.json +1 -1
- package/src/i18n/pl.json +1 -1
- package/src/i18n/ru.json +1 -1
- package/src/i18n/uk.json +1 -1
- package/src/index.ts +5 -0
- package/src/limit-meter.tsx +55 -0
- package/src/plan-card.tsx +67 -0
- package/src/poll.ts +27 -0
- package/src/selectors.ts +93 -0
- package/src/types.ts +92 -1
- package/tests/context.ts +8 -0
- package/tests/entitlement.spec.ts +117 -0
- package/tests/harness/entitlement.tsx +120 -0
- package/tests/harness/mount.tsx +9 -3
- package/tests/i18n.spec.ts +40 -6
- package/tests/pieces.spec.ts +112 -0
package/README.md
CHANGED
|
@@ -28,6 +28,35 @@ Checkout redirects the current window by default; pass `useCheckout('_blank')` o
|
|
|
28
28
|
is intentional. The dialog uses the consumer's `@/components/ui/*` primitives, semantic theme
|
|
29
29
|
tokens, integer minor units, and the packaged seven-language `web-payment` resource.
|
|
30
30
|
|
|
31
|
+
## Entitlements
|
|
32
|
+
|
|
33
|
+
`useEntitlementView(ctx.entrypoint(account.entitlements))` polls a served `EntitlementView` and
|
|
34
|
+
revives its ISO dates; `null` means "not known yet", so render paid controls disabled until it
|
|
35
|
+
answers. Read it with `useCapability(view, param)` (`boolean | null`) and `useLimit(view, key)`
|
|
36
|
+
(the limit row plus `exhausted` and a `ratio` clamped to `[0, 1]`). An application that keeps the
|
|
37
|
+
view in its own store uses the pure selectors instead — `capabilityStateOf`, `limitStatusOf`,
|
|
38
|
+
`planStatusLineOf`, `promoInscriptionOf` — and never polls a second time.
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
const view = useEntitlementView(ctx.entrypoint(account.entitlements))
|
|
42
|
+
const seats = useLimit(view, 'seats')
|
|
43
|
+
const { portal, pending } = usePortal(PortalFlow.Change)
|
|
44
|
+
|
|
45
|
+
{view != null && <>
|
|
46
|
+
<PlanCard plan={view.plan} offer={{ sku: 'pro-monthly', title: 'Pro', priceLabel: '$20 / month' }}
|
|
47
|
+
actionLabel="Change plan" pending={pending}
|
|
48
|
+
onAction={planSku => portal(ctx.entrypoint(account.portal), { body: { planSku } })} />
|
|
49
|
+
{seats != null && <LimitMeter limit={seats} label="Seats" />}
|
|
50
|
+
<CapabilityList capabilities={view.capabilities} labels={{ 'feature:whitelabel': 'White label' }} />
|
|
51
|
+
</>}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`usePortal(flow)` sets `body.flow` on a protocol whose body is a `PortalLinkBody` and sends the
|
|
55
|
+
browser to the returned URL. The pieces take data and callbacks only: titles, prices, labels and
|
|
56
|
+
action copy come from the application; status lines, "N of M", reset dates and promo inscriptions
|
|
57
|
+
come from the packaged `entitlement` strings. They import `@/components/ui/{card,progress,button}`,
|
|
58
|
+
so the consumer provides those primitives and `@radix-ui/react-progress`.
|
|
59
|
+
|
|
31
60
|
<!-- owlmeans:agent-guidance:start -->
|
|
32
61
|
## Agent guidance
|
|
33
62
|
|
|
@@ -36,7 +65,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
36
65
|
your project's skill store (`.agents/skills/`):
|
|
37
66
|
|
|
38
67
|
```sh
|
|
39
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
68
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.28
|
|
40
69
|
```
|
|
41
70
|
|
|
42
71
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/web-payment",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "0.1.18-rc.11",
|
|
5
|
+
"generatedAt": "2026-09-16T17:32:31.942Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -7,13 +7,17 @@ user-invocable: false
|
|
|
7
7
|
|
|
8
8
|
# @owlmeans/web-payment
|
|
9
9
|
|
|
10
|
-
**Install:** `bun add @owlmeans/web-payment@^0.1.18-rc.
|
|
10
|
+
**Install:** `bun add @owlmeans/web-payment@^0.1.18-rc.11`
|
|
11
11
|
|
|
12
12
|
Public MIT web package paired with `@owlmeans/server-payment`. It incorporates checkout, balance,
|
|
13
|
-
entitlement and shallow-auth helpers over the underlying `@owlmeans/client-payment` service
|
|
13
|
+
entitlement and shallow-auth helpers over the underlying `@owlmeans/client-payment` service, plus
|
|
14
|
+
presentational pieces over the entitlement view of `@owlmeans/payment` (the model itself is the
|
|
15
|
+
`entitlements` skill).
|
|
16
|
+
|
|
17
|
+
## Protocol-bound hooks
|
|
14
18
|
|
|
15
19
|
Hooks accept `RegisteredEntrypoint<Request, Response>` values. Pass `ctx.entrypoint(protocol)`;
|
|
16
|
-
never weaken a protocol to a home-grown callable type or recover its I/O with a generic.
|
|
20
|
+
never weaken a protocol to a home-grown callable type or recover its I/O with a generic. Call
|
|
17
21
|
arguments use the protocol's `CallArguments`, so a required body cannot be omitted by the hook.
|
|
18
22
|
|
|
19
23
|
```typescript
|
|
@@ -21,10 +25,60 @@ const { checkout, pending } = useCheckout() // same-window by default
|
|
|
21
25
|
await checkout(ctx.entrypoint(account.topUp), { body: { amountMinor } })
|
|
22
26
|
```
|
|
23
27
|
|
|
24
|
-
`useCheckout('_blank')` is the explicit new-tab variant. `openCheckout(url)` defaults to
|
|
25
|
-
`window.location.assign`; both are inert when no DOM exists.
|
|
26
|
-
`
|
|
27
|
-
|
|
28
|
+
- `useCheckout('_blank')` is the explicit new-tab variant. `openCheckout(url)` defaults to
|
|
29
|
+
`window.location.assign`; both are inert when no DOM exists.
|
|
30
|
+
- `usePaymentBalance(entry, intervalMs?, deps?)` polls one protocol and keeps the last good answer;
|
|
31
|
+
a failed poll is swallowed, because explicit actions own their errors.
|
|
32
|
+
|
|
33
|
+
## Entitlement hooks — `null` means unknown
|
|
34
|
+
|
|
35
|
+
| Hook | Answers |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `useEntitlementView(entry, intervalMs = 60_000, deps = [], ...request)` | The polled `EntitlementView`, revived (`reviveEntitlementView`) so every date is a `Date`; `null` until the first answer. Trailing `request` arguments are the protocol's `CallArguments`. |
|
|
38
|
+
| `useCapability(view, param)` | `boolean \| null` — the capability predicate over granted rows; `null` for a null view. |
|
|
39
|
+
| `useLimit(view, key)` | `LimitStatus \| null` — the `LimitView` plus `exhausted` and `ratio`; `null` for a null view or an undeclared key. |
|
|
40
|
+
| `usePortal(flow, target = '_self')` | `{ portal(entry, request?), pending }` — calls a protocol whose body is a `PortalLinkBody` with `body.flow = flow`, then `openCheckout(url, target)`. The caller's arguments omit `flow` (a compile error otherwise); navigation is inert without a DOM. |
|
|
41
|
+
|
|
42
|
+
- **`null` renders paid controls disabled**, never enabled-then-refused. A `false` is an answer;
|
|
43
|
+
`null` is the absence of one.
|
|
44
|
+
- **One poller per view.** An application that keeps the view in its own store (fed once, refreshed
|
|
45
|
+
after the actions that change it) reads it through the pure selectors, not a second
|
|
46
|
+
`useEntitlementView`.
|
|
47
|
+
- Anything read off a view fetched some other way must be revived before a date is used.
|
|
48
|
+
|
|
49
|
+
## Pure selectors
|
|
50
|
+
|
|
51
|
+
| Selector | Returns |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `capabilityStateOf(view, param)` | `boolean \| null` — what `useCapability` memoizes |
|
|
54
|
+
| `limitStatusOf(limitView)` | `LimitStatus \| null` — `exhausted = remaining < 1` (a `limit: 0` row is exhausted); `ratio = used / limit` clamped to `[0, 1]`, and for a `0` ceiling `1` once anything is used, else `0` |
|
|
55
|
+
| `planStatusLineOf(planView)` | `{ kind, tone, date? }` — first match: `created`/`canceled`/`expired`/`ended` (inactive), `blocked` (critical), `paused` (a `pausedAt`, warning), `suspended` (critical), `trial` (`trialEnd`), `past-due` (warning), `cancel-scheduled` (`periodEnd`, warning), `free`, `renews` (`periodEnd`), `active` |
|
|
56
|
+
| `promoInscriptionOf(promoView)` | `'free-until'` (active, not grandfathered) · `'grandfathered'` (active, grandfathered) · `'ended'` (inactive) · `null` |
|
|
57
|
+
|
|
58
|
+
Use these, plus `capabilityOf` / `limitOf` / `hasLimitRoom` from `@owlmeans/payment`, wherever the
|
|
59
|
+
browser decides something; the server gate uses the same predicates, so a disabled button and a
|
|
60
|
+
403 cannot disagree.
|
|
61
|
+
|
|
62
|
+
## Pieces
|
|
63
|
+
|
|
64
|
+
Pieces take data and callbacks only — no protocol calls, no product copy (titles, prices, labels
|
|
65
|
+
and action text come from the application). Every one accepts `className`.
|
|
66
|
+
|
|
67
|
+
| Piece | Props | Renders |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `PlanCard` | `plan: EntitlementPlanView`, `offer?: { sku, title, priceLabel, highlight? }`, `current?`, `pending?`, `actionLabel?`, `onAction?(sku)`, `children?` | Title; the status line (with a tone dot) for the entity's own plan, or for an offer only when it is current; a "Current plan" badge; `priceLabel`; children; one action button (outline when current, disabled while `pending`). `current` defaults to `offer.sku === plan.sku`. |
|
|
70
|
+
| `LimitMeter` | `limit: LimitView`, `label`, `showReset? = true`, `compact?` | `used of limit` (with `unit`), a `Progress` bar, "Limit reached" when exhausted, "Resets on …" for a window limit, the promo inscription. `limit: 0` reads "Not included" and draws no bar. |
|
|
71
|
+
| `CapabilityList` | `capabilities: CapabilityView[]`, `labels: Record<param, string>`, `onlyGranted?` | One row per labelled param in view order (duplicate params collapse, granted wins); unlabelled rows are not rendered; ungranted rows are muted; promo inscription under the label. |
|
|
72
|
+
|
|
73
|
+
- **Stable selectors** for tests and styling: `[data-plan-card]` with `data-plan-sku`,
|
|
74
|
+
`data-plan-status` (the line kind), `data-plan-tone`, `data-current`; `[data-plan-status-line]`,
|
|
75
|
+
`[data-plan-current]`, `[data-plan-price]`; `[data-limit-meter]` with `data-limit-key`,
|
|
76
|
+
`data-limit-kind`, `data-included`, `data-exhausted`, and `[data-limit-usage]`,
|
|
77
|
+
`[data-limit-resets]`, `[data-limit-exhausted]`; `[data-capability-list]`, `[data-capability]`
|
|
78
|
+
with `data-granted`; `[data-promo]` carrying the inscription kind.
|
|
79
|
+
- **Dates render as calendar UTC days** (`dateStyle: 'medium'`) in the current language — the
|
|
80
|
+
calendar limit windows count in, so a reset date names the day the counter rolls.
|
|
81
|
+
- Promo copy: "Free until {{date}}", "Included for your plan", "Promotion ended".
|
|
28
82
|
|
|
29
83
|
## AmountCheckoutDialog
|
|
30
84
|
|
|
@@ -37,14 +91,35 @@ It shows net credit value, processing adjustment and pre-tax subtotal from `char
|
|
|
37
91
|
the note that Stripe calculates applicable tax. The policy maximum bounds net credit, not the
|
|
38
92
|
adjusted or tax-inclusive debit.
|
|
39
93
|
|
|
40
|
-
The
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
94
|
+
## The `@/components/ui/*` contract
|
|
95
|
+
|
|
96
|
+
Components import the consuming app's shadcn primitives through the app alias:
|
|
97
|
+
`@/components/ui/{button,dialog,input,label}` for the dialog and
|
|
98
|
+
`@/components/ui/{card,progress,button}` for the pieces (`Card`, `CardHeader`, `CardTitle`,
|
|
99
|
+
`CardDescription`, `CardContent`, `CardFooter`, `Progress`). The consumer therefore provides those
|
|
100
|
+
files and the peer `@radix-ui/react-progress` beside the dialog's Radix peers. The package carries
|
|
101
|
+
standalone copies under `src/@` only so its own build and tests resolve the same alias; they are
|
|
102
|
+
never exported. Styling uses semantic theme tokens only (`primary`, `muted-foreground`,
|
|
103
|
+
`destructive`, `border`, `card`).
|
|
104
|
+
|
|
105
|
+
A Tailwind v4 consumer scanning package source adds:
|
|
44
106
|
|
|
45
107
|
```css
|
|
46
108
|
@source "../../node_modules/@owlmeans/web-payment/src";
|
|
47
109
|
```
|
|
48
110
|
|
|
49
|
-
|
|
50
|
-
|
|
111
|
+
## Strings
|
|
112
|
+
|
|
113
|
+
All visible strings live in the `web-payment` library resource (`lib` namespace) in all seven
|
|
114
|
+
languages — `en pl ru be uk es de` — under two branches: `amount-checkout` and `entitlement`
|
|
115
|
+
(`plan`, `status`, `limit`, `promo`, `capability`). A new key lands in every language at once, with
|
|
116
|
+
the same `{{placeholders}}`; the parity spec walks the resources recursively. An application
|
|
117
|
+
overrides a string with `addI18nApp(lng, 'web-payment', data, { ns: LIB_NAMESPACE })`.
|
|
118
|
+
|
|
119
|
+
## Tests
|
|
120
|
+
|
|
121
|
+
Category D plus unit specs: `bun test ./tests` runs the selector and hook specs (hooks rendered with
|
|
122
|
+
`react-dom/server`, a fake `window` for navigation) and drives chromium through the Vite harness,
|
|
123
|
+
which picks a surface by `?case=` (none = the dialog, `pieces`, `hook`). The harness pre-bundles
|
|
124
|
+
every runtime dependency in `optimizeDeps.include`; one discovered mid-navigation loads a second
|
|
125
|
+
React and the page throws "Invalid hook call".
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
declare function Card({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
3
|
+
declare function CardHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
4
|
+
declare function CardTitle({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
5
|
+
declare function CardDescription({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
6
|
+
declare function CardAction({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
7
|
+
declare function CardContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
8
|
+
declare function CardFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
9
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent, };
|
|
10
|
+
//# sourceMappingURL=card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../../src/@/components/ui/card.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWjE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQtE;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQ5E;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,GACZ,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '@/lib/utils';
|
|
3
|
+
function Card({ className, ...props }) {
|
|
4
|
+
return (_jsx("div", { "data-slot": "card", className: cn("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", className), ...props }));
|
|
5
|
+
}
|
|
6
|
+
function CardHeader({ className, ...props }) {
|
|
7
|
+
return (_jsx("div", { "data-slot": "card-header", className: cn("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", className), ...props }));
|
|
8
|
+
}
|
|
9
|
+
function CardTitle({ className, ...props }) {
|
|
10
|
+
return (_jsx("div", { "data-slot": "card-title", className: cn("leading-none font-semibold", className), ...props }));
|
|
11
|
+
}
|
|
12
|
+
function CardDescription({ className, ...props }) {
|
|
13
|
+
return (_jsx("div", { "data-slot": "card-description", className: cn("text-muted-foreground text-sm", className), ...props }));
|
|
14
|
+
}
|
|
15
|
+
function CardAction({ className, ...props }) {
|
|
16
|
+
return (_jsx("div", { "data-slot": "card-action", className: cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className), ...props }));
|
|
17
|
+
}
|
|
18
|
+
function CardContent({ className, ...props }) {
|
|
19
|
+
return (_jsx("div", { "data-slot": "card-content", className: cn("px-6", className), ...props }));
|
|
20
|
+
}
|
|
21
|
+
function CardFooter({ className, ...props }) {
|
|
22
|
+
return (_jsx("div", { "data-slot": "card-footer", className: cn("flex items-center px-6 [.border-t]:pt-6", className), ...props }));
|
|
23
|
+
}
|
|
24
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent, };
|
|
25
|
+
//# sourceMappingURL=card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.js","sourceRoot":"","sources":["../../../../src/@/components/ui/card.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAEhC,SAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IAChE,OAAO,CACL,2BACY,MAAM,EAChB,SAAS,EAAE,EAAE,CACX,mFAAmF,EACnF,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACtE,OAAO,CACL,2BACY,aAAa,EACvB,SAAS,EAAE,EAAE,CACX,4JAA4J,EAC5J,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACrE,OAAO,CACL,2BACY,YAAY,EACtB,SAAS,EAAE,EAAE,CAAC,4BAA4B,EAAE,SAAS,CAAC,KAClD,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IAC3E,OAAO,CACL,2BACY,kBAAkB,EAC5B,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,SAAS,CAAC,KACrD,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACtE,OAAO,CACL,2BACY,aAAa,EACvB,SAAS,EAAE,EAAE,CACX,gEAAgE,EAChE,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACvE,OAAO,CACL,2BACY,cAAc,EACxB,SAAS,EAAE,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,KAC5B,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACtE,OAAO,CACL,2BACY,aAAa,EACvB,SAAS,EAAE,EAAE,CAAC,yCAAyC,EAAE,SAAS,CAAC,KAC/D,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,GACZ,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as ProgressPrimitive from '@radix-ui/react-progress';
|
|
3
|
+
declare function Progress({ className, value, ...props }: React.ComponentProps<typeof ProgressPrimitive.Root>): React.JSX.Element;
|
|
4
|
+
export { Progress };
|
|
5
|
+
//# sourceMappingURL=progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../../../src/@/components/ui/progress.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,iBAAiB,MAAM,0BAA0B,CAAA;AAI7D,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,iBAAiB,CAAC,IAAI,CAAC,qBA4BrD;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as ProgressPrimitive from '@radix-ui/react-progress';
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
|
+
function Progress({ className, value, ...props }) {
|
|
5
|
+
const indeterminate = value == null;
|
|
6
|
+
return (_jsx(ProgressPrimitive.Root, { "data-slot": "progress", className: cn("bg-primary/20 relative h-2 w-full overflow-hidden rounded-full", className), value: indeterminate ? undefined : value, ...props, children: _jsx(ProgressPrimitive.Indicator, { "data-slot": "progress-indicator", "data-state": indeterminate ? 'indeterminate' : 'determinate', className: cn("bg-primary h-full w-full flex-1 transition-all", indeterminate && "absolute inset-y-0 left-0 w-1/3 animate-[progress-indeterminate_1.5s_linear_infinite]"), style: indeterminate
|
|
7
|
+
? undefined
|
|
8
|
+
: { transform: `translateX(-${100 - (value || 0)}%)` } }) }));
|
|
9
|
+
}
|
|
10
|
+
export { Progress };
|
|
11
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../../src/@/components/ui/progress.tsx"],"names":[],"mappings":";AAKA,OAAO,KAAK,iBAAiB,MAAM,0BAA0B,CAAA;AAE7D,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAEhC,SAAS,QAAQ,CAAC,EAChB,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EAC4C;IACpD,MAAM,aAAa,GAAG,KAAK,IAAI,IAAI,CAAA;IAEnC,OAAO,CACL,KAAC,iBAAiB,CAAC,IAAI,iBACX,UAAU,EACpB,SAAS,EAAE,EAAE,CACX,gEAAgE,EAChE,SAAS,CACV,EACD,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,KACpC,KAAK,YAET,KAAC,iBAAiB,CAAC,SAAS,iBAChB,oBAAoB,gBAClB,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa,EAC3D,SAAS,EAAE,EAAE,CACX,gDAAgD,EAChD,aAAa,IAAI,uFAAuF,CACzG,EACD,KAAK,EACH,aAAa;gBACX,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,EAAE,SAAS,EAAE,eAAe,GAAG,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,EAAE,GAE1D,GACqB,CAC1B,CAAA;AACH,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CapabilityListProps } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The capabilities of a view, labelled by the application. A capability without a label is not
|
|
4
|
+
* rendered, so a view may carry grants a screen has nothing to say about.
|
|
5
|
+
*/
|
|
6
|
+
export declare const CapabilityList: ({ capabilities, labels, onlyGranted, className }: CapabilityListProps) => import("react").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=capability-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-list.d.ts","sourceRoot":"","sources":["../src/capability-list.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAkBrD;;;GAGG;AACH,eAAO,MAAM,cAAc,qDAA8D,mBAAmB,gCAyB3G,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { PromoNote, useEntitlementCopy } from './copy.js';
|
|
3
|
+
const classes = (...names) => names.filter(Boolean).join(' ');
|
|
4
|
+
/** One row per param, in view order: granted when any row grants it, the promo of that row. */
|
|
5
|
+
const collapse = (capabilities) => {
|
|
6
|
+
const rows = new Map();
|
|
7
|
+
for (const capability of capabilities) {
|
|
8
|
+
const seen = rows.get(capability.param);
|
|
9
|
+
if (seen == null || (!seen.granted && capability.granted)) {
|
|
10
|
+
rows.set(capability.param, capability);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return [...rows.values()];
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The capabilities of a view, labelled by the application. A capability without a label is not
|
|
17
|
+
* rendered, so a view may carry grants a screen has nothing to say about.
|
|
18
|
+
*/
|
|
19
|
+
export const CapabilityList = ({ capabilities, labels, onlyGranted = false, className }) => {
|
|
20
|
+
const copy = useEntitlementCopy();
|
|
21
|
+
const rows = collapse(capabilities).filter(capability => (labels[capability.param] ?? '') !== '' && (!onlyGranted || capability.granted));
|
|
22
|
+
return _jsx("ul", { "data-capability-list": "", className: classes('grid gap-2 text-sm', className), children: rows.map(capability => _jsxs("li", { "data-capability": capability.param, "data-granted": capability.granted ? 'true' : 'false', className: "flex items-start gap-2", children: [_jsx("span", { "aria-hidden": "true", className: classes('mt-0.5 inline-flex size-4 shrink-0 items-center justify-center text-xs font-semibold', capability.granted ? 'text-primary' : 'text-muted-foreground'), children: capability.granted ? '✓' : '–' }), _jsxs("span", { className: "grid gap-0.5", children: [_jsxs("span", { className: capability.granted ? undefined : 'text-muted-foreground', children: [labels[capability.param], _jsx("span", { className: "sr-only", children: ` — ${copy.text(capability.granted ? 'capability.included' : 'capability.not-included')}` })] }), capability.promo != null && _jsx("span", { className: "text-xs", children: _jsx(PromoNote, { promo: capability.promo, copy: copy }) })] })] }, capability.param)) });
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=capability-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-list.js","sourceRoot":"","sources":["../src/capability-list.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAGzD,MAAM,OAAO,GAAG,CAAC,GAAG,KAA+C,EAAU,EAAE,CAC7E,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAEjC,+FAA+F;AAC/F,MAAM,QAAQ,GAAG,CAAC,YAA8B,EAAoB,EAAE;IACpE,MAAM,IAAI,GAAG,IAAI,GAAG,EAA0B,CAAA;IAC9C,KAAK,MAAM,UAAU,IAAI,YAAY,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QACvC,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA;QACxC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;AAC3B,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,EAAuB,EAAE,EAAE;IAC9G,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAA;IACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CACtD,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,WAAW,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC,CAAA;IAElF,OAAO,qCAAyB,EAAE,EAAC,SAAS,EAAE,OAAO,CAAC,oBAAoB,EAAE,SAAS,CAAC,YACnF,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,iCAEL,UAAU,CAAC,KAAK,kBACnB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EACnD,SAAS,EAAC,wBAAwB,aAElC,8BAAkB,MAAM,EAAC,SAAS,EAAE,OAAO,CACzC,sFAAsF,EACtF,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,uBAAuB,CAC9D,YAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAQ,EAC1C,gBAAM,SAAS,EAAC,cAAc,aAC5B,gBAAM,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,uBAAuB,aACtE,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EACzB,eAAM,SAAS,EAAC,SAAS,YAAE,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,yBAAyB,CAAC,EAAE,GAAQ,IACvH,EACN,UAAU,CAAC,KAAK,IAAI,IAAI,IAAI,eAAM,SAAS,EAAC,SAAS,YAAC,KAAC,SAAS,IAAC,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,GAAI,GAAO,IAC3G,KAfF,UAAU,CAAC,KAAK,CAgBlB,CAAC,GACH,CAAA;AACP,CAAC,CAAA"}
|
package/build/copy.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PromoView } from '@owlmeans/payment';
|
|
2
|
+
export interface EntitlementCopy {
|
|
3
|
+
text: (key: string, values?: Record<string, string>) => string;
|
|
4
|
+
day: (date: Date | string | null | undefined) => string;
|
|
5
|
+
count: (value: number) => string;
|
|
6
|
+
}
|
|
7
|
+
/** The `entitlement` branch of the `web-payment` library resource, with locale-aware formatting. */
|
|
8
|
+
export declare const useEntitlementCopy: () => EntitlementCopy;
|
|
9
|
+
/** The inscription of a promo: free until its end, kept for a grandfathered plan, or ended. */
|
|
10
|
+
export declare const PromoNote: ({ promo, copy }: {
|
|
11
|
+
promo?: PromoView;
|
|
12
|
+
copy: EntitlementCopy;
|
|
13
|
+
}) => import("react").JSX.Element | null;
|
|
14
|
+
//# sourceMappingURL=copy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../src/copy.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AA8BlD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAA;IAC9D,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,KAAK,MAAM,CAAA;IACvD,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;CACjC;AAED,oGAAoG;AACpG,eAAO,MAAM,kBAAkB,QAAO,eAUrC,CAAA;AAED,+FAA+F;AAC/F,eAAO,MAAM,SAAS,oBAAqB;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,uCAStF,CAAA"}
|
package/build/copy.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { useI18nLib, useLanguage } from '@owlmeans/client-i18n';
|
|
4
|
+
import { promoInscriptionOf } from './selectors.js';
|
|
5
|
+
/**
|
|
6
|
+
* A calendar date in UTC — the calendar limit windows are counted in, so "resets on" names the day
|
|
7
|
+
* the counter actually rolls. An unparseable date renders as nothing.
|
|
8
|
+
*/
|
|
9
|
+
const formatDay = (date, locale) => {
|
|
10
|
+
if (date == null) {
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
const value = date instanceof Date ? date : new Date(date);
|
|
14
|
+
if (Number.isNaN(value.getTime())) {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
return new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeZone: 'UTC' }).format(value);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return value.toISOString().slice(0, 10);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const formatCount = (value, locale) => {
|
|
25
|
+
try {
|
|
26
|
+
return new Intl.NumberFormat(locale).format(value);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return String(value);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
/** The `entitlement` branch of the `web-payment` library resource, with locale-aware formatting. */
|
|
33
|
+
export const useEntitlementCopy = () => {
|
|
34
|
+
const t = useI18nLib('web-payment', 'entitlement');
|
|
35
|
+
const [locale] = useLanguage();
|
|
36
|
+
return useMemo(() => ({
|
|
37
|
+
// React escapes what it renders; i18next escaping on top would print `/` for a slash.
|
|
38
|
+
text: (key, values) => t(key, { ...values, interpolation: { escapeValue: false } }),
|
|
39
|
+
day: date => formatDay(date, locale),
|
|
40
|
+
count: value => formatCount(value, locale),
|
|
41
|
+
}), [t, locale]);
|
|
42
|
+
};
|
|
43
|
+
/** The inscription of a promo: free until its end, kept for a grandfathered plan, or ended. */
|
|
44
|
+
export const PromoNote = ({ promo, copy }) => {
|
|
45
|
+
const kind = promoInscriptionOf(promo);
|
|
46
|
+
if (kind == null || promo == null) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return _jsx("span", { "data-promo": kind, className: kind === 'ended' ? 'text-muted-foreground' : 'text-primary', children: copy.text(`promo.${kind}`, { date: copy.day(promo.until) }) });
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=copy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy.js","sourceRoot":"","sources":["../src/copy.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAE/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAEnD;;;GAGG;AACH,MAAM,SAAS,GAAG,CAAC,IAAsC,EAAE,MAAc,EAAU,EAAE;IACnF,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;QACjB,OAAO,EAAE,CAAA;IACX,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAA;IAC1D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,CAAA;IACX,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAChG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACzC,CAAC;AACH,CAAC,CAAA;AAED,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,MAAc,EAAU,EAAE;IAC5D,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;AACH,CAAC,CAAA;AAQD,oGAAoG;AACpG,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAoB,EAAE;IACtD,MAAM,CAAC,GAAG,UAAU,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;IAClD,MAAM,CAAC,MAAM,CAAC,GAAG,WAAW,EAAE,CAAA;IAE9B,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACpB,2FAA2F;QAC3F,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,aAAa,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,CAAC;QACnF,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC;QACpC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC;KAC3C,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;AAClB,CAAC,CAAA;AAED,+FAA+F;AAC/F,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAgD,EAAE,EAAE;IACzF,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;IACtC,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,6BAAkB,IAAI,EAAE,SAAS,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,cAAc,YAClG,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GACvD,CAAA;AACT,CAAC,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CallArguments, RegisteredEntrypoint, RequestShape } from '@owlmeans/entrypoint';
|
|
2
|
+
import type { EntitlementView, PortalFlow, PortalLinkResponse } from '@owlmeans/payment';
|
|
3
|
+
import { type CheckoutTarget } from './service.js';
|
|
4
|
+
import type { LimitStatus, PortalArguments, PortalRequest } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Poll an entitlement-view protocol — `null` until the first answer. The view is revived on the way
|
|
7
|
+
* in (the wire carries ISO strings), so every date in it is a `Date`.
|
|
8
|
+
*
|
|
9
|
+
* An application that already keeps the view in its own store reads it through the pure selectors
|
|
10
|
+
* (`capabilityStateOf`, `limitStatusOf`, `planStatusLineOf`) instead of polling a second time.
|
|
11
|
+
*/
|
|
12
|
+
export declare const useEntitlementView: <Request extends RequestShape>(entry: RegisteredEntrypoint<Request, EntitlementView>, intervalMs?: number, deps?: unknown[], ...request: CallArguments<Request>) => EntitlementView | null;
|
|
13
|
+
/** Whether the view grants a capability parameter; `null` while the view is unknown. */
|
|
14
|
+
export declare const useCapability: (view: EntitlementView | null | undefined, param: string) => boolean | null;
|
|
15
|
+
/** One limit of the view with `exhausted` and `ratio`; `null` while unknown or undeclared. */
|
|
16
|
+
export declare const useLimit: (view: EntitlementView | null | undefined, key: string) => LimitStatus | null;
|
|
17
|
+
/**
|
|
18
|
+
* Open a billing-portal flow: `portal(entry, request?)` calls the portal protocol with `body.flow`
|
|
19
|
+
* set to `flow`, then sends the browser to the returned URL (same window by default). Without a DOM
|
|
20
|
+
* the navigation is inert and the response is still returned.
|
|
21
|
+
*/
|
|
22
|
+
export declare const usePortal: (flow: PortalFlow, target?: CheckoutTarget) => {
|
|
23
|
+
portal: <Request extends PortalRequest>(entry: RegisteredEntrypoint<Request, PortalLinkResponse>, ...request: PortalArguments<Request>) => Promise<PortalLinkResponse | null>;
|
|
24
|
+
pending: boolean;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=entitlement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entitlement.d.ts","sourceRoot":"","sources":["../src/entitlement.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAE7F,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAGxF,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE7E;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,SAAS,YAAY,SACtD,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,eACzC,MAAM,SACZ,OAAO,EAAE,cACH,aAAa,CAAC,OAAO,CAAC,KACjC,eAAe,GAAG,IAEpB,CAAA;AAED,wFAAwF;AACxF,eAAO,MAAM,aAAa,SAAU,eAAe,GAAG,IAAI,GAAG,SAAS,SAAS,MAAM,KAAG,OAAO,GAAG,IACpC,CAAA;AAE9D,8FAA8F;AAC9F,eAAO,MAAM,QAAQ,SAAU,eAAe,GAAG,IAAI,GAAG,SAAS,OAAO,MAAM,KAAG,WAAW,GAAG,IAChC,CAAA;AAE/D;;;;GAIG;AACH,eAAO,MAAM,SAAS,SAAU,UAAU,WAAU,cAAc;aAE9B,OAAO,SAAS,aAAa,SACtD,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,CAAC,cAAc,eAAe,CAAC,OAAO,CAAC,KAC7F,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;;CAatC,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
2
|
+
import { limitOf, reviveEntitlementView } from '@owlmeans/payment';
|
|
3
|
+
import { usePolled } from './poll.js';
|
|
4
|
+
import { capabilityStateOf, limitStatusOf } from './selectors.js';
|
|
5
|
+
import { openCheckout } from './service.js';
|
|
6
|
+
/**
|
|
7
|
+
* Poll an entitlement-view protocol — `null` until the first answer. The view is revived on the way
|
|
8
|
+
* in (the wire carries ISO strings), so every date in it is a `Date`.
|
|
9
|
+
*
|
|
10
|
+
* An application that already keeps the view in its own store reads it through the pure selectors
|
|
11
|
+
* (`capabilityStateOf`, `limitStatusOf`, `planStatusLineOf`) instead of polling a second time.
|
|
12
|
+
*/
|
|
13
|
+
export const useEntitlementView = (entry, intervalMs = 60_000, deps = [], ...request) => usePolled(async () => reviveEntitlementView(await entry.call(...request)), intervalMs, deps);
|
|
14
|
+
/** Whether the view grants a capability parameter; `null` while the view is unknown. */
|
|
15
|
+
export const useCapability = (view, param) => useMemo(() => capabilityStateOf(view, param), [view, param]);
|
|
16
|
+
/** One limit of the view with `exhausted` and `ratio`; `null` while unknown or undeclared. */
|
|
17
|
+
export const useLimit = (view, key) => useMemo(() => limitStatusOf(limitOf(view, key)), [view, key]);
|
|
18
|
+
/**
|
|
19
|
+
* Open a billing-portal flow: `portal(entry, request?)` calls the portal protocol with `body.flow`
|
|
20
|
+
* set to `flow`, then sends the browser to the returned URL (same window by default). Without a DOM
|
|
21
|
+
* the navigation is inert and the response is still returned.
|
|
22
|
+
*/
|
|
23
|
+
export const usePortal = (flow, target = '_self') => {
|
|
24
|
+
const [pending, setPending] = useState(false);
|
|
25
|
+
const portal = useCallback(async (entry, ...request) => {
|
|
26
|
+
setPending(true);
|
|
27
|
+
try {
|
|
28
|
+
const [options] = request;
|
|
29
|
+
// The flow completes the body the caller's arguments deliberately leave out.
|
|
30
|
+
const args = [{ ...options, body: { ...options?.body, flow } }];
|
|
31
|
+
const result = await entry.call(...args);
|
|
32
|
+
if (result?.url != null)
|
|
33
|
+
openCheckout(result.url, target);
|
|
34
|
+
return result ?? null;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
setPending(false);
|
|
38
|
+
}
|
|
39
|
+
}, [flow, target]);
|
|
40
|
+
return { portal, pending };
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=entitlement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entitlement.js","sourceRoot":"","sources":["../src/entitlement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEtD,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACjE,OAAO,EAAE,YAAY,EAAuB,MAAM,cAAc,CAAA;AAGhE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAqD,EACrD,UAAU,GAAW,MAAM,EAC3B,IAAI,GAAc,EAAE,EACpB,GAAG,OAA+B,EACV,EAAE,CAAC,SAAS,CACpC,KAAK,IAAI,EAAE,CAAC,qBAAqB,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAClF,CAAA;AAED,wFAAwF;AACxF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAwC,EAAE,KAAa,EAAkB,EAAE,CACvG,OAAO,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;AAE9D,8FAA8F;AAC9F,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAwC,EAAE,GAAW,EAAsB,EAAE,CACpG,OAAO,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;AAE/D;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAgB,EAAE,MAAM,GAAmB,OAAO,EAAE,EAAE;IAC9E,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,EAC9B,KAAwD,EAAE,GAAG,OAAiC,EAC1D,EAAE;QACtC,UAAU,CAAC,IAAI,CAAC,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,CAAC,OAAO,CAAC,GAAG,OAA+B,CAAA;YACjD,6EAA6E;YAC7E,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAsC,CAAA;YACpG,MAAM,MAAM,GAAmC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAA;YACxE,IAAI,MAAM,EAAE,GAAG,IAAI,IAAI;gBAAE,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACzD,OAAO,MAAM,IAAI,IAAI,CAAA;QACvB,CAAC;gBAAS,CAAC;YAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QAAC,CAAC;IACjC,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;IAElB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AAC5B,CAAC,CAAA"}
|
package/build/hooks.d.ts
CHANGED
|
@@ -6,8 +6,4 @@ export declare const useCheckout: (target?: CheckoutTarget) => {
|
|
|
6
6
|
pending: boolean;
|
|
7
7
|
};
|
|
8
8
|
export declare const usePaymentBalance: <T>(entry: RegisteredEntrypoint<{}, T>, intervalMs?: number, deps?: unknown[]) => T | null;
|
|
9
|
-
export declare const useEntitlements: <T extends {
|
|
10
|
-
entitlements?: string[];
|
|
11
|
-
}>(entry: RegisteredEntrypoint<{}, T>, intervalMs?: number, deps?: unknown[]) => string[] | null;
|
|
12
|
-
export declare const useEntitlement: (list: string[] | null, param: string) => boolean;
|
|
13
9
|
//# sourceMappingURL=hooks.d.ts.map
|
package/build/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAE7F,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,eAAO,MAAM,WAAW,YAAY,cAAc;eAEZ,OAAO,SAAS,YAAY,SACvD,oBAAoB,CAAC,OAAO,EAAE,cAAc,CAAC,cAAc,aAAa,CAAC,OAAO,CAAC,KACvF,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;;CASlC,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAC1B,oBAAoB,CAAC,EAAE,EAAE,CAAC,CAAC,eAAc,MAAM,SAAiB,OAAO,EAAE,KAC/E,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAE7F,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,eAAO,MAAM,WAAW,YAAY,cAAc;eAEZ,OAAO,SAAS,YAAY,SACvD,oBAAoB,CAAC,OAAO,EAAE,cAAc,CAAC,cAAc,aAAa,CAAC,OAAO,CAAC,KACvF,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;;CASlC,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAC1B,oBAAoB,CAAC,EAAE,EAAE,CAAC,CAAC,eAAc,MAAM,SAAiB,OAAO,EAAE,KAC/E,CAAC,GAAG,IAAuD,CAAA"}
|
package/build/hooks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useCallback,
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
2
|
+
import { usePolled } from './poll.js';
|
|
3
3
|
import { openCheckout } from './service.js';
|
|
4
4
|
export const useCheckout = (target = '_self') => {
|
|
5
5
|
const [pending, setPending] = useState(false);
|
|
@@ -17,32 +17,5 @@ export const useCheckout = (target = '_self') => {
|
|
|
17
17
|
}, [target]);
|
|
18
18
|
return { checkout, pending };
|
|
19
19
|
};
|
|
20
|
-
export const usePaymentBalance = (entry, intervalMs = 60_000, deps = []) =>
|
|
21
|
-
const [balance, setBalance] = useState(null);
|
|
22
|
-
const entryRef = useRef(entry);
|
|
23
|
-
entryRef.current = entry;
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
let active = true;
|
|
26
|
-
const load = async () => {
|
|
27
|
-
try {
|
|
28
|
-
const value = await entryRef.current.call();
|
|
29
|
-
if (active)
|
|
30
|
-
setBalance(value);
|
|
31
|
-
}
|
|
32
|
-
catch { /* explicit actions own their errors */ }
|
|
33
|
-
};
|
|
34
|
-
void load();
|
|
35
|
-
const ticker = setInterval(load, intervalMs);
|
|
36
|
-
return () => { active = false; clearInterval(ticker); };
|
|
37
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
38
|
-
}, [intervalMs, ...deps]);
|
|
39
|
-
return balance;
|
|
40
|
-
};
|
|
41
|
-
export const useEntitlements = (entry, intervalMs = 60_000, deps = []) => usePaymentBalance(entry, intervalMs, deps)?.entitlements ?? null;
|
|
42
|
-
export const useEntitlement = (list, param) => list != null && hasEntitlement(list.map(item => {
|
|
43
|
-
const colon = item.indexOf(':');
|
|
44
|
-
return colon >= 0
|
|
45
|
-
? { scope: item.slice(0, colon), permissions: { [item.slice(colon + 1)]: true } }
|
|
46
|
-
: { scope: '', permissions: { [item]: true } };
|
|
47
|
-
}), param);
|
|
20
|
+
export const usePaymentBalance = (entry, intervalMs = 60_000, deps = []) => usePolled(() => entry.call(), intervalMs, deps);
|
|
48
21
|
//# sourceMappingURL=hooks.js.map
|
package/build/hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,YAAY,EAAuB,MAAM,cAAc,CAAA;AAGhE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAM,GAAmB,OAAO,EAAE,EAAE;IAC9D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,EAChC,KAAoD,EAAE,GAAG,OAA+B,EACxD,EAAE;QAClC,UAAU,CAAC,IAAI,CAAC,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAA;YAC3C,IAAI,MAAM,EAAE,GAAG,IAAI,IAAI;gBAAE,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACzD,OAAO,MAAM,IAAI,IAAI,CAAA;QACvB,CAAC;gBAAS,CAAC;YAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QAAC,CAAC;IACjC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IACZ,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;AAC9B,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,KAAkC,EAAE,UAAU,GAAW,MAAM,EAAE,IAAI,GAAc,EAAE,EAC3E,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,CAAA"}
|
package/build/i18n/be.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "amount-checkout": { "title": "Папоўніць крэдыты", "description": "Выберыце чысты кошт крэдытаў для арганізацыі.", "presets": "Гатовыя сумы", "custom": "Свая сума", "invalid": "Увядзіце карэктную суму, не больш за два знакі пасля коскі.", "below": "Мінімальная сума — {{amount}}.", "above": "Максімальная сума — {{amount}}.", "bounds": "Выберыце суму ад {{minimum}} да {{maximum}}.", "credits": "Кошт крэдытаў", "adjustment": "Карэкціроўка апрацоўкі", "subtotal": "Сума да падатку", "tax-note": "Stripe разлічыць падатак падчас аплаты.", "cancel": "Скасаваць", "continue": "Перайсці ў Stripe", "pending": "Адкрываем аплату…", "close": "Закрыць" } }
|
|
1
|
+
{ "amount-checkout": { "title": "Папоўніць крэдыты", "description": "Выберыце чысты кошт крэдытаў для арганізацыі.", "presets": "Гатовыя сумы", "custom": "Свая сума", "invalid": "Увядзіце карэктную суму, не больш за два знакі пасля коскі.", "below": "Мінімальная сума — {{amount}}.", "above": "Максімальная сума — {{amount}}.", "bounds": "Выберыце суму ад {{minimum}} да {{maximum}}.", "credits": "Кошт крэдытаў", "adjustment": "Карэкціроўка апрацоўкі", "subtotal": "Сума да падатку", "tax-note": "Stripe разлічыць падатак падчас аплаты.", "cancel": "Скасаваць", "continue": "Перайсці ў Stripe", "pending": "Адкрываем аплату…", "close": "Закрыць" }, "entitlement": { "plan": { "current": "Бягучы план" }, "status": { "trial": "Пробны перыяд", "trial-on": "Пробны перыяд да {{date}}", "past-due": "Плацёж пратэрмінаваны", "cancel-scheduled": "Адмена запланавана", "cancel-scheduled-on": "Адмяняецца {{date}}", "paused": "На паўзе", "paused-on": "На паўзе з {{date}}", "suspended": "Прыпынены", "free": "Бясплатны план", "renews-on": "Падаўжаецца {{date}}", "active": "Актыўны", "created": "Чакае актывацыі", "canceled": "Адменены", "expired": "Тэрмін скончыўся", "ended": "Завершаны", "blocked": "Заблакаваны" }, "limit": { "usage": "{{used}} з {{limit}}", "usage-unit": "{{used}} з {{limit}} {{unit}}", "not-included": "Не ўваходзіць у план", "exhausted": "Ліміт вычарпаны", "resets-on": "Абновіцца {{date}}" }, "promo": { "free-until": "Бясплатна да {{date}}", "grandfathered": "Захавана для вашага плана", "ended": "Акцыя завершана" }, "capability": { "included": "Уваходзіць у план", "not-included": "Не ўваходзіць у план" } } }
|
package/build/i18n/de.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "amount-checkout": { "title": "Guthaben aufladen", "description": "Wähle den Nettowert des Guthabens für deine Organisation.", "presets": "Vorgegebene Beträge", "custom": "Eigener Betrag", "invalid": "Gib einen gültigen Betrag mit höchstens zwei Dezimalstellen ein.", "below": "Der Mindestbetrag ist {{amount}}.", "above": "Der Höchstbetrag ist {{amount}}.", "bounds": "Wähle zwischen {{minimum}} und {{maximum}}.", "credits": "Guthabenwert", "adjustment": "Verarbeitungsaufschlag", "subtotal": "Zwischensumme vor Steuern", "tax-note": "Stripe berechnet anwendbare Steuern beim Bezahlen.", "cancel": "Abbrechen", "continue": "Weiter zu Stripe", "pending": "Zahlung wird geöffnet…", "close": "Schließen" } }
|
|
1
|
+
{ "amount-checkout": { "title": "Guthaben aufladen", "description": "Wähle den Nettowert des Guthabens für deine Organisation.", "presets": "Vorgegebene Beträge", "custom": "Eigener Betrag", "invalid": "Gib einen gültigen Betrag mit höchstens zwei Dezimalstellen ein.", "below": "Der Mindestbetrag ist {{amount}}.", "above": "Der Höchstbetrag ist {{amount}}.", "bounds": "Wähle zwischen {{minimum}} und {{maximum}}.", "credits": "Guthabenwert", "adjustment": "Verarbeitungsaufschlag", "subtotal": "Zwischensumme vor Steuern", "tax-note": "Stripe berechnet anwendbare Steuern beim Bezahlen.", "cancel": "Abbrechen", "continue": "Weiter zu Stripe", "pending": "Zahlung wird geöffnet…", "close": "Schließen" }, "entitlement": { "plan": { "current": "Aktueller Tarif" }, "status": { "trial": "Testphase", "trial-on": "Testphase endet am {{date}}", "past-due": "Zahlung überfällig", "cancel-scheduled": "Kündigung vorgemerkt", "cancel-scheduled-on": "Endet am {{date}}", "paused": "Pausiert", "paused-on": "Pausiert seit {{date}}", "suspended": "Ausgesetzt", "free": "Kostenloser Tarif", "renews-on": "Verlängert sich am {{date}}", "active": "Aktiv", "created": "Wartet auf Aktivierung", "canceled": "Gekündigt", "expired": "Abgelaufen", "ended": "Beendet", "blocked": "Gesperrt" }, "limit": { "usage": "{{used}} von {{limit}}", "usage-unit": "{{used}} von {{limit}} {{unit}}", "not-included": "Nicht enthalten", "exhausted": "Limit erreicht", "resets-on": "Wird am {{date}} zurückgesetzt" }, "promo": { "free-until": "Kostenlos bis {{date}}", "grandfathered": "In deinem Tarif enthalten", "ended": "Aktion beendet" }, "capability": { "included": "Enthalten", "not-included": "Nicht enthalten" } } }
|
package/build/i18n/en.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "amount-checkout": { "title": "Add credits", "description": "Choose the net credit value to add to your organization.", "presets": "Preset amounts", "custom": "Custom amount", "invalid": "Enter a valid amount with no more than two decimal places.", "below": "The minimum amount is {{amount}}.", "above": "The maximum amount is {{amount}}.", "bounds": "Choose between {{minimum}} and {{maximum}}.", "credits": "Credit value", "adjustment": "Processing adjustment", "subtotal": "Pre-tax subtotal", "tax-note": "Stripe calculates any applicable tax at checkout.", "cancel": "Cancel", "continue": "Continue to Stripe", "pending": "Opening checkout…", "close": "Close" } }
|
|
1
|
+
{ "amount-checkout": { "title": "Add credits", "description": "Choose the net credit value to add to your organization.", "presets": "Preset amounts", "custom": "Custom amount", "invalid": "Enter a valid amount with no more than two decimal places.", "below": "The minimum amount is {{amount}}.", "above": "The maximum amount is {{amount}}.", "bounds": "Choose between {{minimum}} and {{maximum}}.", "credits": "Credit value", "adjustment": "Processing adjustment", "subtotal": "Pre-tax subtotal", "tax-note": "Stripe calculates any applicable tax at checkout.", "cancel": "Cancel", "continue": "Continue to Stripe", "pending": "Opening checkout…", "close": "Close" }, "entitlement": { "plan": { "current": "Current plan" }, "status": { "trial": "Trial", "trial-on": "Trial ends on {{date}}", "past-due": "Payment past due", "cancel-scheduled": "Cancellation scheduled", "cancel-scheduled-on": "Cancels on {{date}}", "paused": "Paused", "paused-on": "Paused since {{date}}", "suspended": "Suspended", "free": "Free plan", "renews-on": "Renews on {{date}}", "active": "Active", "created": "Awaiting activation", "canceled": "Canceled", "expired": "Expired", "ended": "Ended", "blocked": "Blocked" }, "limit": { "usage": "{{used}} of {{limit}}", "usage-unit": "{{used}} of {{limit}} {{unit}}", "not-included": "Not included", "exhausted": "Limit reached", "resets-on": "Resets on {{date}}" }, "promo": { "free-until": "Free until {{date}}", "grandfathered": "Included for your plan", "ended": "Promotion ended" }, "capability": { "included": "Included", "not-included": "Not included" } } }
|
package/build/i18n/es.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "amount-checkout": { "title": "Añadir créditos", "description": "Elige el valor neto de créditos para tu organización.", "presets": "Importes predefinidos", "custom": "Importe personalizado", "invalid": "Introduce un importe válido con un máximo de dos decimales.", "below": "El importe mínimo es {{amount}}.", "above": "El importe máximo es {{amount}}.", "bounds": "Elige entre {{minimum}} y {{maximum}}.", "credits": "Valor de los créditos", "adjustment": "Ajuste de procesamiento", "subtotal": "Subtotal antes de impuestos", "tax-note": "Stripe calcula los impuestos aplicables al pagar.", "cancel": "Cancelar", "continue": "Continuar a Stripe", "pending": "Abriendo el pago…", "close": "Cerrar" } }
|
|
1
|
+
{ "amount-checkout": { "title": "Añadir créditos", "description": "Elige el valor neto de créditos para tu organización.", "presets": "Importes predefinidos", "custom": "Importe personalizado", "invalid": "Introduce un importe válido con un máximo de dos decimales.", "below": "El importe mínimo es {{amount}}.", "above": "El importe máximo es {{amount}}.", "bounds": "Elige entre {{minimum}} y {{maximum}}.", "credits": "Valor de los créditos", "adjustment": "Ajuste de procesamiento", "subtotal": "Subtotal antes de impuestos", "tax-note": "Stripe calcula los impuestos aplicables al pagar.", "cancel": "Cancelar", "continue": "Continuar a Stripe", "pending": "Abriendo el pago…", "close": "Cerrar" }, "entitlement": { "plan": { "current": "Plan actual" }, "status": { "trial": "Prueba", "trial-on": "La prueba termina el {{date}}", "past-due": "Pago vencido", "cancel-scheduled": "Cancelación programada", "cancel-scheduled-on": "Se cancela el {{date}}", "paused": "En pausa", "paused-on": "En pausa desde el {{date}}", "suspended": "Suspendido", "free": "Plan gratuito", "renews-on": "Se renueva el {{date}}", "active": "Activo", "created": "Pendiente de activación", "canceled": "Cancelado", "expired": "Vencido", "ended": "Finalizado", "blocked": "Bloqueado" }, "limit": { "usage": "{{used}} de {{limit}}", "usage-unit": "{{used}} de {{limit}} {{unit}}", "not-included": "No incluido", "exhausted": "Límite alcanzado", "resets-on": "Se restablece el {{date}}" }, "promo": { "free-until": "Gratis hasta el {{date}}", "grandfathered": "Incluido en tu plan", "ended": "Promoción finalizada" }, "capability": { "included": "Incluido", "not-included": "No incluido" } } }
|
package/build/i18n/pl.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "amount-checkout": { "title": "Dodaj kredyty", "description": "Wybierz wartość netto kredytów dla organizacji.", "presets": "Kwoty sugerowane", "custom": "Własna kwota", "invalid": "Wpisz prawidłową kwotę z maksymalnie dwoma miejscami dziesiętnymi.", "below": "Minimalna kwota to {{amount}}.", "above": "Maksymalna kwota to {{amount}}.", "bounds": "Wybierz od {{minimum}} do {{maximum}}.", "credits": "Wartość kredytów", "adjustment": "Korekta przetwarzania", "subtotal": "Suma przed podatkiem", "tax-note": "Stripe obliczy należny podatek podczas płatności.", "cancel": "Anuluj", "continue": "Przejdź do Stripe", "pending": "Otwieranie płatności…", "close": "Zamknij" } }
|
|
1
|
+
{ "amount-checkout": { "title": "Dodaj kredyty", "description": "Wybierz wartość netto kredytów dla organizacji.", "presets": "Kwoty sugerowane", "custom": "Własna kwota", "invalid": "Wpisz prawidłową kwotę z maksymalnie dwoma miejscami dziesiętnymi.", "below": "Minimalna kwota to {{amount}}.", "above": "Maksymalna kwota to {{amount}}.", "bounds": "Wybierz od {{minimum}} do {{maximum}}.", "credits": "Wartość kredytów", "adjustment": "Korekta przetwarzania", "subtotal": "Suma przed podatkiem", "tax-note": "Stripe obliczy należny podatek podczas płatności.", "cancel": "Anuluj", "continue": "Przejdź do Stripe", "pending": "Otwieranie płatności…", "close": "Zamknij" }, "entitlement": { "plan": { "current": "Obecny plan" }, "status": { "trial": "Okres próbny", "trial-on": "Okres próbny kończy się {{date}}", "past-due": "Zaległa płatność", "cancel-scheduled": "Anulowanie zaplanowane", "cancel-scheduled-on": "Zostanie anulowany {{date}}", "paused": "Wstrzymany", "paused-on": "Wstrzymany od {{date}}", "suspended": "Zawieszony", "free": "Plan darmowy", "renews-on": "Odnawia się {{date}}", "active": "Aktywny", "created": "Oczekuje na aktywację", "canceled": "Anulowany", "expired": "Wygasł", "ended": "Zakończony", "blocked": "Zablokowany" }, "limit": { "usage": "{{used}} z {{limit}}", "usage-unit": "{{used}} z {{limit}} {{unit}}", "not-included": "Brak w planie", "exhausted": "Limit wyczerpany", "resets-on": "Odnowienie {{date}}" }, "promo": { "free-until": "Bezpłatnie do {{date}}", "grandfathered": "Zachowane w Twoim planie", "ended": "Promocja zakończona" }, "capability": { "included": "W planie", "not-included": "Brak w planie" } } }
|