@usethrottle/auth 0.7.0 → 0.9.0

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/dist/index.d.cts CHANGED
@@ -164,6 +164,18 @@ interface Invoice {
164
164
  sourceType: string | null;
165
165
  /** Frozen at issue — the lines actually billed, not the order's lines today. */
166
166
  lineItems: InvoiceLineItem[];
167
+ /**
168
+ * Set when the invoice bills less than the order: the order total its lines
169
+ * add up to. `total` is then the amount due (Net-N invoice) or the amount
170
+ * paid (a deposit receipt). Null when the invoice bills the whole order.
171
+ */
172
+ orderTotal: number | null;
173
+ /** Net-N invoices: paid on the order before this invoice (e.g. a deposit). */
174
+ amountPaid: number | null;
175
+ /** Net-N invoices: waived by a comp. */
176
+ compWaived: number | null;
177
+ /** Deposit receipts: the balance still due, billed on the Net-N invoice. */
178
+ balanceDue: number | null;
167
179
  /** Resolved on the detail read only; null on list rows and when the hop fails. */
168
180
  orderId: string | null;
169
181
  orderNumber: string | null;
@@ -180,6 +192,21 @@ interface Subscription {
180
192
  totalPayments: number | null;
181
193
  paymentsMade: number;
182
194
  completedAt: string | null;
195
+ /** Installment plans only: every payment in order; dueAt is an estimate. */
196
+ paymentSchedule?: Array<{
197
+ index: number;
198
+ amount: number;
199
+ discount: number;
200
+ net: number;
201
+ intervalUnit: string | null;
202
+ intervalCount: number | null;
203
+ status: 'paid' | 'due' | 'upcoming';
204
+ dueAt: string | null;
205
+ }> | null;
206
+ /** Installment plans only: the sum of every payment's net amount. */
207
+ scheduleTotal?: number | null;
208
+ /** Installment plans only: what the next payment will charge; null once complete. */
209
+ nextPaymentAmount?: number | null;
183
210
  amount: number;
184
211
  quantity: number;
185
212
  currency: string;
package/dist/index.d.ts CHANGED
@@ -164,6 +164,18 @@ interface Invoice {
164
164
  sourceType: string | null;
165
165
  /** Frozen at issue — the lines actually billed, not the order's lines today. */
166
166
  lineItems: InvoiceLineItem[];
167
+ /**
168
+ * Set when the invoice bills less than the order: the order total its lines
169
+ * add up to. `total` is then the amount due (Net-N invoice) or the amount
170
+ * paid (a deposit receipt). Null when the invoice bills the whole order.
171
+ */
172
+ orderTotal: number | null;
173
+ /** Net-N invoices: paid on the order before this invoice (e.g. a deposit). */
174
+ amountPaid: number | null;
175
+ /** Net-N invoices: waived by a comp. */
176
+ compWaived: number | null;
177
+ /** Deposit receipts: the balance still due, billed on the Net-N invoice. */
178
+ balanceDue: number | null;
167
179
  /** Resolved on the detail read only; null on list rows and when the hop fails. */
168
180
  orderId: string | null;
169
181
  orderNumber: string | null;
@@ -180,6 +192,21 @@ interface Subscription {
180
192
  totalPayments: number | null;
181
193
  paymentsMade: number;
182
194
  completedAt: string | null;
195
+ /** Installment plans only: every payment in order; dueAt is an estimate. */
196
+ paymentSchedule?: Array<{
197
+ index: number;
198
+ amount: number;
199
+ discount: number;
200
+ net: number;
201
+ intervalUnit: string | null;
202
+ intervalCount: number | null;
203
+ status: 'paid' | 'due' | 'upcoming';
204
+ dueAt: string | null;
205
+ }> | null;
206
+ /** Installment plans only: the sum of every payment's net amount. */
207
+ scheduleTotal?: number | null;
208
+ /** Installment plans only: what the next payment will charge; null once complete. */
209
+ nextPaymentAmount?: number | null;
183
210
  amount: number;
184
211
  quantity: number;
185
212
  currency: string;
@@ -1209,6 +1209,12 @@ var enUS = {
1209
1209
  viewSubscription: "View subscription",
1210
1210
  payButton: "Pay this invoice",
1211
1211
  billedTo: "Billed to",
1212
+ /** Shown when an invoice bills less than the order, matching the PDF. */
1213
+ orderTotal: "Order total",
1214
+ amountPaid: "Amount paid",
1215
+ waived: "Waived",
1216
+ amountDue: "Amount due",
1217
+ balanceDue: "Balance due",
1212
1218
  /** Display copy for `invoice.status` — the wire values are paid|open|void. */
1213
1219
  statusLabels: { paid: "Paid", open: "Open", void: "Void" },
1214
1220
  downloadUnavailable: "This invoice is not available to download right now."
@@ -1228,6 +1234,11 @@ var enUS = {
1228
1234
  cancelledOn: "Cancelled on",
1229
1235
  trialEnds: "Trial ends",
1230
1236
  installmentProgress: "Payment {paid} of {total}",
1237
+ installmentTotal: "{amount} total",
1238
+ installmentNext: "Next {amount} on {date}",
1239
+ /** Spec §5: a varied schedule's dated list; dates are estimates, hence "~". */
1240
+ upcomingPayments: "Upcoming payments",
1241
+ upcomingPayment: "{amount} \xB7 ~{date}",
1231
1242
  cancelButton: "Cancel",
1232
1243
  cancelAtPeriodEnd: "Cancel at period end",
1233
1244
  cancelNow: "Cancel immediately",
@@ -4219,6 +4230,9 @@ function InvoiceDetail(props) {
4219
4230
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PanelState, { resource, isEmpty: (i) => i === null, emptyTitle: t.invoices.empty, skeletonRows: 4, children: (invoice) => {
4220
4231
  const money = (v) => formatMoney(v, invoice.currency, locale);
4221
4232
  const lines = invoice.lineItems ?? [];
4233
+ const partOfOrder = invoice.orderTotal != null;
4234
+ const isDepositReceipt = partOfOrder && invoice.balanceDue != null;
4235
+ const headlineLabel = !partOfOrder ? t.invoices.total : isDepositReceipt ? t.invoices.amountPaid : t.invoices.amountDue;
4222
4236
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ...a.el("invoiceDetail.layout", "throttle-detail"), children: [
4223
4237
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ...a.el("invoiceDetail.main", "throttle-detail__main"), children: [
4224
4238
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "throttle-detail__section", children: [
@@ -4252,10 +4266,14 @@ function InvoiceDetail(props) {
4252
4266
  ] }),
4253
4267
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("aside", { ...a.el("invoiceDetail.rail", "throttle-detail__rail"), children: [
4254
4268
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "throttle-detail__section", children: [
4255
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "throttle-detail__label", children: t.invoices.total }),
4269
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "throttle-detail__label", children: headlineLabel }),
4256
4270
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "throttle-detail__headline", children: money(invoice.total) })
4257
4271
  ] }),
4258
4272
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ...a.el("invoiceDetail.totals", "throttle-totals"), children: [
4273
+ partOfOrder ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.orderTotal, value: money(invoice.orderTotal) }) : null,
4274
+ partOfOrder && invoice.amountPaid ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.amountPaid, value: `-${money(invoice.amountPaid)}` }) : null,
4275
+ partOfOrder && invoice.compWaived ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.waived, value: `-${money(invoice.compWaived)}` }) : null,
4276
+ isDepositReceipt && invoice.balanceDue ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.balanceDue, value: money(invoice.balanceDue) }) : null,
4259
4277
  invoice.dueAt ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.due, value: formatDate(invoice.dueAt, locale) }) : null,
4260
4278
  invoice.periodStart && invoice.periodEnd ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4261
4279
  Line2,
@@ -4414,6 +4432,18 @@ function isIntervalUnit(value) {
4414
4432
  return typeof value === "string" && INTERVAL_UNITS.includes(value);
4415
4433
  }
4416
4434
 
4435
+ // ../core-cadence/src/schedule.ts
4436
+ function isVariedSchedule(rows) {
4437
+ if (!rows || rows.length === 0) return false;
4438
+ return rows.some(
4439
+ (r, i) => r.discount !== 0 || r.amount !== rows[0].amount || i > 1 && (r.intervalUnit !== rows[1].intervalUnit || r.intervalCount !== rows[1].intervalCount)
4440
+ );
4441
+ }
4442
+ function upcomingSchedulePayments(rows) {
4443
+ if (!rows || !isVariedSchedule(rows)) return [];
4444
+ return rows.filter((r) => r.status !== "paid" && r.dueAt != null);
4445
+ }
4446
+
4417
4447
  // ../core-cadence/src/labels.ts
4418
4448
  var NAMED_NOUN = {
4419
4449
  weekly: "week",
@@ -4429,6 +4459,10 @@ function cadenceNoun(cadence) {
4429
4459
  }
4430
4460
  return cadence.interval;
4431
4461
  }
4462
+ function scheduleDeal(sub) {
4463
+ if (!sub.paymentSchedule || sub.scheduleTotal == null || !isVariedSchedule(sub.paymentSchedule)) return null;
4464
+ return { total: sub.scheduleTotal, payments: sub.paymentSchedule.length };
4465
+ }
4432
4466
 
4433
4467
  // src/react/components/account/SubscriptionsPanel.tsx
4434
4468
  var import_jsx_runtime43 = require("react/jsx-runtime");
@@ -4455,7 +4489,20 @@ function SubscriptionsPanel(props) {
4455
4489
  await run(fn);
4456
4490
  })();
4457
4491
  };
4458
- const priceLabel = (sub) => `${formatMoney(sub.amount, sub.currency, locale)} / ${cadenceNoun(sub)}${sub.quantity > 1 ? ` \xD7 ${sub.quantity}` : ""}`;
4492
+ const priceLabel = (sub) => {
4493
+ const deal = scheduleDeal(sub);
4494
+ return deal ? t.subscriptions.installmentTotal.replace("{amount}", formatMoney(deal.total, sub.currency, locale)) : `${formatMoney(sub.amount, sub.currency, locale)} / ${cadenceNoun(sub)}${sub.quantity > 1 ? ` \xD7 ${sub.quantity}` : ""}`;
4495
+ };
4496
+ const nextPaymentLabel = (sub) => {
4497
+ if (!isVariedSchedule(sub.paymentSchedule) || !sub.paymentSchedule || sub.nextPaymentAmount == null) return null;
4498
+ const upcoming = sub.paymentSchedule.find((r) => r.status !== "paid");
4499
+ return t.subscriptions.installmentNext.replace("{amount}", formatMoney(sub.nextPaymentAmount, sub.currency, locale)).replace("{date}", formatDate(upcoming?.dueAt ?? sub.currentPeriodEnd, locale));
4500
+ };
4501
+ const upcomingList = (sub) => {
4502
+ const upcoming = upcomingSchedulePayments(sub.paymentSchedule);
4503
+ if (upcoming.length === 0) return null;
4504
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { className: "throttle-muted", "aria-label": t.subscriptions.upcomingPayments, children: upcoming.map((r) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: t.subscriptions.upcomingPayment.replace("{amount}", formatMoney(r.net, sub.currency, locale)).replace("{date}", formatDate(r.dueAt, locale)) }, r.dueAt)) });
4505
+ };
4459
4506
  const renewsLabel = (sub) => formatDate(
4460
4507
  sub.status === "completed" ? sub.completedAt ?? sub.currentPeriodEnd : sub.status === "cancelled" ? sub.cancelledAt ?? sub.currentPeriodEnd : sub.currentPeriodEnd,
4461
4508
  locale
@@ -4537,7 +4584,9 @@ function SubscriptionsPanel(props) {
4537
4584
  columns: [
4538
4585
  { key: "plan", label: t.subscriptions.columnPlan, render: (sub) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
4539
4586
  sub.planName ?? sub.planReference,
4540
- sub.totalPayments != null ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: t.subscriptions.installmentProgress.replace("{paid}", String(Math.min(sub.paymentsMade ?? 0, sub.totalPayments))).replace("{total}", String(sub.totalPayments)) }) : null
4587
+ sub.totalPayments != null ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: t.subscriptions.installmentProgress.replace("{paid}", String(Math.min(sub.paymentsMade ?? 0, sub.totalPayments))).replace("{total}", String(sub.totalPayments)) }) : null,
4588
+ nextPaymentLabel(sub) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: nextPaymentLabel(sub) }) : null,
4589
+ upcomingList(sub)
4541
4590
  ] }) },
4542
4591
  { key: "price", label: t.subscriptions.columnPrice, render: (sub) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "throttle-table__money", children: priceLabel(sub) }) },
4543
4592
  { key: "renews", label: t.subscriptions.columnRenews, render: (sub) => renewsLabel(sub) },
@@ -4555,12 +4604,9 @@ function SubscriptionsPanel(props) {
4555
4604
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StatusBadge, { status: sub.status, labels: t.subscriptions.statusLabels })
4556
4605
  ] }),
4557
4606
  sub.totalPayments != null ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: t.subscriptions.installmentProgress.replace("{paid}", String(Math.min(sub.paymentsMade ?? 0, sub.totalPayments))).replace("{total}", String(sub.totalPayments)) }) : null,
4558
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "throttle-muted", children: [
4559
- formatMoney(sub.amount, sub.currency, locale),
4560
- " / ",
4561
- cadenceNoun(sub),
4562
- sub.quantity > 1 ? ` \xD7 ${sub.quantity}` : ""
4563
- ] }),
4607
+ nextPaymentLabel(sub) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: nextPaymentLabel(sub) }) : null,
4608
+ upcomingList(sub),
4609
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "throttle-muted", children: priceLabel(sub) }),
4564
4610
  sub.status === "completed" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "throttle-muted", children: [
4565
4611
  t.subscriptions.statusLabels.completed,
4566
4612
  " ",