@softure-ai/billing 0.0.0-stage → 0.1.5
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/LICENSE +21 -0
- package/README.md +699 -2
- package/dist/calendar.d.ts +26 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +81 -0
- package/dist/calendar.js.map +1 -0
- package/dist/contract.d.ts +187 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +6 -0
- package/dist/contract.js.map +1 -0
- package/dist/currency-digits.d.ts +3 -0
- package/dist/currency-digits.d.ts.map +1 -0
- package/dist/currency-digits.js +32 -0
- package/dist/currency-digits.js.map +1 -0
- package/dist/entitlement.d.ts +25 -0
- package/dist/entitlement.d.ts.map +1 -0
- package/dist/entitlement.js +75 -0
- package/dist/entitlement.js.map +1 -0
- package/dist/fields.d.ts +25 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +27 -0
- package/dist/fields.js.map +1 -0
- package/dist/index.d.ts +274 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/invoice.d.ts +29 -0
- package/dist/invoice.d.ts.map +1 -0
- package/dist/invoice.js +35 -0
- package/dist/invoice.js.map +1 -0
- package/dist/mailing/index.d.ts +2 -0
- package/dist/mailing/index.d.ts.map +1 -0
- package/dist/mailing/index.js +4 -0
- package/dist/mailing/index.js.map +1 -0
- package/dist/mailing/reminder-mail.d.ts +50 -0
- package/dist/mailing/reminder-mail.d.ts.map +1 -0
- package/dist/mailing/reminder-mail.js +71 -0
- package/dist/mailing/reminder-mail.js.map +1 -0
- package/dist/manual.d.ts +12 -0
- package/dist/manual.d.ts.map +1 -0
- package/dist/manual.js +22 -0
- package/dist/manual.js.map +1 -0
- package/dist/messages/en.d.ts +176 -0
- package/dist/messages/en.d.ts.map +1 -0
- package/dist/messages/en.js +151 -0
- package/dist/messages/en.js.map +1 -0
- package/dist/messages/index.d.ts +359 -0
- package/dist/messages/index.d.ts.map +1 -0
- package/dist/messages/index.js +14 -0
- package/dist/messages/index.js.map +1 -0
- package/dist/messages/pl.d.ts +3 -0
- package/dist/messages/pl.d.ts.map +1 -0
- package/dist/messages/pl.js +151 -0
- package/dist/messages/pl.js.map +1 -0
- package/dist/next/access.d.ts +16 -0
- package/dist/next/access.d.ts.map +1 -0
- package/dist/next/access.js +24 -0
- package/dist/next/access.js.map +1 -0
- package/dist/next/actions.d.ts +24 -0
- package/dist/next/actions.d.ts.map +1 -0
- package/dist/next/actions.js +158 -0
- package/dist/next/actions.js.map +1 -0
- package/dist/next/context.d.ts +4 -0
- package/dist/next/context.d.ts.map +1 -0
- package/dist/next/context.js +17 -0
- package/dist/next/context.js.map +1 -0
- package/dist/next/current-entitlement.d.ts +18 -0
- package/dist/next/current-entitlement.d.ts.map +1 -0
- package/dist/next/current-entitlement.js +26 -0
- package/dist/next/current-entitlement.js.map +1 -0
- package/dist/next/index.d.ts +8 -0
- package/dist/next/index.d.ts.map +1 -0
- package/dist/next/index.js +12 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/pages.d.ts +24 -0
- package/dist/next/pages.d.ts.map +1 -0
- package/dist/next/pages.js +166 -0
- package/dist/next/pages.js.map +1 -0
- package/dist/next/pricing.d.ts +12 -0
- package/dist/next/pricing.d.ts.map +1 -0
- package/dist/next/pricing.js +20 -0
- package/dist/next/pricing.js.map +1 -0
- package/dist/next/route.d.ts +11 -0
- package/dist/next/route.d.ts.map +1 -0
- package/dist/next/route.js +56 -0
- package/dist/next/route.js.map +1 -0
- package/dist/options.d.ts +85 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +121 -0
- package/dist/options.js.map +1 -0
- package/dist/payment.d.ts +61 -0
- package/dist/payment.d.ts.map +1 -0
- package/dist/payment.js +12 -0
- package/dist/payment.js.map +1 -0
- package/dist/plans.d.ts +20 -0
- package/dist/plans.d.ts.map +1 -0
- package/dist/plans.js +53 -0
- package/dist/plans.js.map +1 -0
- package/dist/price.d.ts +12 -0
- package/dist/price.d.ts.map +1 -0
- package/dist/price.js +37 -0
- package/dist/price.js.map +1 -0
- package/dist/refund.d.ts +70 -0
- package/dist/refund.d.ts.map +1 -0
- package/dist/refund.js +109 -0
- package/dist/refund.js.map +1 -0
- package/dist/reminder.d.ts +30 -0
- package/dist/reminder.d.ts.map +1 -0
- package/dist/reminder.js +34 -0
- package/dist/reminder.js.map +1 -0
- package/dist/schema.d.ts +1023 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +77 -0
- package/dist/schema.js.map +1 -0
- package/dist/scripts/entitlement-scripts.d.ts +17 -0
- package/dist/scripts/entitlement-scripts.d.ts.map +1 -0
- package/dist/scripts/entitlement-scripts.js +167 -0
- package/dist/scripts/entitlement-scripts.js.map +1 -0
- package/dist/scripts/index.d.ts +3 -0
- package/dist/scripts/index.d.ts.map +1 -0
- package/dist/scripts/index.js +5 -0
- package/dist/scripts/index.js.map +1 -0
- package/dist/scripts/plan-scripts.d.ts +19 -0
- package/dist/scripts/plan-scripts.d.ts.map +1 -0
- package/dist/scripts/plan-scripts.js +106 -0
- package/dist/scripts/plan-scripts.js.map +1 -0
- package/dist/server/entitlements.d.ts +69 -0
- package/dist/server/entitlements.d.ts.map +1 -0
- package/dist/server/entitlements.js +202 -0
- package/dist/server/entitlements.js.map +1 -0
- package/dist/server/grants.d.ts +74 -0
- package/dist/server/grants.d.ts.map +1 -0
- package/dist/server/grants.js +174 -0
- package/dist/server/grants.js.map +1 -0
- package/dist/server/health.d.ts +3 -0
- package/dist/server/health.d.ts.map +1 -0
- package/dist/server/health.js +17 -0
- package/dist/server/health.js.map +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +14 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/options.d.ts +20 -0
- package/dist/server/options.d.ts.map +1 -0
- package/dist/server/options.js +38 -0
- package/dist/server/options.js.map +1 -0
- package/dist/server/payments.d.ts +140 -0
- package/dist/server/payments.d.ts.map +1 -0
- package/dist/server/payments.js +339 -0
- package/dist/server/payments.js.map +1 -0
- package/dist/server/plans.d.ts +50 -0
- package/dist/server/plans.d.ts.map +1 -0
- package/dist/server/plans.js +129 -0
- package/dist/server/plans.js.map +1 -0
- package/dist/server/privacy.d.ts +77 -0
- package/dist/server/privacy.d.ts.map +1 -0
- package/dist/server/privacy.js +110 -0
- package/dist/server/privacy.js.map +1 -0
- package/dist/server/reminders.d.ts +20 -0
- package/dist/server/reminders.d.ts.map +1 -0
- package/dist/server/reminders.js +85 -0
- package/dist/server/reminders.js.map +1 -0
- package/dist/server/requests.d.ts +80 -0
- package/dist/server/requests.d.ts.map +1 -0
- package/dist/server/requests.js +155 -0
- package/dist/server/requests.js.map +1 -0
- package/dist/server/setup.d.ts +9 -0
- package/dist/server/setup.d.ts.map +1 -0
- package/dist/server/setup.js +34 -0
- package/dist/server/setup.js.map +1 -0
- package/dist/server/take-back.d.ts +80 -0
- package/dist/server/take-back.d.ts.map +1 -0
- package/dist/server/take-back.js +138 -0
- package/dist/server/take-back.js.map +1 -0
- package/dist/server/user-id.d.ts +4 -0
- package/dist/server/user-id.d.ts.map +1 -0
- package/dist/server/user-id.js +11 -0
- package/dist/server/user-id.js.map +1 -0
- package/dist/stripe-currency.d.ts +27 -0
- package/dist/stripe-currency.d.ts.map +1 -0
- package/dist/stripe-currency.js +57 -0
- package/dist/stripe-currency.js.map +1 -0
- package/dist/stripe-webhook.d.ts +101 -0
- package/dist/stripe-webhook.d.ts.map +1 -0
- package/dist/stripe-webhook.js +209 -0
- package/dist/stripe-webhook.js.map +1 -0
- package/dist/stripe.d.ts +25 -0
- package/dist/stripe.d.ts.map +1 -0
- package/dist/stripe.js +116 -0
- package/dist/stripe.js.map +1 -0
- package/dist/ui/access-badge.d.ts +16 -0
- package/dist/ui/access-badge.d.ts.map +1 -0
- package/dist/ui/access-badge.js +43 -0
- package/dist/ui/access-badge.js.map +1 -0
- package/dist/ui/access-notice.d.ts +20 -0
- package/dist/ui/access-notice.d.ts.map +1 -0
- package/dist/ui/access-notice.js +41 -0
- package/dist/ui/access-notice.js.map +1 -0
- package/dist/ui/format.d.ts +11 -0
- package/dist/ui/format.d.ts.map +1 -0
- package/dist/ui/format.js +21 -0
- package/dist/ui/format.js.map +1 -0
- package/dist/ui/grant-form.d.ts +18 -0
- package/dist/ui/grant-form.d.ts.map +1 -0
- package/dist/ui/grant-form.js +23 -0
- package/dist/ui/grant-form.js.map +1 -0
- package/dist/ui/grant-history.d.ts +39 -0
- package/dist/ui/grant-history.d.ts.map +1 -0
- package/dist/ui/grant-history.js +36 -0
- package/dist/ui/grant-history.js.map +1 -0
- package/dist/ui/index.d.ts +9 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +12 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/payment-form.d.ts +23 -0
- package/dist/ui/payment-form.d.ts.map +1 -0
- package/dist/ui/payment-form.js +34 -0
- package/dist/ui/payment-form.js.map +1 -0
- package/dist/ui/payment-requests.d.ts +30 -0
- package/dist/ui/payment-requests.d.ts.map +1 -0
- package/dist/ui/payment-requests.js +31 -0
- package/dist/ui/payment-requests.js.map +1 -0
- package/dist/ui/pricing-tiles.d.ts +22 -0
- package/dist/ui/pricing-tiles.d.ts.map +1 -0
- package/dist/ui/pricing-tiles.js +40 -0
- package/dist/ui/pricing-tiles.js.map +1 -0
- package/migrations/0001_create_entitlements.sql +16 -0
- package/migrations/0002_create_payments.sql +30 -0
- package/migrations/0003_record_payment_grants.sql +25 -0
- package/migrations/0004_create_requests_and_grants.sql +58 -0
- package/migrations/0005_record_refunded_amounts.sql +18 -0
- package/migrations/0006_record_request_handover_and_prices.sql +38 -0
- package/migrations/0007_record_failed_refunds.sql +27 -0
- package/migrations/0008_record_request_handover_claims.sql +9 -0
- package/migrations/0009_record_pending_charge_states.sql +16 -0
- package/module.json +23 -0
- package/package.json +81 -4
- package/src/calendar.ts +90 -0
- package/src/contract.ts +181 -0
- package/src/currency-digits.ts +37 -0
- package/src/entitlement.ts +84 -0
- package/src/fields.ts +37 -0
- package/src/index.ts +163 -0
- package/src/invoice.ts +58 -0
- package/src/mailing/index.ts +11 -0
- package/src/mailing/reminder-mail.ts +108 -0
- package/src/manual.ts +31 -0
- package/src/messages/en.ts +150 -0
- package/src/messages/index.ts +18 -0
- package/src/messages/pl.ts +152 -0
- package/src/next/access.tsx +55 -0
- package/src/next/actions.ts +176 -0
- package/src/next/context.ts +18 -0
- package/src/next/current-entitlement.ts +36 -0
- package/src/next/index.ts +11 -0
- package/src/next/next-modules.d.ts +21 -0
- package/src/next/pages.tsx +267 -0
- package/src/next/pricing.tsx +39 -0
- package/src/next/route.ts +57 -0
- package/src/options.ts +128 -0
- package/src/payment.ts +77 -0
- package/src/plans.ts +63 -0
- package/src/price.ts +50 -0
- package/src/refund.ts +135 -0
- package/src/reminder.ts +52 -0
- package/src/schema.ts +86 -0
- package/src/scripts/entitlement-scripts.ts +188 -0
- package/src/scripts/index.ts +11 -0
- package/src/scripts/plan-scripts.ts +143 -0
- package/src/server/entitlements.ts +227 -0
- package/src/server/grants.ts +227 -0
- package/src/server/health.ts +18 -0
- package/src/server/index.ts +83 -0
- package/src/server/options.ts +52 -0
- package/src/server/payments.ts +434 -0
- package/src/server/plans.ts +143 -0
- package/src/server/privacy.ts +189 -0
- package/src/server/reminders.ts +113 -0
- package/src/server/requests.ts +201 -0
- package/src/server/setup.ts +37 -0
- package/src/server/take-back.ts +190 -0
- package/src/server/user-id.ts +12 -0
- package/src/stripe-currency.ts +65 -0
- package/src/stripe-webhook.ts +278 -0
- package/src/stripe.ts +130 -0
- package/src/ui/access-badge.tsx +64 -0
- package/src/ui/access-notice.tsx +73 -0
- package/src/ui/format.ts +25 -0
- package/src/ui/grant-form.tsx +69 -0
- package/src/ui/grant-history.tsx +127 -0
- package/src/ui/index.ts +25 -0
- package/src/ui/payment-form.tsx +111 -0
- package/src/ui/payment-requests.tsx +126 -0
- package/src/ui/pricing-tiles.tsx +105 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-notice.js","sourceRoot":"","sources":["../../src/ui/access-notice.tsx"],"names":[],"mappings":";AAAA,+FAA+F;AAC/F,iGAAiG;AACjG,gFAAgF;AAChF,OAAO,EAAE,aAAa,EAAe,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAmB,qBAAqB,EAA0B,MAAM,gBAAgB,CAAC;AAG5G,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAwB5C,6EAA6E;AAC7E,SAAS,aAAa,CAAC,WAAwB,EAAE,QAAyB,EAAE,MAAc,EAAE,QAAgB;IAC1G,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC7B,QAAQ,WAAW,CAAC,MAAM,EAAE,CAAC;QAC3B,KAAK,OAAO;YACV,IAAI,CAAC,WAAW,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAC;YACvC,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC3J,KAAK,MAAM;YACT,IAAI,CAAC,WAAW,CAAC,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YACtE,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACrJ,KAAK,WAAW;YACd,OAAO,WAAW,CAAC,MAAM,KAAK,aAAa;gBACzC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE;gBACnE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACpE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAqB;IAC3I,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACtE,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,IAAI,GAAG,qBAAqB,CAAmB;QACnD,QAAQ,EAAE;YACR,IAAI,EAAE,oIACJ,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC,gDAC7D,EAAE;YACF,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE,uBAAuB;SACjC;QACD,UAAU;QACV,QAAQ;KACT,CAAC,CAAC;IACH,OAAO,CACL,eAAK,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,iBAAe,WAAW,CAAC,MAAM,aACzE,YAAG,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,YAAG,MAAM,CAAC,IAAI,GAAK,EAChD,cAAK,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,YAC7B,KAAC,UAAU,IAAC,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,EAAC,IAAI,EAAC,QAAQ,EAAE,QAAQ,YACzI,MAAM,CAAC,MAAM,GACH,GACT,IACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Locale } from "@softure-ai/core";
|
|
2
|
+
import type { PlanPeriod } from "../contract.js";
|
|
3
|
+
import type { BillingMessages } from "../messages/index.js";
|
|
4
|
+
/** The last local day covered by an access that ends at `end`, e.g. "October 16, 2026" in en. */
|
|
5
|
+
export declare function formatLastDay(end: Date, locale: Locale, timezone: string): string;
|
|
6
|
+
/** The local day of an instant, e.g. "October 3, 2026" in en: when something happened, or a first day of access. */
|
|
7
|
+
export declare function formatDay(instant: Date, locale: Locale, timezone: string): string;
|
|
8
|
+
export declare function formatDaysLeft(days: number, locale: Locale, messages: BillingMessages): string;
|
|
9
|
+
/** How long one payment lasts, as the tiles say it: "per month", "per 3 months", "one-time payment". */
|
|
10
|
+
export declare function formatPeriod(period: PlanPeriod, locale: Locale, messages: BillingMessages): string;
|
|
11
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/ui/format.ts"],"names":[],"mappings":"AAEA,OAAO,EAA+B,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED,oHAAoH;AACpH,wBAAgB,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,MAAM,CAE9F;AAED,wGAAwG;AACxG,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,MAAM,CAGlG"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Dates and day counts of an entitlement as the components show them. An end is the first instant
|
|
2
|
+
// without access, so the date shown is the last day with it, in the app's time zone.
|
|
3
|
+
import { formatMessage, selectPlural } from "@softure-ai/core";
|
|
4
|
+
/** The last local day covered by an access that ends at `end`, e.g. "October 16, 2026" in en. */
|
|
5
|
+
export function formatLastDay(end, locale, timezone) {
|
|
6
|
+
return new Intl.DateTimeFormat(locale, { dateStyle: "long", timeZone: timezone }).format(new Date(end.getTime() - 1));
|
|
7
|
+
}
|
|
8
|
+
/** The local day of an instant, e.g. "October 3, 2026" in en: when something happened, or a first day of access. */
|
|
9
|
+
export function formatDay(instant, locale, timezone) {
|
|
10
|
+
return new Intl.DateTimeFormat(locale, { dateStyle: "long", timeZone: timezone }).format(instant);
|
|
11
|
+
}
|
|
12
|
+
export function formatDaysLeft(days, locale, messages) {
|
|
13
|
+
return formatMessage(selectPlural(locale, days, messages.badge.daysLeft), { count: days });
|
|
14
|
+
}
|
|
15
|
+
/** How long one payment lasts, as the tiles say it: "per month", "per 3 months", "one-time payment". */
|
|
16
|
+
export function formatPeriod(period, locale, messages) {
|
|
17
|
+
if (period.unit === "lifetime")
|
|
18
|
+
return messages.pricing.period.lifetime;
|
|
19
|
+
return formatMessage(selectPlural(locale, period.count, messages.pricing.period[period.unit]), { count: period.count });
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/ui/format.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,qFAAqF;AACrF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAe,MAAM,kBAAkB,CAAC;AAI5E,iGAAiG;AACjG,MAAM,UAAU,aAAa,CAAC,GAAS,EAAE,MAAc,EAAE,QAAgB;IACvE,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AACxH,CAAC;AAED,oHAAoH;AACpH,MAAM,UAAU,SAAS,CAAC,OAAa,EAAE,MAAc,EAAE,QAAgB;IACvE,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAAc,EAAE,QAAyB;IACpF,OAAO,aAAa,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7F,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,YAAY,CAAC,MAAkB,EAAE,MAAc,EAAE,QAAyB;IACxF,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;IACxE,OAAO,aAAa,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AAC1H,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Locale } from "@softure-ai/core";
|
|
2
|
+
import { type ClassNames, type SelectOption } from "@softure-ai/ui";
|
|
3
|
+
import { type GrantFormState } from "../contract.js";
|
|
4
|
+
import { type BillingMessages } from "../messages/index.js";
|
|
5
|
+
export type GrantFormAction = (previous: GrantFormState, formData: FormData) => Promise<GrantFormState>;
|
|
6
|
+
export type GrantFormSlot = "root" | "form" | "notice";
|
|
7
|
+
export interface GrantFormProps {
|
|
8
|
+
readonly action: GrantFormAction;
|
|
9
|
+
/** The plans to choose from: id and name in the app's locale. */
|
|
10
|
+
readonly plans: readonly SelectOption[];
|
|
11
|
+
readonly messages: BillingMessages;
|
|
12
|
+
/** Locale of the built-in copy of the ui primitives. */
|
|
13
|
+
readonly locale?: Locale;
|
|
14
|
+
readonly classNames?: ClassNames<GrantFormSlot>;
|
|
15
|
+
readonly unstyled?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function GrantForm({ action, plans, messages, locale, classNames, unstyled }: GrantFormProps): import("react").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=grant-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grant-form.d.ts","sourceRoot":"","sources":["../../src/ui/grant-form.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAU,KAAK,UAAU,EAAiD,KAAK,YAAY,EAAa,MAAM,gBAAgB,CAAC;AAEtI,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAMpF,MAAM,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAExG,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;IAChD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAQD,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,cAAc,+BAkClG"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button, createSlotClassGetter, FormError, SelectField, TextField } from "@softure-ai/ui";
|
|
4
|
+
import { useActionState } from "react";
|
|
5
|
+
import { INITIAL_GRANT_FORM_STATE } from "../contract.js";
|
|
6
|
+
import { EMAIL_FIELD, PLAN_FIELD } from "../fields.js";
|
|
7
|
+
import { getBillingErrorMessage } from "../messages/index.js";
|
|
8
|
+
const DEFAULT_CLASSES = {
|
|
9
|
+
root: "sft:flex sft:flex-col sft:gap-3 sft:font-sans",
|
|
10
|
+
form: "sft:flex sft:flex-col sft:gap-3",
|
|
11
|
+
notice: "sft:m-0 sft:text-sm sft:text-success",
|
|
12
|
+
};
|
|
13
|
+
export function GrantForm({ action, plans, messages, locale, classNames, unstyled }) {
|
|
14
|
+
const [state, formAction, isPending] = useActionState(action, INITIAL_GRANT_FORM_STATE);
|
|
15
|
+
const slot = createSlotClassGetter({ defaults: DEFAULT_CLASSES, classNames, unstyled });
|
|
16
|
+
const copy = messages.admin;
|
|
17
|
+
const error = state.error === undefined ? undefined : getBillingErrorMessage(messages, state.error);
|
|
18
|
+
const isEmailError = state.error === "billing.account_unknown";
|
|
19
|
+
return (_jsxs("div", { className: slot("root"), children: [_jsxs("form", { action: formAction, className: slot("form"), children: [_jsx(TextField
|
|
20
|
+
// A fresh, empty field after each grant; the typed address after an error.
|
|
21
|
+
, { name: EMAIL_FIELD, type: "email", label: copy.email, required: true, defaultValue: state.status === "error" ? (state.email ?? "") : "", error: isEmailError ? error : undefined, locale: locale, unstyled: unstyled }, `${state.status}:${state.email ?? ""}`), _jsx(SelectField, { name: PLAN_FIELD, label: copy.plan, options: plans, defaultValue: state.planId, locale: locale, unstyled: unstyled }), _jsx(FormError, { message: isEmailError ? undefined : error, unstyled: unstyled }), _jsx(Button, { type: "submit", variant: "primary", pending: isPending, unstyled: unstyled, children: isPending ? copy.pending : copy.submit })] }), state.status === "granted" ? (_jsx("p", { role: "status", className: slot("notice"), children: state.notice })) : null] }));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=grant-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grant-form.js","sourceRoot":"","sources":["../../src/ui/grant-form.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Locale } from "@softure-ai/core";
|
|
2
|
+
import { type ClassNames } from "@softure-ai/ui";
|
|
3
|
+
import { type BillingMessages } from "../messages/index.js";
|
|
4
|
+
import type { AdminAction } from "./payment-requests.js";
|
|
5
|
+
export type GrantHistorySlot = "root" | "empty" | "item" | "itemHeader" | "title" | "status" | "details";
|
|
6
|
+
/** One grant or payment, prepared on the server. */
|
|
7
|
+
export interface GrantHistoryRow {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
/** The plan and where it came from, e.g. "Monthly, granted by hand". */
|
|
10
|
+
readonly title: string;
|
|
11
|
+
/** "Active", "Revoked on …", "Paid", "Refunded on …". */
|
|
12
|
+
readonly statusText: string;
|
|
13
|
+
/** Whether it still gives access (active or paid); the rest is drawn muted. */
|
|
14
|
+
readonly isCurrent: boolean;
|
|
15
|
+
/** The date, the access it added and the amount, one line each. */
|
|
16
|
+
readonly details: readonly string[];
|
|
17
|
+
/** Set for an active manual grant: the accessible name of its Revoke button. */
|
|
18
|
+
readonly revokeLabel: string | null;
|
|
19
|
+
}
|
|
20
|
+
export interface GrantHistoryProps {
|
|
21
|
+
readonly rows: readonly GrantHistoryRow[];
|
|
22
|
+
readonly revokeAction: AdminAction;
|
|
23
|
+
readonly messages: BillingMessages;
|
|
24
|
+
readonly classNames?: ClassNames<GrantHistorySlot>;
|
|
25
|
+
readonly unstyled?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare function GrantHistory({ rows, revokeAction, messages, classNames, unstyled }: GrantHistoryProps): import("react").JSX.Element;
|
|
28
|
+
export type AccountLookupSlot = "root";
|
|
29
|
+
export interface AccountLookupProps {
|
|
30
|
+
readonly action: AdminAction;
|
|
31
|
+
readonly messages: BillingMessages;
|
|
32
|
+
/** Locale of the built-in copy of the ui primitives. */
|
|
33
|
+
readonly locale?: Locale;
|
|
34
|
+
readonly classNames?: ClassNames<AccountLookupSlot>;
|
|
35
|
+
readonly unstyled?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** The email lookup of the history card; a found account reloads the page on its history. */
|
|
38
|
+
export declare function AccountLookup({ action, messages, locale, classNames, unstyled }: AccountLookupProps): import("react").JSX.Element;
|
|
39
|
+
//# sourceMappingURL=grant-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grant-history.d.ts","sourceRoot":"","sources":["../../src/ui/grant-history.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAU,KAAK,UAAU,EAA+C,MAAM,gBAAgB,CAAC;AAItG,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAOzD,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzG,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,gFAAgF;IAChF,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,eAAe,EAAE,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC,CAAC;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAyCD,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,iBAAiB,+BAUrG;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC;IACpD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAuBnG"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button, createSlotClassGetter, FormError, TextField } from "@softure-ai/ui";
|
|
4
|
+
import { useActionState } from "react";
|
|
5
|
+
import { INITIAL_ADMIN_ACTION_STATE } from "../contract.js";
|
|
6
|
+
import { EMAIL_FIELD, GRANT_FIELD } from "../fields.js";
|
|
7
|
+
import { getBillingErrorMessage } from "../messages/index.js";
|
|
8
|
+
const DEFAULT_CLASSES = {
|
|
9
|
+
root: "sft:m-0 sft:flex sft:list-none sft:flex-col sft:gap-3 sft:p-0 sft:font-sans",
|
|
10
|
+
empty: "sft:m-0 sft:font-sans sft:text-sm sft:text-muted",
|
|
11
|
+
item: "sft:flex sft:flex-col sft:gap-1 sft:border-t sft:border-border sft:pt-3 sft:first-of-type:border-t-0 sft:first-of-type:pt-0",
|
|
12
|
+
itemHeader: "sft:flex sft:items-center sft:justify-between sft:gap-2",
|
|
13
|
+
title: "sft:m-0 sft:text-sm sft:font-semibold sft:text-foreground",
|
|
14
|
+
status: "sft:text-xs sft:font-medium sft:text-success",
|
|
15
|
+
details: "sft:m-0 sft:text-xs sft:text-muted",
|
|
16
|
+
};
|
|
17
|
+
function HistoryItem({ row, revokeAction, messages, slot, unstyled }) {
|
|
18
|
+
const [state, formAction, isPending] = useActionState(revokeAction, INITIAL_ADMIN_ACTION_STATE);
|
|
19
|
+
const copy = messages.admin.history;
|
|
20
|
+
return (_jsxs("li", { className: slot("item"), "data-history-id": row.id, children: [_jsxs("div", { className: slot("itemHeader"), children: [_jsx("p", { className: slot("title"), children: row.title }), row.revokeLabel === null ? null : (_jsxs("form", { action: formAction, children: [_jsx("input", { type: "hidden", name: GRANT_FIELD, value: row.id }), _jsx(Button, { type: "submit", variant: "danger", size: "sm", pending: isPending, "aria-label": row.revokeLabel, unstyled: unstyled, children: isPending ? copy.revoking : copy.revoke })] }))] }), _jsx("p", { className: row.isCurrent ? slot("status") : slot("details"), children: row.statusText }), row.details.map((line) => (_jsx("p", { className: slot("details"), children: line }, line))), _jsx(FormError, { message: state.status === "error" ? getBillingErrorMessage(messages, state.error) : undefined, unstyled: unstyled })] }));
|
|
21
|
+
}
|
|
22
|
+
export function GrantHistory({ rows, revokeAction, messages, classNames, unstyled }) {
|
|
23
|
+
const slot = createSlotClassGetter({ defaults: DEFAULT_CLASSES, classNames, unstyled });
|
|
24
|
+
if (rows.length === 0)
|
|
25
|
+
return _jsx("p", { className: slot("empty"), children: messages.admin.history.empty });
|
|
26
|
+
return (_jsx("ul", { className: slot("root"), "aria-label": messages.admin.history.title, children: rows.map((row) => (_jsx(HistoryItem, { row: row, revokeAction: revokeAction, messages: messages, slot: slot, unstyled: unstyled }, row.id))) }));
|
|
27
|
+
}
|
|
28
|
+
/** The email lookup of the history card; a found account reloads the page on its history. */
|
|
29
|
+
export function AccountLookup({ action, messages, locale, classNames, unstyled }) {
|
|
30
|
+
const [state, formAction, isPending] = useActionState(action, INITIAL_ADMIN_ACTION_STATE);
|
|
31
|
+
const slot = createSlotClassGetter({ defaults: { root: "sft:flex sft:flex-col sft:gap-3 sft:font-sans" }, classNames, unstyled });
|
|
32
|
+
const copy = messages.admin.history;
|
|
33
|
+
const error = state.status === "error" ? getBillingErrorMessage(messages, state.error) : undefined;
|
|
34
|
+
return (_jsxs("form", { action: formAction, className: slot("root"), children: [_jsx(TextField, { name: EMAIL_FIELD, type: "email", label: copy.email, required: true, defaultValue: state.status === "error" ? (state.email ?? "") : "", error: error, locale: locale, unstyled: unstyled }, state.status === "error" ? `error:${state.email ?? ""}` : "lookup"), _jsx(Button, { type: "submit", variant: "secondary", pending: isPending, unstyled: unstyled, children: isPending ? copy.pending : copy.submit })] }));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=grant-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grant-history.js","sourceRoot":"","sources":["../../src/ui/grant-history.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,MAAM,EAAmB,qBAAqB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtG,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAwB,MAAM,sBAAsB,CAAC;AAiCpF,MAAM,eAAe,GAA+C;IAClE,IAAI,EAAE,6EAA6E;IACnF,KAAK,EAAE,kDAAkD;IACzD,IAAI,EAAE,6HAA6H;IACnI,UAAU,EAAE,yDAAyD;IACrE,KAAK,EAAE,2DAA2D;IAClE,MAAM,EAAE,8CAA8C;IACtD,OAAO,EAAE,oCAAoC;CAC9C,CAAC;AAIF,SAAS,WAAW,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAA6H;IAC7L,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,GAAG,cAAc,CAAC,YAAY,EAAE,0BAA0B,CAAC,CAAC;IAChG,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;IACpC,OAAO,CACL,cAAI,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,qBAAmB,GAAG,CAAC,EAAE,aAClD,eAAK,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,aAChC,YAAG,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,YAAG,GAAG,CAAC,KAAK,GAAK,EAC3C,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACjC,gBAAM,MAAM,EAAE,UAAU,aACtB,gBAAO,IAAI,EAAC,QAAQ,EAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,GAAI,EACzD,KAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAC,QAAQ,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,SAAS,gBAAc,GAAG,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,YACjH,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GACjC,IACJ,CACR,IACG,EACN,YAAG,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,YAAG,GAAG,CAAC,UAAU,GAAK,EACnF,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACzB,YAAc,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,YACrC,IAAI,IADC,IAAI,CAER,CACL,CAAC,EACF,KAAC,SAAS,IAAC,OAAO,EAAE,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAI,IAC7H,CACN,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAqB;IACpG,MAAM,IAAI,GAAG,qBAAqB,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,YAAG,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,YAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,GAAK,CAAC;IAC9F,OAAO,CACL,aAAI,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAc,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,YAClE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,KAAC,WAAW,IAAc,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,IAAhG,GAAG,CAAC,EAAE,CAA8F,CACvH,CAAC,GACC,CACN,CAAC;AACJ,CAAC;AAaD,6FAA6F;AAC7F,MAAM,UAAU,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAsB;IAClG,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;IAC1F,MAAM,IAAI,GAAG,qBAAqB,CAAoB,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,+CAA+C,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;IACrJ,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;IACpC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACnG,OAAO,CACL,gBAAM,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,aAC/C,KAAC,SAAS,IAER,IAAI,EAAE,WAAW,EACjB,IAAI,EAAC,OAAO,EACZ,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,QAAQ,QACR,YAAY,EAAE,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EACjE,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,IARb,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CASvE,EACF,KAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAC,WAAW,EAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,YAC7E,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAChC,IACJ,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { AccessBadge, type AccessBadgeProps, type AccessBadgeSlot } from "./access-badge.js";
|
|
2
|
+
export { AccessNotice, type AccessNoticeProps, type AccessNoticeSlot } from "./access-notice.js";
|
|
3
|
+
export { formatDay, formatDaysLeft, formatLastDay, formatPeriod } from "./format.js";
|
|
4
|
+
export { GrantForm, type GrantFormAction, type GrantFormProps, type GrantFormSlot } from "./grant-form.js";
|
|
5
|
+
export { AccountLookup, type AccountLookupProps, type AccountLookupSlot, GrantHistory, type GrantHistoryProps, type GrantHistoryRow, type GrantHistorySlot, } from "./grant-history.js";
|
|
6
|
+
export { PaymentForm, type PaymentFormAction, type PaymentFormProps, type PaymentFormSlot } from "./payment-form.js";
|
|
7
|
+
export { type AdminAction, PaymentRequestList, type PaymentRequestListProps, type PaymentRequestListSlot, type PaymentRequestRow, } from "./payment-requests.js";
|
|
8
|
+
export { PricingTiles, type PricingTilesProps, type PricingTilesSlot } from "./pricing-tiles.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjG,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EACL,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACrH,OAAO,EACL,KAAK,WAAW,EAChB,kBAAkB,EAClB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/ui/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// The billing components, to compose into the app's own pages. They render from props (an
|
|
2
|
+
// entitlement or the plans read on the server) and import nothing from `next/*`
|
|
3
|
+
// (docs/02-module-standard.md §5); `/next` renders them wired to the registered configuration.
|
|
4
|
+
export { AccessBadge } from "./access-badge.js";
|
|
5
|
+
export { AccessNotice } from "./access-notice.js";
|
|
6
|
+
export { formatDay, formatDaysLeft, formatLastDay, formatPeriod } from "./format.js";
|
|
7
|
+
export { GrantForm } from "./grant-form.js";
|
|
8
|
+
export { AccountLookup, GrantHistory, } from "./grant-history.js";
|
|
9
|
+
export { PaymentForm } from "./payment-form.js";
|
|
10
|
+
export { PaymentRequestList, } from "./payment-requests.js";
|
|
11
|
+
export { PricingTiles } from "./pricing-tiles.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,gFAAgF;AAChF,+FAA+F;AAC/F,OAAO,EAAE,WAAW,EAA+C,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAiD,MAAM,oBAAoB,CAAC;AACjG,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,SAAS,EAAiE,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EACL,aAAa,EAGb,YAAY,GAIb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAuE,MAAM,mBAAmB,CAAC;AACrH,OAAO,EAEL,kBAAkB,GAInB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAiD,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Locale } from "@softure-ai/core";
|
|
2
|
+
import { type ClassNames } from "@softure-ai/ui";
|
|
3
|
+
import { type PaymentFormState } from "../contract.js";
|
|
4
|
+
import { type BillingMessages } from "../messages/index.js";
|
|
5
|
+
export type PaymentFormAction = (previous: PaymentFormState, formData: FormData) => Promise<PaymentFormState>;
|
|
6
|
+
export type PaymentFormSlot = "root" | "form" | "notice";
|
|
7
|
+
export interface PaymentFormProps {
|
|
8
|
+
readonly action: PaymentFormAction;
|
|
9
|
+
readonly planId: string;
|
|
10
|
+
/** The plan's name in the app's locale, for the confirmation. */
|
|
11
|
+
readonly planName: string;
|
|
12
|
+
/** The buyer's address, for the confirmation. */
|
|
13
|
+
readonly email: string;
|
|
14
|
+
/** Asks for the invoice details (the manual adapter); else one checkout button. */
|
|
15
|
+
readonly collectsInvoiceDetails: boolean;
|
|
16
|
+
readonly messages: BillingMessages;
|
|
17
|
+
/** Locale of the built-in copy of the ui primitives. */
|
|
18
|
+
readonly locale?: Locale;
|
|
19
|
+
readonly classNames?: ClassNames<PaymentFormSlot>;
|
|
20
|
+
readonly unstyled?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function PaymentForm({ action, planId, planName, email, collectsInvoiceDetails, messages, locale, classNames, unstyled }: PaymentFormProps): import("react").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=payment-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-form.d.ts","sourceRoot":"","sources":["../../src/ui/payment-form.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAU,KAAK,UAAU,EAA+C,MAAM,gBAAgB,CAAC;AAEtG,OAAO,EAA8B,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEnF,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAOpF,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAE9G,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEzD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,eAAe,CAAC,CAAC;IAClD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAQD,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,gBAAgB,+BAsEhJ"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { formatMessage } from "@softure-ai/core";
|
|
4
|
+
import { Button, createSlotClassGetter, FormError, TextField } from "@softure-ai/ui";
|
|
5
|
+
import { useActionState } from "react";
|
|
6
|
+
import { INITIAL_PAYMENT_FORM_STATE } from "../contract.js";
|
|
7
|
+
import { getInvoiceFieldLimit, INVOICE_FIELDS, INVOICE_LIMITS, PLAN_FIELD } from "../fields.js";
|
|
8
|
+
import { getBillingErrorMessage } from "../messages/index.js";
|
|
9
|
+
const DEFAULT_CLASSES = {
|
|
10
|
+
root: "sft:flex sft:flex-col sft:gap-3 sft:font-sans",
|
|
11
|
+
form: "sft:flex sft:flex-col sft:gap-3",
|
|
12
|
+
notice: "sft:m-0 sft:text-sm sft:text-success",
|
|
13
|
+
};
|
|
14
|
+
export function PaymentForm({ action, planId, planName, email, collectsInvoiceDetails, messages, locale, classNames, unstyled }) {
|
|
15
|
+
const [state, formAction, isPending] = useActionState(action, INITIAL_PAYMENT_FORM_STATE);
|
|
16
|
+
const slot = createSlotClassGetter({ defaults: DEFAULT_CLASSES, classNames, unstyled });
|
|
17
|
+
if (state.status === "requested") {
|
|
18
|
+
return (_jsx("div", { className: slot("root"), children: _jsx("p", { role: "status", className: slot("notice"), children: formatMessage(messages.payment.requested, { plan: planName, email }) }) }));
|
|
19
|
+
}
|
|
20
|
+
const copy = messages.payment;
|
|
21
|
+
const values = state.values ?? {};
|
|
22
|
+
const fieldError = (name) => {
|
|
23
|
+
const code = state.fieldErrors?.[name];
|
|
24
|
+
if (code === undefined)
|
|
25
|
+
return undefined;
|
|
26
|
+
const limit = getInvoiceFieldLimit(name);
|
|
27
|
+
return formatMessage(getBillingErrorMessage(messages, code), limit === undefined ? {} : { max: limit });
|
|
28
|
+
};
|
|
29
|
+
const hasFieldErrors = Object.keys(state.fieldErrors ?? {}).length > 0;
|
|
30
|
+
const formError = state.error === undefined || hasFieldErrors ? undefined : getBillingErrorMessage(messages, state.error);
|
|
31
|
+
const submitLabel = collectsInvoiceDetails ? copy.requestInvoice : copy.checkout;
|
|
32
|
+
return (_jsx("div", { className: slot("root"), children: _jsxs("form", { action: formAction, className: slot("form"), children: [_jsx("input", { type: "hidden", name: PLAN_FIELD, value: planId }), collectsInvoiceDetails ? (_jsxs(_Fragment, { children: [_jsx(TextField, { name: INVOICE_FIELDS.name, label: copy.fields.name, autoComplete: "name", required: true, maxLength: INVOICE_LIMITS.name, defaultValue: values[INVOICE_FIELDS.name] ?? "", error: fieldError(INVOICE_FIELDS.name), locale: locale, unstyled: unstyled }), _jsx(TextField, { name: INVOICE_FIELDS.taxId, label: copy.fields.taxId, maxLength: INVOICE_LIMITS.taxId, defaultValue: values[INVOICE_FIELDS.taxId] ?? "", error: fieldError(INVOICE_FIELDS.taxId), locale: locale, unstyled: unstyled }), _jsx(TextField, { name: INVOICE_FIELDS.address, label: copy.fields.address, autoComplete: "street-address", required: true, maxLength: INVOICE_LIMITS.address, defaultValue: values[INVOICE_FIELDS.address] ?? "", error: fieldError(INVOICE_FIELDS.address), locale: locale, unstyled: unstyled })] })) : null, _jsx(FormError, { message: formError, unstyled: unstyled }), _jsx(Button, { type: "submit", variant: "primary", fullWidth: true, pending: isPending, unstyled: unstyled, children: isPending ? copy.pending : submitLabel })] }) }));
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=payment-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-form.js","sourceRoot":"","sources":["../../src/ui/payment-form.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ClassNames, type LinkComponentType } from "@softure-ai/ui";
|
|
2
|
+
import { type AdminActionState } from "../contract.js";
|
|
3
|
+
import { type BillingMessages } from "../messages/index.js";
|
|
4
|
+
export type AdminAction = (previous: AdminActionState, formData: FormData) => Promise<AdminActionState>;
|
|
5
|
+
export type PaymentRequestListSlot = "root" | "empty" | "item" | "itemHeader" | "title" | "details" | "actions";
|
|
6
|
+
/** One open request, prepared on the server. */
|
|
7
|
+
export interface PaymentRequestRow {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
/** The account's email and the plan, e.g. "ada@example.com · Monthly". */
|
|
10
|
+
readonly title: string;
|
|
11
|
+
/** When it was asked for and the invoice details, one line each. */
|
|
12
|
+
readonly details: readonly string[];
|
|
13
|
+
/** The admin page showing this account's history. */
|
|
14
|
+
readonly historyHref: string;
|
|
15
|
+
/** Accessible names of the buttons, naming the request. */
|
|
16
|
+
readonly grantLabel: string;
|
|
17
|
+
readonly dismissLabel: string;
|
|
18
|
+
}
|
|
19
|
+
export interface PaymentRequestListProps {
|
|
20
|
+
readonly requests: readonly PaymentRequestRow[];
|
|
21
|
+
readonly grantAction: AdminAction;
|
|
22
|
+
readonly dismissAction: AdminAction;
|
|
23
|
+
readonly messages: BillingMessages;
|
|
24
|
+
/** The app's link component, e.g. Next's `Link`; a plain `<a>` when omitted. */
|
|
25
|
+
readonly LinkComponent?: LinkComponentType;
|
|
26
|
+
readonly classNames?: ClassNames<PaymentRequestListSlot>;
|
|
27
|
+
readonly unstyled?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function PaymentRequestList({ requests, grantAction, dismissAction, messages, LinkComponent, classNames, unstyled }: PaymentRequestListProps): import("react").JSX.Element;
|
|
30
|
+
//# sourceMappingURL=payment-requests.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-requests.d.ts","sourceRoot":"","sources":["../../src/ui/payment-requests.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,UAAU,EAAoC,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAE/H,OAAO,EAA8B,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEnF,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAOpF,MAAM,MAAM,WAAW,GAAG,CAAC,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAExG,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAEhH,gDAAgD;AAChD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,qDAAqD;IACrD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAChD,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,gFAAgF;IAChF,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,sBAAsB,CAAC,CAAC;IACzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAkED,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,uBAAuB,+BAmBlJ"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button, ButtonLink, createSlotClassGetter, FormError } from "@softure-ai/ui";
|
|
4
|
+
import { useActionState } from "react";
|
|
5
|
+
import { INITIAL_ADMIN_ACTION_STATE } from "../contract.js";
|
|
6
|
+
import { REQUEST_FIELD } from "../fields.js";
|
|
7
|
+
import { getBillingErrorMessage } from "../messages/index.js";
|
|
8
|
+
const DEFAULT_CLASSES = {
|
|
9
|
+
root: "sft:m-0 sft:flex sft:list-none sft:flex-col sft:gap-3 sft:p-0 sft:font-sans",
|
|
10
|
+
empty: "sft:m-0 sft:font-sans sft:text-sm sft:text-muted",
|
|
11
|
+
item: "sft:flex sft:flex-col sft:gap-1 sft:border-t sft:border-border sft:pt-3 sft:first-of-type:border-t-0 sft:first-of-type:pt-0",
|
|
12
|
+
itemHeader: "sft:flex sft:items-center sft:justify-between sft:gap-2",
|
|
13
|
+
title: "sft:m-0 sft:text-sm sft:font-semibold sft:text-foreground",
|
|
14
|
+
details: "sft:m-0 sft:text-xs sft:text-muted",
|
|
15
|
+
actions: "sft:flex sft:items-center sft:gap-2",
|
|
16
|
+
};
|
|
17
|
+
function RequestItem({ row, grantAction, dismissAction, messages, LinkComponent, slot, unstyled, }) {
|
|
18
|
+
const [granted, grant, isGranting] = useActionState(grantAction, INITIAL_ADMIN_ACTION_STATE);
|
|
19
|
+
const [dismissed, dismiss, isDismissing] = useActionState(dismissAction, INITIAL_ADMIN_ACTION_STATE);
|
|
20
|
+
const copy = messages.admin.requests;
|
|
21
|
+
const failed = granted.status === "error" ? granted : dismissed.status === "error" ? dismissed : null;
|
|
22
|
+
const isPending = isGranting || isDismissing;
|
|
23
|
+
return (_jsxs("li", { className: slot("item"), "data-request-id": row.id, children: [_jsx("p", { className: slot("title"), children: row.title }), row.details.map((line) => (_jsx("p", { className: slot("details"), children: line }, line))), _jsxs("div", { className: slot("actions"), children: [_jsxs("form", { action: grant, children: [_jsx("input", { type: "hidden", name: REQUEST_FIELD, value: row.id }), _jsx(Button, { type: "submit", variant: "primary", size: "sm", pending: isGranting, disabled: isPending, "aria-label": row.grantLabel, unstyled: unstyled, children: isGranting ? copy.granting : copy.grant })] }), _jsxs("form", { action: dismiss, children: [_jsx("input", { type: "hidden", name: REQUEST_FIELD, value: row.id }), _jsx(Button, { type: "submit", variant: "ghost", size: "sm", pending: isDismissing, disabled: isPending, "aria-label": row.dismissLabel, unstyled: unstyled, children: isDismissing ? copy.dismissing : copy.dismiss })] }), _jsx(ButtonLink, { href: row.historyHref, variant: "ghost", size: "sm", LinkComponent: LinkComponent, unstyled: unstyled, children: copy.history })] }), _jsx(FormError, { message: failed === null ? undefined : getBillingErrorMessage(messages, failed.error), unstyled: unstyled })] }));
|
|
24
|
+
}
|
|
25
|
+
export function PaymentRequestList({ requests, grantAction, dismissAction, messages, LinkComponent, classNames, unstyled }) {
|
|
26
|
+
const slot = createSlotClassGetter({ defaults: DEFAULT_CLASSES, classNames, unstyled });
|
|
27
|
+
if (requests.length === 0)
|
|
28
|
+
return _jsx("p", { className: slot("empty"), children: messages.admin.requests.empty });
|
|
29
|
+
return (_jsx("ul", { className: slot("root"), "aria-label": messages.admin.requests.title, children: requests.map((row) => (_jsx(RequestItem, { row: row, grantAction: grantAction, dismissAction: dismissAction, messages: messages, LinkComponent: LinkComponent, slot: slot, unstyled: unstyled }, row.id))) }));
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=payment-requests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-requests.js","sourceRoot":"","sources":["../../src/ui/payment-requests.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Locale } from "@softure-ai/core";
|
|
2
|
+
import { type ClassNames, type LinkComponentType } from "@softure-ai/ui";
|
|
3
|
+
import type { Plan } from "../contract.js";
|
|
4
|
+
import type { BillingMessages } from "../messages/index.js";
|
|
5
|
+
export type PricingTilesSlot = "root" | "tile" | "badge" | "name" | "description" | "priceRow" | "price" | "period" | "features" | "feature" | "featureIcon" | "action";
|
|
6
|
+
export interface PricingTilesProps {
|
|
7
|
+
readonly plans: readonly Plan[];
|
|
8
|
+
readonly messages: BillingMessages;
|
|
9
|
+
readonly locale: Locale;
|
|
10
|
+
/** Where a tile's button leads, e.g. the payment page with the plan; no button when omitted. */
|
|
11
|
+
readonly getPlanHref?: (plan: Plan) => string;
|
|
12
|
+
/** The plan already chosen: its tile is marked `aria-current` and has no button. */
|
|
13
|
+
readonly selectedPlanId?: string;
|
|
14
|
+
/** Renders the buttons; a plain `<a>` when omitted. */
|
|
15
|
+
readonly LinkComponent?: LinkComponentType;
|
|
16
|
+
/** Names the list of plans for assistive technology. */
|
|
17
|
+
readonly label?: string;
|
|
18
|
+
readonly classNames?: ClassNames<PricingTilesSlot>;
|
|
19
|
+
readonly unstyled?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function PricingTiles({ plans, messages, locale, getPlanHref, selectedPlanId, LinkComponent, label, classNames, unstyled }: PricingTilesProps): import("react").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=pricing-tiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-tiles.d.ts","sourceRoot":"","sources":["../../src/ui/pricing-tiles.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAyB,KAAK,UAAU,EAAqC,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnI,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAK5D,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;AAExK,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gGAAgG;IAChG,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;IAC9C,oFAAoF;IACpF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAC3C,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC,CAAC;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAsBD,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,iBAAiB,+BAuDnJ"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// The plans of `billing({ plans })` as tiles: name, price, period, description, feature lines and a
|
|
3
|
+
// button to choose the plan. Server-safe and framework-free: it renders from props, and the button
|
|
4
|
+
// goes through an injected `LinkComponent` (`Pricing` and `PaymentPage` in `/next` wire it).
|
|
5
|
+
import { formatMessage } from "@softure-ai/core";
|
|
6
|
+
import { ButtonLink, CheckIcon, createSlotClassGetter, EmptyState } from "@softure-ai/ui";
|
|
7
|
+
import { getLocalizedText } from "../plans.js";
|
|
8
|
+
import { formatPrice } from "../price.js";
|
|
9
|
+
import { formatPeriod } from "./format.js";
|
|
10
|
+
const TILE_CLASS = "sft:flex sft:flex-col sft:gap-3 sft:rounded-card sft:border sft:bg-surface sft:p-5 sft:font-sans";
|
|
11
|
+
const DEFAULT_CLASSES = {
|
|
12
|
+
root: "sft:m-0 sft:flex sft:list-none sft:flex-col sft:gap-4 sft:p-0",
|
|
13
|
+
tile: `${TILE_CLASS} sft:border-border`,
|
|
14
|
+
badge: "sft:m-0 sft:w-fit sft:rounded-full sft:bg-accent-fill sft:px-2.5 sft:py-1 sft:text-xs sft:font-medium sft:text-on-accent",
|
|
15
|
+
name: "sft:m-0 sft:font-heading sft:text-lg sft:font-semibold sft:text-foreground",
|
|
16
|
+
description: "sft:m-0 sft:text-sm sft:text-muted",
|
|
17
|
+
priceRow: "sft:m-0 sft:flex sft:items-baseline sft:gap-2",
|
|
18
|
+
price: "sft:text-2xl sft:font-bold sft:tabular-nums sft:text-foreground",
|
|
19
|
+
period: "sft:text-sm sft:text-muted",
|
|
20
|
+
features: "sft:m-0 sft:flex sft:list-none sft:flex-col sft:gap-1.5 sft:p-0 sft:text-sm sft:text-foreground",
|
|
21
|
+
feature: "sft:flex sft:items-start sft:gap-2",
|
|
22
|
+
featureIcon: "sft:mt-0.5 sft:size-4 sft:shrink-0 sft:text-success",
|
|
23
|
+
action: "sft:flex",
|
|
24
|
+
};
|
|
25
|
+
/** A featured or chosen tile stands out with a stronger border and a shadow. */
|
|
26
|
+
const PROMINENT_CLASSES = { ...DEFAULT_CLASSES, tile: `${TILE_CLASS} sft:border-border-strong sft:shadow-2` };
|
|
27
|
+
export function PricingTiles({ plans, messages, locale, getPlanHref, selectedPlanId, LinkComponent, label, classNames, unstyled }) {
|
|
28
|
+
if (plans.length === 0)
|
|
29
|
+
return _jsx(EmptyState, { title: messages.pricing.empty, unstyled: unstyled });
|
|
30
|
+
const regular = createSlotClassGetter({ defaults: DEFAULT_CLASSES, classNames, unstyled });
|
|
31
|
+
const prominent = createSlotClassGetter({ defaults: PROMINENT_CLASSES, classNames, unstyled });
|
|
32
|
+
return (_jsx("ul", { className: regular("root"), "aria-label": label, children: plans.map((plan) => {
|
|
33
|
+
const name = getLocalizedText(plan.name, locale);
|
|
34
|
+
const isSelected = plan.id === selectedPlanId;
|
|
35
|
+
const href = isSelected ? undefined : getPlanHref?.(plan);
|
|
36
|
+
const slot = plan.isFeatured || isSelected ? prominent : regular;
|
|
37
|
+
return (_jsxs("li", { className: slot("tile"), "data-plan": plan.id, "data-featured": plan.isFeatured ? "true" : undefined, "aria-current": isSelected ? "true" : undefined, children: [plan.isFeatured ? _jsx("p", { className: slot("badge"), children: messages.pricing.featured }) : null, _jsx("h3", { className: slot("name"), children: name }), _jsxs("p", { className: slot("priceRow"), children: [_jsx("span", { className: slot("price"), children: formatPrice(plan.price, locale) }), _jsx("span", { className: slot("period"), children: formatPeriod(plan.period, locale, messages) })] }), plan.description === undefined ? null : _jsx("p", { className: slot("description"), children: getLocalizedText(plan.description, locale) }), plan.features.length === 0 ? null : (_jsx("ul", { className: slot("features"), children: plan.features.map((feature, index) => (_jsxs("li", { className: slot("feature"), children: [_jsx(CheckIcon, { className: slot("featureIcon") }), _jsx("span", { children: getLocalizedText(feature, locale) })] }, index))) })), href === undefined ? null : (_jsx("div", { className: slot("action"), children: _jsx(ButtonLink, { href: href, LinkComponent: LinkComponent, variant: plan.isFeatured ? "primary" : "secondary", fullWidth: true, unstyled: unstyled, children: formatMessage(messages.pricing.choose, { plan: name }) }) }))] }, plan.id));
|
|
38
|
+
}) }));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=pricing-tiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-tiles.js","sourceRoot":"","sources":["../../src/ui/pricing-tiles.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- Entitlements: at most one row per account, apart from auth.users. An account without a row is on
|
|
2
|
+
-- the trial that starts at its auth.users.created_at (computed by the module, never stored), so a
|
|
3
|
+
-- row exists only once something changed: a grant, a revoke or a trial extension.
|
|
4
|
+
-- Rollback: DROP TABLE billing.entitlements; then
|
|
5
|
+
-- DELETE FROM softure.migrations WHERE module = 'billing' AND version = 1;
|
|
6
|
+
CREATE TABLE entitlements (
|
|
7
|
+
user_id uuid PRIMARY KEY REFERENCES auth.users (id) ON DELETE CASCADE,
|
|
8
|
+
trial_ends_at timestamptz NOT NULL,
|
|
9
|
+
-- NULL: never paid, or revoked. Lifetime access has no end, so it is a flag, not a date.
|
|
10
|
+
paid_until timestamptz,
|
|
11
|
+
is_lifetime boolean NOT NULL DEFAULT false,
|
|
12
|
+
created_at timestamptz NOT NULL,
|
|
13
|
+
updated_at timestamptz NOT NULL,
|
|
14
|
+
CONSTRAINT entitlements_lifetime_without_end CHECK (NOT (is_lifetime AND paid_until IS NOT NULL)),
|
|
15
|
+
CONSTRAINT entitlements_updated_after_created CHECK (updated_at >= created_at)
|
|
16
|
+
);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-- Payments taken by a provider (Stripe Checkout): one row per paid checkout, written in the same
|
|
2
|
+
-- transaction as the plan grant it caused, so a webhook delivered twice (or two events for one
|
|
3
|
+
-- checkout) grants once. A full refund flips the row to `refunded` with a conditional update, so
|
|
4
|
+
-- the paid access it gave is revoked once.
|
|
5
|
+
-- Rollback: DROP TABLE billing.payments; then
|
|
6
|
+
-- DELETE FROM softure.migrations WHERE module = 'billing' AND version = 2;
|
|
7
|
+
CREATE TABLE payments (
|
|
8
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
9
|
+
user_id uuid NOT NULL REFERENCES auth.users (id) ON DELETE CASCADE,
|
|
10
|
+
-- The adapter's name, e.g. `stripe`.
|
|
11
|
+
provider text NOT NULL CHECK (provider ~ '^[a-z][a-z0-9-]*$' AND length(provider) <= 32),
|
|
12
|
+
-- The provider's checkout id (a Stripe Checkout Session, `cs_...`).
|
|
13
|
+
checkout_id text NOT NULL CHECK (length(checkout_id) BETWEEN 1 AND 255),
|
|
14
|
+
-- The provider's payment id that refunds name (a Stripe PaymentIntent, `pi_...`); NULL when the
|
|
15
|
+
-- provider gave none (a free checkout).
|
|
16
|
+
payment_id text CHECK (length(payment_id) BETWEEN 1 AND 255),
|
|
17
|
+
plan_id text NOT NULL CHECK (length(plan_id) BETWEEN 1 AND 64),
|
|
18
|
+
-- What the provider charged, in the currency's minor unit.
|
|
19
|
+
amount bigint NOT NULL CHECK (amount >= 0),
|
|
20
|
+
currency text NOT NULL CHECK (currency ~ '^[A-Z]{3}$'),
|
|
21
|
+
status text NOT NULL CHECK (status IN ('paid', 'refunded')),
|
|
22
|
+
paid_at timestamptz NOT NULL,
|
|
23
|
+
refunded_at timestamptz,
|
|
24
|
+
CONSTRAINT payments_checkout_once UNIQUE (provider, checkout_id),
|
|
25
|
+
CONSTRAINT payments_payment_once UNIQUE (provider, payment_id),
|
|
26
|
+
CONSTRAINT payments_refunded_at_with_status CHECK ((status = 'refunded') = (refunded_at IS NOT NULL)),
|
|
27
|
+
CONSTRAINT payments_refunded_after_paid CHECK (refunded_at IS NULL OR refunded_at >= paid_at)
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE INDEX payments_user_id ON payments (user_id);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- What each provider payment granted, so a full refund takes back only that: a paid period (its
|
|
2
|
+
-- start and end) or lifetime access. Rows recorded before this migration keep NULL and a refund of
|
|
3
|
+
-- them revokes paid access as before. Lifetime access now keeps the dated end beside it, so a
|
|
4
|
+
-- refunded lifetime falls back to the periods bought next to it.
|
|
5
|
+
-- Rollback: ALTER TABLE billing.payments DROP CONSTRAINT payments_grant_shape,
|
|
6
|
+
-- DROP COLUMN grant_kind, DROP COLUMN granted_from, DROP COLUMN granted_until;
|
|
7
|
+
-- UPDATE billing.entitlements SET paid_until = NULL WHERE is_lifetime;
|
|
8
|
+
-- ALTER TABLE billing.entitlements ADD CONSTRAINT entitlements_lifetime_without_end
|
|
9
|
+
-- CHECK (NOT (is_lifetime AND paid_until IS NOT NULL)); then
|
|
10
|
+
-- DELETE FROM softure.migrations WHERE module = 'billing' AND version = 3;
|
|
11
|
+
ALTER TABLE entitlements DROP CONSTRAINT entitlements_lifetime_without_end;
|
|
12
|
+
|
|
13
|
+
ALTER TABLE payments
|
|
14
|
+
-- `period` or `lifetime`; NULL for a payment recorded before grants were stored.
|
|
15
|
+
ADD COLUMN grant_kind text CHECK (grant_kind IN ('period', 'lifetime')),
|
|
16
|
+
-- The paid period the payment added: from where access ended (or the payment's instant) to
|
|
17
|
+
-- the period's end. Both NULL unless `grant_kind` is `period`.
|
|
18
|
+
ADD COLUMN granted_from timestamptz,
|
|
19
|
+
ADD COLUMN granted_until timestamptz,
|
|
20
|
+
ADD CONSTRAINT payments_grant_shape CHECK (
|
|
21
|
+
CASE grant_kind
|
|
22
|
+
WHEN 'period' THEN granted_from IS NOT NULL AND granted_until IS NOT NULL AND granted_until > granted_from
|
|
23
|
+
ELSE granted_from IS NULL AND granted_until IS NULL
|
|
24
|
+
END
|
|
25
|
+
);
|