@usethrottle/quotes 0.5.0 → 0.7.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
@@ -27,6 +27,16 @@ interface QuoteItemRecurring {
27
27
  totalPayments: number | null;
28
28
  /** 0 when there is no free trial. A free-trial line charges nothing at acceptance. */
29
29
  trialDays: number;
30
+ /**
31
+ * Custom installment schedule: payments that differ in amount (per unit, minor
32
+ * units) and in the gap before each one. Present only on a schedule line, where
33
+ * `totalPayments` equals its length. Row 0 has no gap.
34
+ */
35
+ schedule?: Array<{
36
+ amount: number;
37
+ intervalUnit: string | null;
38
+ intervalCount: number | null;
39
+ }>;
30
40
  }
31
41
  interface QuoteItem {
32
42
  id: string;
@@ -123,6 +133,8 @@ interface RequestFormConfig {
123
133
  fields: {
124
134
  companyName?: boolean;
125
135
  phone?: boolean;
136
+ /** Show an optional shipping address section. */
137
+ shippingAddress?: boolean;
126
138
  buyerReference?: boolean;
127
139
  lineItems?: boolean;
128
140
  targetPrice?: boolean;
@@ -164,6 +176,19 @@ interface SubmitQuoteRequestInput {
164
176
  companyName?: string | null;
165
177
  phone?: string | null;
166
178
  buyerReference?: string | null;
179
+ /**
180
+ * Optional. All blank = no address; otherwise `addressLine1`, `city` and a
181
+ * 2-letter `countryCode` are required. Stored on the quote and prefilled
182
+ * into checkout when the buyer accepts.
183
+ */
184
+ shippingAddress?: {
185
+ addressLine1?: string | null;
186
+ addressLine2?: string | null;
187
+ city?: string | null;
188
+ stateProvince?: string | null;
189
+ postalCode?: string | null;
190
+ countryCode?: string | null;
191
+ } | null;
167
192
  /** Honeypot — leave empty. The component wires this for you. */
168
193
  website?: string | null;
169
194
  /** Client mount time in ms; the API enforces a minimum fill duration. */
package/dist/index.d.ts CHANGED
@@ -27,6 +27,16 @@ interface QuoteItemRecurring {
27
27
  totalPayments: number | null;
28
28
  /** 0 when there is no free trial. A free-trial line charges nothing at acceptance. */
29
29
  trialDays: number;
30
+ /**
31
+ * Custom installment schedule: payments that differ in amount (per unit, minor
32
+ * units) and in the gap before each one. Present only on a schedule line, where
33
+ * `totalPayments` equals its length. Row 0 has no gap.
34
+ */
35
+ schedule?: Array<{
36
+ amount: number;
37
+ intervalUnit: string | null;
38
+ intervalCount: number | null;
39
+ }>;
30
40
  }
31
41
  interface QuoteItem {
32
42
  id: string;
@@ -123,6 +133,8 @@ interface RequestFormConfig {
123
133
  fields: {
124
134
  companyName?: boolean;
125
135
  phone?: boolean;
136
+ /** Show an optional shipping address section. */
137
+ shippingAddress?: boolean;
126
138
  buyerReference?: boolean;
127
139
  lineItems?: boolean;
128
140
  targetPrice?: boolean;
@@ -164,6 +176,19 @@ interface SubmitQuoteRequestInput {
164
176
  companyName?: string | null;
165
177
  phone?: string | null;
166
178
  buyerReference?: string | null;
179
+ /**
180
+ * Optional. All blank = no address; otherwise `addressLine1`, `city` and a
181
+ * 2-letter `countryCode` are required. Stored on the quote and prefilled
182
+ * into checkout when the buyer accepts.
183
+ */
184
+ shippingAddress?: {
185
+ addressLine1?: string | null;
186
+ addressLine2?: string | null;
187
+ city?: string | null;
188
+ stateProvince?: string | null;
189
+ postalCode?: string | null;
190
+ countryCode?: string | null;
191
+ } | null;
167
192
  /** Honeypot — leave empty. The component wires this for you. */
168
193
  website?: string | null;
169
194
  /** Client mount time in ms; the API enforces a minimum fill duration. */
package/dist/index.js CHANGED
@@ -543,6 +543,11 @@ function isIntervalUnit(value) {
543
543
  return typeof value === "string" && INTERVAL_UNITS.includes(value);
544
544
  }
545
545
 
546
+ // ../core-cadence/src/schedule.ts
547
+ function scheduleUnitTotal(schedule) {
548
+ return schedule.reduce((sum, row2) => sum + row2.amount, 0);
549
+ }
550
+
546
551
  // ../core-cadence/src/labels.ts
547
552
  var NAMED_NOUN = {
548
553
  weekly: "week",
@@ -558,7 +563,12 @@ function cadenceNoun(cadence) {
558
563
  }
559
564
  return cadence.interval;
560
565
  }
561
- function recurringTermsLabel(terms, each) {
566
+ function recurringTermsLabel(terms, price, money) {
567
+ const quantity = price.quantity ?? 1;
568
+ if (terms.schedule && terms.schedule.length > 0) {
569
+ return `${money(scheduleUnitTotal(terms.schedule) * quantity)} total \xB7 ${terms.schedule.length} payments`;
570
+ }
571
+ const each = money(price.unitPrice * quantity);
562
572
  const noun = cadenceNoun(terms);
563
573
  const trialDays = terms.trialDays ?? 0;
564
574
  if (trialDays > 0) return `Free for ${trialDays} day${trialDays === 1 ? "" : "s"}, then ${each} / ${noun}`;
@@ -647,7 +657,7 @@ function QuoteView({ token, options, onCheckout, loadingFallback, className }) {
647
657
  item.description ? /* @__PURE__ */ jsx("div", { style: muted, children: item.description }) : null,
648
658
  item.recurring ? /* @__PURE__ */ jsxs("div", { style: muted, children: [
649
659
  "Subscription \xB7 ",
650
- recurringTermsLabel(item.recurring, formatMoney(item.unitPrice * state.quantity, currency))
660
+ recurringTermsLabel(item.recurring, { unitPrice: item.unitPrice, quantity: state.quantity }, (m) => formatMoney(m, currency))
651
661
  ] }) : null
652
662
  ] }),
653
663
  /* @__PURE__ */ jsx("td", { align: "right", children: formatMoney(item.unitPrice, currency) }),
@@ -677,7 +687,7 @@ function QuoteView({ token, options, onCheckout, loadingFallback, className }) {
677
687
  recurringKept.map((i) => /* @__PURE__ */ jsxs("p", { style: muted, children: [
678
688
  i.name,
679
689
  ": ",
680
- recurringTermsLabel(i.recurring, formatMoney(i.unitPrice * (q.selections[i.id]?.quantity ?? i.quantity), currency))
690
+ recurringTermsLabel(i.recurring, { unitPrice: i.unitPrice, quantity: q.selections[i.id]?.quantity ?? i.quantity }, (m) => formatMoney(m, currency))
681
691
  ] }, i.id))
682
692
  ] }) : null,
683
693
  /* @__PURE__ */ jsx("p", { style: muted, children: termsLabel(rev.paymentTerms, rev.depositAmount, currency) }),
@@ -842,6 +852,12 @@ function QuoteRequestForm({
842
852
  companyName: "",
843
853
  phone: "",
844
854
  buyerReference: "",
855
+ addressLine1: "",
856
+ addressLine2: "",
857
+ city: "",
858
+ stateProvince: "",
859
+ postalCode: "",
860
+ countryCode: "",
845
861
  message: "",
846
862
  website: ""
847
863
  // honeypot
@@ -871,6 +887,16 @@ function QuoteRequestForm({
871
887
  companyName: fields.companyName ? values.companyName || null : null,
872
888
  phone: fields.phone ? values.phone || null : null,
873
889
  buyerReference: fields.buyerReference ? values.buyerReference || null : null,
890
+ ...fields.shippingAddress ? {
891
+ shippingAddress: {
892
+ addressLine1: values.addressLine1 || null,
893
+ addressLine2: values.addressLine2 || null,
894
+ city: values.city || null,
895
+ stateProvince: values.stateProvince || null,
896
+ postalCode: values.postalCode || null,
897
+ countryCode: values.countryCode || null
898
+ }
899
+ } : {},
874
900
  website: values.website || null,
875
901
  ...turnstileToken ? { turnstileToken } : {}
876
902
  }).then(() => onSubmitted?.()).catch(() => {
@@ -896,6 +922,33 @@ function QuoteRequestForm({
896
922
  "Phone",
897
923
  /* @__PURE__ */ jsx2("input", { value: values.phone, onChange: set("phone") })
898
924
  ] }) : null,
925
+ fields.shippingAddress ? /* @__PURE__ */ jsxs2("fieldset", { children: [
926
+ /* @__PURE__ */ jsx2("legend", { children: "Shipping address (optional)" }),
927
+ /* @__PURE__ */ jsxs2("label", { children: [
928
+ "Address line 1",
929
+ /* @__PURE__ */ jsx2("input", { value: values.addressLine1, onChange: set("addressLine1") })
930
+ ] }),
931
+ /* @__PURE__ */ jsxs2("label", { children: [
932
+ "Address line 2",
933
+ /* @__PURE__ */ jsx2("input", { value: values.addressLine2, onChange: set("addressLine2") })
934
+ ] }),
935
+ /* @__PURE__ */ jsxs2("label", { children: [
936
+ "City",
937
+ /* @__PURE__ */ jsx2("input", { value: values.city, onChange: set("city") })
938
+ ] }),
939
+ /* @__PURE__ */ jsxs2("label", { children: [
940
+ "State / province",
941
+ /* @__PURE__ */ jsx2("input", { value: values.stateProvince, onChange: set("stateProvince") })
942
+ ] }),
943
+ /* @__PURE__ */ jsxs2("label", { children: [
944
+ "Postal code",
945
+ /* @__PURE__ */ jsx2("input", { value: values.postalCode, onChange: set("postalCode") })
946
+ ] }),
947
+ /* @__PURE__ */ jsxs2("label", { children: [
948
+ "Country code (e.g. US)",
949
+ /* @__PURE__ */ jsx2("input", { value: values.countryCode, onChange: set("countryCode"), maxLength: 2 })
950
+ ] })
951
+ ] }) : null,
899
952
  fields.buyerReference ? /* @__PURE__ */ jsxs2("label", { children: [
900
953
  "Your reference #",
901
954
  /* @__PURE__ */ jsx2("input", { value: values.buyerReference, onChange: set("buyerReference") })