@mindbill/react 0.26.0 → 0.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,14 +8,14 @@ npm install @mindbill/react @mindbill/node
8
8
 
9
9
  ## Connected lifecycle
10
10
 
11
- `ConnectedBillLifecycle` starts after `BillSubmissionForm` atomically submits an immutable bill. It owns the submitted-to-closed progress rail, a read-only rendering of the exact submitted snapshot, server-owned human-readable history, packet download, EORs, payment posting, Second Bill Review, close, and reopen. The only persistent header action is **Download packet**; status-dependent actions open in a compact action sheet when MindBill makes them available.
11
+ `ConnectedBillLifecycle` starts after `BillSubmissionForm` atomically submits an immutable bill. Its only bill input is `billId`; `getSession` returns the short-lived token. The component fetches the submitted snapshot, progress, human-readable history, EOR/remittance amounts, payments, and available actions from MindBill. Do not pass lifecycle seed data or duplicate this state in the host app. The only persistent header action is **Download packet**; status-dependent actions open in a compact action sheet when MindBill makes them available.
12
12
 
13
13
  ```tsx
14
14
  import { ConnectedBillLifecycle } from "@mindbill/react";
15
15
 
16
16
  <ConnectedBillLifecycle
17
17
  billId={billId}
18
- sessionEndpoint="/api/mindbill/session"
18
+ getSession={getMindBillSession}
19
19
  appearance={{ preset: "qme-companion" }}
20
20
  />
21
21
  ```
package/dist/index.d.ts CHANGED
@@ -808,7 +808,6 @@ declare function BillPaymentLedger({ payments, appearance, className, style }: B
808
808
  type UseBillLifecycleOptions = BillLifecycleClientOptions & {
809
809
  refreshInterval?: number;
810
810
  enabled?: boolean;
811
- initialData?: BillLifecycleData | null;
812
811
  };
813
812
  type UseBillLifecycleResult = {
814
813
  billId: string;
@@ -830,7 +829,7 @@ type UseBillLifecycleResult = {
830
829
  resubmitBill: BillLifecycleClient["resubmitBill"];
831
830
  simulateSandbox: BillLifecycleClient["simulateSandbox"];
832
831
  };
833
- declare function useBillLifecycle({ billId: providedBillId, sessionEndpoint, getSession, apiBaseUrl, refreshInterval, enabled, initialData, fetch: fetchOverride, }: UseBillLifecycleOptions): UseBillLifecycleResult;
832
+ declare function useBillLifecycle({ billId: providedBillId, sessionEndpoint, getSession, apiBaseUrl, refreshInterval, enabled, fetch: fetchOverride, }: UseBillLifecycleOptions): UseBillLifecycleResult;
834
833
  type ConnectedBillLifecycleProps = UseBillLifecycleOptions & {
835
834
  appearance?: MindBillReactAppearance;
836
835
  className?: string;
package/dist/index.js CHANGED
@@ -3034,15 +3034,35 @@ function BillRemittanceCard({ remittance, appearance, className, style }) {
3034
3034
  ] }) }),
3035
3035
  /* @__PURE__ */ jsxs6("dl", { children: [
3036
3036
  /* @__PURE__ */ jsxs6("div", { children: [
3037
- /* @__PURE__ */ jsx6("dt", { children: "Payer reported" }),
3037
+ /* @__PURE__ */ jsx6("dt", { children: "Amount billed" }),
3038
+ /* @__PURE__ */ jsx6("dd", { children: currency(remittance.billedAmount) })
3039
+ ] }),
3040
+ /* @__PURE__ */ jsxs6("div", { children: [
3041
+ /* @__PURE__ */ jsx6("dt", { children: "Expected" }),
3042
+ /* @__PURE__ */ jsx6("dd", { children: currency(remittance.expectedAmount) })
3043
+ ] }),
3044
+ /* @__PURE__ */ jsxs6("div", { children: [
3045
+ /* @__PURE__ */ jsx6("dt", { children: "Payer allowed" }),
3046
+ /* @__PURE__ */ jsx6("dd", { children: remittance.payerAllowedAmount === null ? "\u2014" : currency(remittance.payerAllowedAmount) })
3047
+ ] }),
3048
+ /* @__PURE__ */ jsxs6("div", { children: [
3049
+ /* @__PURE__ */ jsx6("dt", { children: "Payer reported paid" }),
3038
3050
  /* @__PURE__ */ jsx6("dd", { children: remittance.payerReportedPaid === null ? "\u2014" : currency(remittance.payerReportedPaid) })
3039
3051
  ] }),
3040
3052
  /* @__PURE__ */ jsxs6("div", { children: [
3041
- /* @__PURE__ */ jsx6("dt", { children: "Posted" }),
3042
- /* @__PURE__ */ jsx6("dd", { children: currency(remittance.totalPaid) })
3053
+ /* @__PURE__ */ jsx6("dt", { children: "Payment posted" }),
3054
+ /* @__PURE__ */ jsx6("dd", { children: currency(remittance.postedPrincipal) })
3055
+ ] }),
3056
+ /* @__PURE__ */ jsxs6("div", { children: [
3057
+ /* @__PURE__ */ jsx6("dt", { children: "Penalty & interest" }),
3058
+ /* @__PURE__ */ jsx6("dd", { children: currency(remittance.postedAdditional) })
3043
3059
  ] }),
3044
3060
  /* @__PURE__ */ jsxs6("div", { children: [
3045
- /* @__PURE__ */ jsx6("dt", { children: "Balance" }),
3061
+ /* @__PURE__ */ jsx6("dt", { children: "Total received" }),
3062
+ /* @__PURE__ */ jsx6("dd", { children: currency(remittance.totalPostedCash) })
3063
+ ] }),
3064
+ /* @__PURE__ */ jsxs6("div", { children: [
3065
+ /* @__PURE__ */ jsx6("dt", { children: "Balance due" }),
3046
3066
  /* @__PURE__ */ jsx6("dd", { children: currency(remittance.balanceDue) })
3047
3067
  ] })
3048
3068
  ] }),
@@ -3078,28 +3098,59 @@ function BillPayerContactCard({ delivery, appearance, className, style }) {
3078
3098
  function BillPaymentLedger({ payments, appearance, className, style }) {
3079
3099
  return /* @__PURE__ */ jsxs6("section", { className: classes("mb-surface mb-payments", className), style: mindBillAppearanceStyle(appearance, style), "aria-label": "Payment ledger", children: [
3080
3100
  /* @__PURE__ */ jsx6("style", { children: lifecycleSurfaceStyles }),
3081
- /* @__PURE__ */ jsxs6("header", { className: "mb-surface-heading", children: [
3082
- /* @__PURE__ */ jsxs6("div", { children: [
3083
- /* @__PURE__ */ jsx6("strong", { children: "Payments" }),
3084
- /* @__PURE__ */ jsx6("span", { children: "Payments posted to this bill." })
3085
- ] }),
3086
- /* @__PURE__ */ jsx6("span", { children: payments.length })
3087
- ] }),
3088
- !payments.length ? /* @__PURE__ */ jsx6("p", { className: "mb-empty", children: "No payments posted." }) : /* @__PURE__ */ jsx6("div", { className: "mb-payment-list", children: payments.map((payment) => /* @__PURE__ */ jsxs6("article", { children: [
3089
- /* @__PURE__ */ jsxs6("div", { children: [
3090
- /* @__PURE__ */ jsx6("strong", { children: currency(payment.amount) }),
3091
- /* @__PURE__ */ jsxs6("span", { children: [
3092
- humanize(payment.status || "posted"),
3093
- " \xB7 ",
3094
- payment.method.toUpperCase()
3095
- ] })
3096
- ] }),
3097
- /* @__PURE__ */ jsxs6("div", { children: [
3098
- /* @__PURE__ */ jsx6("span", { children: payment.checkNumber ? `#${payment.checkNumber}` : payment.source.toUpperCase() }),
3099
- /* @__PURE__ */ jsx6("span", { children: payment.depositDate || defaultFormatDate(payment.postedAt) })
3100
- ] }),
3101
- payment.note ? /* @__PURE__ */ jsx6("p", { children: payment.note }) : null
3102
- ] }, payment.id)) })
3101
+ /* @__PURE__ */ jsx6("header", { className: "mb-surface-heading", children: /* @__PURE__ */ jsxs6("div", { children: [
3102
+ /* @__PURE__ */ jsx6("strong", { children: "Payments" }),
3103
+ /* @__PURE__ */ jsx6("span", { children: "Funds recorded against this bill." })
3104
+ ] }) }),
3105
+ !payments.length ? /* @__PURE__ */ jsx6("p", { className: "mb-empty", children: "No payments posted." }) : /* @__PURE__ */ jsx6("div", { className: "mb-payment-list", children: payments.map((payment) => {
3106
+ const additional = payment.feeAmount ?? 0;
3107
+ return /* @__PURE__ */ jsxs6("article", { children: [
3108
+ /* @__PURE__ */ jsxs6("div", { className: "mb-payment-amount", children: [
3109
+ /* @__PURE__ */ jsx6("strong", { children: currency(payment.amount) }),
3110
+ /* @__PURE__ */ jsx6("span", { children: "Total received" })
3111
+ ] }),
3112
+ /* @__PURE__ */ jsxs6("dl", { children: [
3113
+ /* @__PURE__ */ jsxs6("div", { children: [
3114
+ /* @__PURE__ */ jsx6("dt", { children: "Applied to bill" }),
3115
+ /* @__PURE__ */ jsx6("dd", { children: currency(payment.principalAmount) })
3116
+ ] }),
3117
+ additional > 0 ? /* @__PURE__ */ jsxs6("div", { children: [
3118
+ /* @__PURE__ */ jsx6("dt", { children: "Penalty & interest" }),
3119
+ /* @__PURE__ */ jsx6("dd", { children: currency(additional) })
3120
+ ] }) : null,
3121
+ /* @__PURE__ */ jsxs6("div", { children: [
3122
+ /* @__PURE__ */ jsx6("dt", { children: "Method" }),
3123
+ /* @__PURE__ */ jsx6("dd", { children: payment.method.toUpperCase() })
3124
+ ] }),
3125
+ /* @__PURE__ */ jsxs6("div", { children: [
3126
+ /* @__PURE__ */ jsx6("dt", { children: "Reference" }),
3127
+ /* @__PURE__ */ jsx6("dd", { children: payment.checkNumber || "\u2014" })
3128
+ ] }),
3129
+ /* @__PURE__ */ jsxs6("div", { children: [
3130
+ /* @__PURE__ */ jsx6("dt", { children: "Effective date" }),
3131
+ /* @__PURE__ */ jsx6("dd", { children: payment.receivedDate || payment.depositDate || defaultFormatDate(payment.postedAt) })
3132
+ ] }),
3133
+ /* @__PURE__ */ jsxs6("div", { children: [
3134
+ /* @__PURE__ */ jsx6("dt", { children: "Deposit date" }),
3135
+ /* @__PURE__ */ jsx6("dd", { children: payment.depositDate || "Not recorded" })
3136
+ ] }),
3137
+ /* @__PURE__ */ jsxs6("div", { children: [
3138
+ /* @__PURE__ */ jsx6("dt", { children: "Posted" }),
3139
+ /* @__PURE__ */ jsxs6("dd", { children: [
3140
+ defaultFormatDate(payment.postedAt),
3141
+ " \xB7 ",
3142
+ payment.source.toUpperCase()
3143
+ ] })
3144
+ ] }),
3145
+ /* @__PURE__ */ jsxs6("div", { children: [
3146
+ /* @__PURE__ */ jsx6("dt", { children: "Status" }),
3147
+ /* @__PURE__ */ jsx6("dd", { children: humanize(payment.status || "posted") })
3148
+ ] })
3149
+ ] }),
3150
+ payment.feeReason ? /* @__PURE__ */ jsx6("p", { children: payment.feeReason }) : null,
3151
+ payment.note ? /* @__PURE__ */ jsx6("p", { children: payment.note }) : null
3152
+ ] }, payment.id);
3153
+ }) })
3103
3154
  ] });
3104
3155
  }
3105
3156
  function classes(base, className) {
@@ -3118,9 +3169,9 @@ var lifecycleSurfaceStyles = `
3118
3169
  .mb-lifecycle-actions{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-start}.mb-lifecycle-action{display:grid;gap:5px;max-width:260px}.mb-action-button{appearance:none;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius,8px);background:var(--mb-surface);color:var(--mb-text);font:inherit;font-weight:700;line-height:1.2;padding:11px 15px;cursor:pointer}.mb-action-button:hover:not(:disabled){border-color:var(--mb-accent);color:var(--mb-accent)}.mb-action-button:focus-visible{outline:3px solid color-mix(in srgb,var(--mb-accent) 28%,transparent);outline-offset:2px}.mb-action-button.is-primary{background:var(--mb-accent);border-color:var(--mb-accent);color:var(--mb-accent-contrast)}.mb-action-button:disabled{cursor:not-allowed;opacity:.55}.mb-action-reason{color:var(--mb-muted);font-size:12px;line-height:1.35}
3119
3170
  .mb-activity-list{list-style:none;margin:0;padding:0}.mb-activity-item{display:grid;grid-template-columns:18px minmax(0,1fr);gap:12px;position:relative;padding:0 0 22px}.mb-activity-item:last-child{padding-bottom:0}.mb-activity-item:not(:last-child)::before{background:var(--mb-border);content:"";left:8px;position:absolute;top:10px;bottom:0;width:1px}.mb-activity-marker{background:var(--mb-surface);border:3px solid var(--mb-accent);border-radius:999px;height:11px;margin-top:4px;position:relative;width:11px;z-index:1}.mb-activity-content{display:grid;gap:4px;min-width:0}.mb-activity-content strong{font-size:15px;line-height:1.35}.mb-activity-content p{color:var(--mb-text);font-size:14px;line-height:1.5;margin:0}.mb-activity-content span,.mb-activity-empty{color:var(--mb-muted);font-size:13px;line-height:1.45}.mb-activity-empty,.mb-empty{margin:0}
3120
3171
  .mb-progress-list{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));list-style:none;margin:0;padding:0}.mb-progress-list li{display:grid;gap:7px;position:relative;text-align:center;color:var(--mb-muted);font-size:12px}.mb-progress-list li:not(:last-child)::after{content:"";position:absolute;left:calc(50% + 14px);right:calc(-50% + 14px);top:13px;height:2px;background:var(--mb-border)}.mb-progress-list li.is-complete:not(:last-child)::after{background:var(--mb-accent)}.mb-progress-list li>span{display:grid;place-items:center;justify-self:center;position:relative;z-index:1;width:28px;height:28px;border:2px solid var(--mb-border);border-radius:50%;background:var(--mb-surface);font-weight:800}.mb-progress-list li.is-complete>span,.mb-progress-list li.is-current>span{border-color:var(--mb-accent);background:var(--mb-accent);color:var(--mb-accent-contrast)}.mb-progress-list li.is-current{color:var(--mb-text)}
3121
- .mb-snapshot dl,.mb-remittance dl,.mb-contacts dl{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;margin:0}.mb-snapshot dl>div,.mb-remittance dl>div,.mb-contacts dl>div{display:grid;gap:3px;padding:10px 14px;border-left:1px solid var(--mb-border)}.mb-snapshot dl>div:nth-child(3n+1),.mb-remittance dl>div:first-child,.mb-contacts dl>div:first-child{border-left:0}.mb-snapshot dt,.mb-remittance dt,.mb-contacts dt{color:var(--mb-muted);font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.mb-snapshot dd,.mb-remittance dd,.mb-contacts dd{font-size:14px;font-weight:750;margin:0;overflow-wrap:anywhere}.mb-contacts a{color:var(--mb-accent)}.mb-denial{margin-top:16px;border-left:4px solid var(--mb-danger);border-radius:var(--mb-control-radius);background:color-mix(in srgb,var(--mb-danger) 8%,var(--mb-surface));padding:12px 14px}.mb-denial p{margin:4px 0 0}
3122
- .mb-payment-list{display:grid}.mb-payment-list article{display:grid;grid-template-columns:1fr auto;gap:5px 18px;padding:12px 0;border-top:1px solid var(--mb-border)}.mb-payment-list article:first-child{border-top:0}.mb-payment-list article>div{display:grid;gap:2px}.mb-payment-list article>div:nth-child(2){text-align:right}.mb-payment-list article span{color:var(--mb-muted);font-size:12px}.mb-payment-list article p{grid-column:1/-1;margin:0;color:var(--mb-muted);font-size:13px}
3123
- @media(max-width:700px){.mb-surface.mb-progress{padding:16px 10px}.mb-progress-list{grid-template-columns:repeat(4,minmax(0,1fr))}.mb-progress-list li{display:grid;grid-template-columns:1fr;align-items:start;gap:6px;text-align:center;font-size:10px;min-width:0}.mb-progress-list li b{font-size:10px;white-space:nowrap}.mb-progress-list li:not(:last-child)::after{left:calc(50% + 12px);right:calc(-50% + 12px);top:11px;bottom:auto;width:auto;height:2px}.mb-progress-list li>span{grid-row:auto;width:24px;height:24px;font-size:11px}.mb-snapshot dl,.mb-remittance dl,.mb-contacts dl{grid-template-columns:1fr 1fr}.mb-snapshot dl>div,.mb-remittance dl>div,.mb-contacts dl>div{border:0;border-top:1px solid var(--mb-border);padding:10px 0}.mb-snapshot dl>div:nth-child(-n+2),.mb-remittance dl>div:nth-child(-n+2),.mb-contacts dl>div:nth-child(-n+2){border-top:0}.mb-payment-list article{grid-template-columns:1fr}.mb-payment-list article>div:nth-child(2){text-align:left}}
3172
+ .mb-snapshot dl,.mb-remittance dl,.mb-contacts dl{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;margin:0}.mb-remittance dl{grid-template-columns:repeat(4,minmax(0,1fr));row-gap:1px;background:var(--mb-border)}.mb-snapshot dl>div,.mb-remittance dl>div,.mb-contacts dl>div{display:grid;gap:3px;padding:10px 14px;border-left:1px solid var(--mb-border)}.mb-remittance dl>div{border:0;background:var(--mb-surface)}.mb-snapshot dl>div:nth-child(3n+1),.mb-contacts dl>div:first-child{border-left:0}.mb-snapshot dt,.mb-remittance dt,.mb-contacts dt,.mb-payment-list dt{color:var(--mb-muted);font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.mb-snapshot dd,.mb-remittance dd,.mb-contacts dd,.mb-payment-list dd{font-size:14px;font-weight:750;margin:0;overflow-wrap:anywhere}.mb-contacts a{color:var(--mb-accent)}.mb-denial{margin-top:16px;border-left:4px solid var(--mb-danger);border-radius:var(--mb-control-radius);background:color-mix(in srgb,var(--mb-danger) 8%,var(--mb-surface));padding:12px 14px}.mb-denial p{margin:4px 0 0}
3173
+ .mb-payment-list{display:grid}.mb-payment-list article{display:grid;grid-template-columns:minmax(120px,.35fr) 1fr;gap:14px 24px;padding:16px 0;border-top:1px solid var(--mb-border)}.mb-payment-list article:first-child{border-top:0}.mb-payment-amount{display:grid;align-content:start;gap:2px}.mb-payment-amount strong{font-size:1.2rem}.mb-payment-list article>dl{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin:0}.mb-payment-list article>dl>div{display:grid;align-content:start;gap:3px}.mb-payment-list article span{color:var(--mb-muted);font-size:12px}.mb-payment-list article p{grid-column:1/-1;margin:0;color:var(--mb-muted);font-size:13px}
3174
+ @media(max-width:700px){.mb-surface.mb-progress{padding:16px 10px}.mb-progress-list{grid-template-columns:repeat(4,minmax(0,1fr))}.mb-progress-list li{display:grid;grid-template-columns:1fr;align-items:start;gap:6px;text-align:center;font-size:10px;min-width:0}.mb-progress-list li b{font-size:10px;white-space:nowrap}.mb-progress-list li:not(:last-child)::after{left:calc(50% + 12px);right:calc(-50% + 12px);top:11px;bottom:auto;width:auto;height:2px}.mb-progress-list li>span{grid-row:auto;width:24px;height:24px;font-size:11px}.mb-snapshot dl,.mb-remittance dl,.mb-contacts dl{grid-template-columns:1fr 1fr}.mb-snapshot dl>div,.mb-remittance dl>div,.mb-contacts dl>div{border:0;border-top:1px solid var(--mb-border);padding:10px 0}.mb-snapshot dl>div:nth-child(-n+2),.mb-remittance dl>div:nth-child(-n+2),.mb-contacts dl>div:nth-child(-n+2){border-top:0}.mb-payment-list article{grid-template-columns:1fr}.mb-payment-list article>dl{grid-template-columns:1fr 1fr}}
3124
3175
  `;
3125
3176
 
3126
3177
  // src/connected-bill-lifecycle.tsx
@@ -3139,15 +3190,6 @@ import {
3139
3190
  import { createBillLifecycleClient as createBillLifecycleClient2 } from "@mindbill/browser";
3140
3191
  import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
3141
3192
  var DEFAULT_REFRESH_INTERVAL2 = 6e4;
3142
- function downloadBlob(blob, filename) {
3143
- const url = URL.createObjectURL(blob);
3144
- const link = document.createElement("a");
3145
- link.href = url;
3146
- link.rel = "noopener noreferrer";
3147
- link.download = filename;
3148
- link.click();
3149
- window.setTimeout(() => URL.revokeObjectURL(url), 6e4);
3150
- }
3151
3193
  function reservePreviewWindow() {
3152
3194
  const preview = window.open("about:blank", "_blank");
3153
3195
  if (preview) preview.opener = null;
@@ -3165,6 +3207,15 @@ function previewBlob(blob, preview) {
3165
3207
  }
3166
3208
  window.setTimeout(() => URL.revokeObjectURL(url), 3e5);
3167
3209
  }
3210
+ async function openPdfFromUserGesture(loadPdf) {
3211
+ const preview = reservePreviewWindow();
3212
+ try {
3213
+ previewBlob(await loadPdf(), preview);
3214
+ } catch (error) {
3215
+ preview?.close();
3216
+ throw error;
3217
+ }
3218
+ }
3168
3219
  function useBillLifecycle({
3169
3220
  billId: providedBillId,
3170
3221
  sessionEndpoint = DEFAULT_SESSION_ENDPOINT2,
@@ -3172,12 +3223,11 @@ function useBillLifecycle({
3172
3223
  apiBaseUrl = DEFAULT_API_BASE_URL2,
3173
3224
  refreshInterval = DEFAULT_REFRESH_INTERVAL2,
3174
3225
  enabled = true,
3175
- initialData = null,
3176
3226
  fetch: fetchOverride
3177
3227
  }) {
3178
- const [data, setData] = useState6(initialData);
3228
+ const [data, setData] = useState6(null);
3179
3229
  const [error, setError] = useState6(null);
3180
- const [isLoading, setIsLoading] = useState6(enabled && !initialData);
3230
+ const [isLoading, setIsLoading] = useState6(enabled);
3181
3231
  const [isRefreshing, setIsRefreshing] = useState6(false);
3182
3232
  const [isMutating, setIsMutating] = useState6(false);
3183
3233
  const mounted = useRef4(true);
@@ -3189,9 +3239,10 @@ function useBillLifecycle({
3189
3239
  fetch: fetchOverride
3190
3240
  }), [apiBaseUrl, fetchOverride, getSession, providedBillId, sessionEndpoint]);
3191
3241
  useEffect5(() => {
3192
- setData(initialData);
3242
+ setData(null);
3193
3243
  setError(null);
3194
- }, [initialData, providedBillId]);
3244
+ setIsLoading(enabled);
3245
+ }, [enabled, providedBillId]);
3195
3246
  useEffect5(() => {
3196
3247
  mounted.current = true;
3197
3248
  return () => {
@@ -3243,27 +3294,21 @@ function useBillLifecycle({
3243
3294
  }
3244
3295
  }, []);
3245
3296
  const openAttachment = useCallback3(async (attachment) => {
3246
- const preview = reservePreviewWindow();
3247
- try {
3248
- previewBlob(await client.getAttachment(attachment.id), preview);
3249
- } catch (error2) {
3250
- preview?.close();
3251
- throw error2;
3252
- }
3297
+ await openPdfFromUserGesture(() => client.getAttachment(attachment.id));
3253
3298
  }, [client]);
3254
3299
  const openEor = useCallback3(async (document2) => {
3255
- const preview = reservePreviewWindow();
3300
+ await openPdfFromUserGesture(() => client.getEor(document2.id));
3301
+ }, [client]);
3302
+ const downloadPacket = useCallback3(async () => {
3303
+ setError(null);
3256
3304
  try {
3257
- previewBlob(await client.getEor(document2.id), preview);
3258
- } catch (error2) {
3259
- preview?.close();
3260
- throw error2;
3305
+ await openPdfFromUserGesture(() => client.getPacket());
3306
+ } catch (cause) {
3307
+ const nextError = cause instanceof Error ? cause : new Error("Submission packet could not be opened.");
3308
+ if (mounted.current) setError(nextError);
3309
+ throw nextError;
3261
3310
  }
3262
3311
  }, [client]);
3263
- const downloadPacket = useCallback3(async () => {
3264
- const packet = await client.getPacket();
3265
- downloadBlob(packet, `mindbill-${data?.bill.billNumber ?? providedBillId}-submission-packet.pdf`);
3266
- }, [client, data?.bill.billNumber, providedBillId]);
3267
3312
  return {
3268
3313
  billId: providedBillId,
3269
3314
  data,
@@ -3332,14 +3377,20 @@ function ConnectedBillLifecycle({ appearance, className, style, loadingFallback,
3332
3377
  const [panel, setPanel] = useState6("");
3333
3378
  const [notice, setNotice] = useState6("");
3334
3379
  const [reason, setReason] = useState6("");
3335
- const [payment, setPayment] = useState6({ amount: 0, method: "check", checkNumber: "", depositDate: today(), note: "" });
3380
+ const [payment, setPayment] = useState6({ amount: 0, penaltyAmount: 0, interestAmount: 0, method: "check", checkNumber: "", depositDate: today(), note: "" });
3336
3381
  const [review, setReview] = useState6({ reason: "", payerClaimControlNumber: "", disputedAmount: void 0, attachmentIds: [], route: "ebill" });
3337
3382
  const lastData = useRef4(null);
3338
3383
  useEffect5(() => {
3339
3384
  if (!data || data === lastData.current) return;
3340
3385
  lastData.current = data;
3341
3386
  onChanged?.(data);
3342
- setPayment((current) => ({ ...current, amount: current.amount > 0 ? current.amount : data.bill.balanceDue }));
3387
+ const payerRemaining = data.remittance.payerReportedPaid === null ? data.bill.balanceDue : Math.max(0, data.remittance.payerReportedPaid - data.remittance.postedPrincipal);
3388
+ setPayment((current) => ({
3389
+ ...current,
3390
+ amount: current.amount > 0 && current.amount <= data.bill.balanceDue ? current.amount : Math.min(data.bill.balanceDue, payerRemaining || data.bill.balanceDue),
3391
+ penaltyAmount: 0,
3392
+ interestAmount: 0
3393
+ }));
3343
3394
  setReview((current) => ({
3344
3395
  ...current,
3345
3396
  disputedAmount: current.disputedAmount ?? data.bill.balanceDue,
@@ -3406,14 +3457,12 @@ function ConnectedBillLifecycle({ appearance, className, style, loadingFallback,
3406
3457
  ] }) : null,
3407
3458
  tab === "details" ? /* @__PURE__ */ jsxs7("div", { className: "mb-lifecycle-tabpanel", role: "tabpanel", children: [
3408
3459
  /* @__PURE__ */ jsx7(BillReadOnlyForm, { data, onOpenAttachment: lifecycle.openAttachment, ...appearance ? { appearance } : {} }),
3460
+ /* @__PURE__ */ jsx7(BillRemittanceCard, { remittance: data.remittance, ...appearance ? { appearance } : {} }),
3409
3461
  data.eors.length ? /* @__PURE__ */ jsxs7("section", { className: "mb-lifecycle-card", id: `mb-eors-${data.bill.id}`, children: [
3410
- /* @__PURE__ */ jsxs7("header", { children: [
3411
- /* @__PURE__ */ jsxs7("div", { children: [
3412
- /* @__PURE__ */ jsx7("h3", { children: "Explanation of Review" }),
3413
- /* @__PURE__ */ jsx7("p", { children: "The payer response associated with this immutable submission." })
3414
- ] }),
3415
- /* @__PURE__ */ jsx7("span", { children: data.eors.length })
3416
- ] }),
3462
+ /* @__PURE__ */ jsx7("header", { children: /* @__PURE__ */ jsxs7("div", { children: [
3463
+ /* @__PURE__ */ jsx7("h3", { children: "Explanation of Review" }),
3464
+ /* @__PURE__ */ jsx7("p", { children: "The payer response associated with this immutable submission." })
3465
+ ] }) }),
3417
3466
  /* @__PURE__ */ jsx7("ul", { className: "mb-lifecycle-documents", children: data.eors.map((eor) => /* @__PURE__ */ jsxs7("li", { children: [
3418
3467
  /* @__PURE__ */ jsxs7("div", { children: [
3419
3468
  /* @__PURE__ */ jsx7("strong", { children: eor.filename }),
@@ -3422,6 +3471,7 @@ function ConnectedBillLifecycle({ appearance, className, style, loadingFallback,
3422
3471
  /* @__PURE__ */ jsx7("button", { type: "button", className: "mb-lifecycle-button secondary", onClick: () => void lifecycle.openEor(eor).catch(() => void 0), children: "View EOR" })
3423
3472
  ] }, eor.id)) })
3424
3473
  ] }) : null,
3474
+ /* @__PURE__ */ jsx7(BillPaymentLedger, { payments: data.payments, ...appearance ? { appearance } : {} }),
3425
3475
  viewEor || actions.length ? /* @__PURE__ */ jsx7("button", { type: "button", className: "mb-lifecycle-button secondary mb-lifecycle-actions-trigger", onClick: () => setPanel("actions"), children: "Bill actions" }) : null
3426
3476
  ] }) : /* @__PURE__ */ jsx7("div", { className: "mb-lifecycle-tabpanel", role: "tabpanel", children: /* @__PURE__ */ jsx7(BillActivityTimeline, { events: data.activity, ...appearance ? { appearance } : {} }) }),
3427
3477
  panel === "actions" ? /* @__PURE__ */ jsx7(LifecycleDialog, { title: "Bill actions", onClose: () => setPanel(""), children: /* @__PURE__ */ jsxs7("section", { className: "mb-lifecycle-panel mb-lifecycle-action-panel", children: [
@@ -3501,13 +3551,21 @@ function ConnectedBillLifecycle({ appearance, className, style, loadingFallback,
3501
3551
  panel === "payment" ? /* @__PURE__ */ jsx7(LifecycleDialog, { title: "Post payment", onClose: () => setPanel(""), children: /* @__PURE__ */ jsxs7("section", { className: "mb-lifecycle-panel", children: [
3502
3552
  /* @__PURE__ */ jsxs7("div", { children: [
3503
3553
  /* @__PURE__ */ jsx7("h3", { children: "Post payment" }),
3504
- /* @__PURE__ */ jsx7("p", { children: "Record funds shown on the payer response." })
3554
+ /* @__PURE__ */ jsx7("p", { children: "Record a full or partial payment, plus any penalty and interest received." })
3505
3555
  ] }),
3506
3556
  /* @__PURE__ */ jsxs7("div", { className: "mb-lifecycle-fields two", children: [
3507
3557
  /* @__PURE__ */ jsxs7("label", { children: [
3508
- /* @__PURE__ */ jsx7("span", { children: "Amount" }),
3558
+ /* @__PURE__ */ jsx7("span", { children: "Amount applied to bill" }),
3509
3559
  /* @__PURE__ */ jsx7("input", { type: "number", min: "0.01", max: data.bill.balanceDue, step: "0.01", value: payment.amount || "", onChange: (event) => setPayment((current) => ({ ...current, amount: Number(event.target.value) })) })
3510
3560
  ] }),
3561
+ /* @__PURE__ */ jsxs7("label", { children: [
3562
+ /* @__PURE__ */ jsx7("span", { children: "Penalty" }),
3563
+ /* @__PURE__ */ jsx7("input", { type: "number", min: "0", step: "0.01", value: payment.penaltyAmount || "", placeholder: "0.00", onChange: (event) => setPayment((current) => ({ ...current, penaltyAmount: Number(event.target.value) })) })
3564
+ ] }),
3565
+ /* @__PURE__ */ jsxs7("label", { children: [
3566
+ /* @__PURE__ */ jsx7("span", { children: "Interest" }),
3567
+ /* @__PURE__ */ jsx7("input", { type: "number", min: "0", step: "0.01", value: payment.interestAmount || "", placeholder: "0.00", onChange: (event) => setPayment((current) => ({ ...current, interestAmount: Number(event.target.value) })) })
3568
+ ] }),
3511
3569
  /* @__PURE__ */ jsxs7("label", { children: [
3512
3570
  /* @__PURE__ */ jsx7("span", { children: "Method" }),
3513
3571
  /* @__PURE__ */ jsxs7("select", { value: payment.method, onChange: (event) => setPayment((current) => ({ ...current, method: event.target.value })), children: [
@@ -3528,9 +3586,13 @@ function ConnectedBillLifecycle({ appearance, className, style, loadingFallback,
3528
3586
  /* @__PURE__ */ jsx7("input", { value: payment.note, onChange: (event) => setPayment((current) => ({ ...current, note: event.target.value })) })
3529
3587
  ] })
3530
3588
  ] }),
3589
+ /* @__PURE__ */ jsxs7("div", { className: "mb-payment-total", children: [
3590
+ /* @__PURE__ */ jsx7("span", { children: "Total received" }),
3591
+ /* @__PURE__ */ jsx7("strong", { children: new Intl.NumberFormat(void 0, { style: "currency", currency: "USD" }).format(payment.amount + (payment.penaltyAmount ?? 0) + (payment.interestAmount ?? 0)) })
3592
+ ] }),
3531
3593
  /* @__PURE__ */ jsxs7("div", { className: "mb-lifecycle-panel-actions", children: [
3532
3594
  /* @__PURE__ */ jsx7("button", { type: "button", className: "mb-lifecycle-button secondary", onClick: () => setPanel(""), children: "Cancel" }),
3533
- /* @__PURE__ */ jsx7("button", { type: "button", className: "mb-lifecycle-button primary", disabled: lifecycle.isMutating || payment.amount <= 0 || payment.amount > data.bill.balanceDue || !payment.depositDate, onClick: () => void complete("Payment posted.", () => lifecycle.postPayment(payment)), children: lifecycle.isMutating ? "Posting\u2026" : "Post payment" })
3595
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "mb-lifecycle-button primary", disabled: lifecycle.isMutating || payment.amount <= 0 || payment.amount > data.bill.balanceDue || (payment.penaltyAmount ?? 0) < 0 || (payment.interestAmount ?? 0) < 0 || !payment.depositDate, onClick: () => void complete("Payment posted.", () => lifecycle.postPayment(payment)), children: lifecycle.isMutating ? "Posting\u2026" : "Post payment" })
3534
3596
  ] })
3535
3597
  ] }) }) : null,
3536
3598
  panel === "close" || panel === "reopen" ? /* @__PURE__ */ jsx7(LifecycleDialog, { title: panel === "close" ? "Close bill" : "Reopen bill", onClose: () => setPanel(""), children: /* @__PURE__ */ jsxs7("section", { className: "mb-lifecycle-panel", children: [
@@ -3554,6 +3616,7 @@ function ConnectedBillLifecycle({ appearance, className, style, loadingFallback,
3554
3616
  var CONNECTED_LIFECYCLE_STYLES = `
3555
3617
  .mb-lifecycle-simulator{display:grid;gap:14px;padding:18px;border:1px solid #b8dadd;border-radius:var(--mb-radius,14px);background:#f2fbfb}.mb-lifecycle-simulator>div:first-child>span{color:var(--mb-accent);font-size:.72rem;font-weight:850;letter-spacing:.09em;text-transform:uppercase}.mb-lifecycle-simulator h3{margin:3px 0 0;font-size:1.05rem}.mb-lifecycle-simulator p{margin:4px 0 0;color:var(--mb-muted)}.mb-lifecycle-simulator-actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px}.mb-lifecycle-simulator-actions button{min-height:76px;border:1px solid #a9cccf;border-radius:10px;background:var(--mb-surface);color:var(--mb-text);cursor:pointer;padding:12px 14px;text-align:left;font:inherit}.mb-lifecycle-simulator-actions button:hover{border-color:var(--mb-accent);box-shadow:0 3px 14px rgba(23,108,112,.1)}.mb-lifecycle-simulator-actions button:disabled{cursor:not-allowed;opacity:.55}.mb-lifecycle-simulator-actions button strong,.mb-lifecycle-simulator-actions button span{display:block}.mb-lifecycle-simulator-actions button span{margin-top:3px;color:var(--mb-muted);font-size:.83rem}.mb-lifecycle-simulator-idle{padding:10px 12px;border-radius:8px;background:rgba(255,255,255,.72)}
3556
3618
  .mb-connected-lifecycle{--mb-accent:#176c70;--mb-text:#17282d;--mb-muted:#607176;--mb-border:#d7e0df;--mb-soft:#f4f7f6;--mb-surface:#fff;display:grid;gap:18px;color:var(--mb-text);font:14px/1.45 var(--mb-font,Inter,ui-sans-serif,system-ui,sans-serif)}.mb-connected-lifecycle *{box-sizing:border-box}.mb-lifecycle-head{display:flex;align-items:center;justify-content:space-between;gap:20px}.mb-lifecycle-title{display:flex;align-items:center;flex-wrap:wrap;gap:10px}.mb-lifecycle-title h2{margin:0;font-size:1.7rem}.mb-lifecycle-title span{border-radius:999px;background:var(--mb-soft);padding:5px 10px;font-weight:750}.mb-lifecycle-head p{margin:3px 0 0;color:var(--mb-muted)}.mb-lifecycle-tabs{display:grid;grid-template-columns:1fr 1fr;border:1px solid var(--mb-border);border-radius:12px;background:var(--mb-surface);padding:6px}.mb-lifecycle-tabs button{min-height:46px;border:0;border-radius:8px;background:transparent;color:var(--mb-muted);font:inherit;font-size:1rem;font-weight:750;cursor:pointer}.mb-lifecycle-tabs button[aria-selected=true]{background:var(--mb-accent);color:white}.mb-lifecycle-tabpanel{display:grid;gap:18px}.mb-lifecycle-button{min-height:40px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius,8px);background:var(--mb-input,#fff);color:var(--mb-text);cursor:pointer;font:inherit;font-weight:750;padding:9px 14px}.mb-lifecycle-button.primary{border-color:var(--mb-accent);background:var(--mb-accent);color:var(--mb-accent-contrast,#fff)}.mb-lifecycle-button:disabled{cursor:not-allowed;opacity:.5}.mb-lifecycle-actions-trigger{width:100%}.mb-lifecycle-card,.mb-lifecycle-panel{padding:20px;border:1px solid var(--mb-border);border-radius:var(--mb-radius,14px);background:var(--mb-surface)}.mb-lifecycle-card header{display:flex;align-items:center;justify-content:space-between;gap:20px}.mb-lifecycle-card h3,.mb-lifecycle-panel h3{margin:0;font-size:1.08rem}.mb-lifecycle-card p,.mb-lifecycle-panel p{margin:3px 0 0;color:var(--mb-muted)}.mb-lifecycle-card header>span{display:grid;place-items:center;min-width:28px;height:28px;border-radius:999px;background:var(--mb-soft);font-weight:750}.mb-lifecycle-action-options{display:grid;gap:10px}.mb-lifecycle-action-options .mb-lifecycle-button{width:100%}.mb-lifecycle-documents{list-style:none;margin:14px 0 0;padding:0}.mb-lifecycle-documents li{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:12px 0;border-top:1px solid var(--mb-border)}.mb-lifecycle-documents li>div{display:grid;gap:3px;min-width:0}.mb-lifecycle-documents li span{color:var(--mb-muted);font-size:.85rem}.mb-lifecycle-dialog-backdrop{position:fixed;z-index:2147483000;inset:0;display:grid;place-items:center;padding:20px;background:rgba(18,35,43,.56);backdrop-filter:blur(3px)}.mb-lifecycle-dialog{position:relative;width:min(760px,100%);max-height:calc(100vh - 40px);overflow:auto;outline:0}.mb-lifecycle-dialog-close{position:absolute;z-index:1;top:12px;right:12px;width:34px;height:34px;border:1px solid var(--mb-border);border-radius:8px;background:var(--mb-surface);color:var(--mb-text);cursor:pointer;font:22px/1 inherit}.mb-lifecycle-panel{display:grid;gap:17px;padding-top:24px;box-shadow:0 24px 70px rgba(18,35,43,.22)}.mb-lifecycle-panel label{display:grid;gap:6px;font-size:.85rem;font-weight:750}.mb-lifecycle-panel label small{color:var(--mb-muted);font-weight:500}.mb-lifecycle-panel input,.mb-lifecycle-panel select,.mb-lifecycle-panel textarea{width:100%;min-height:44px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius,8px);background:var(--mb-input,#fff);color:var(--mb-text);font:inherit;padding:10px 12px}.mb-lifecycle-panel textarea{min-height:100px;resize:vertical}.mb-lifecycle-fields{display:grid;gap:13px}.mb-lifecycle-fields.two{grid-template-columns:repeat(2,minmax(0,1fr))}.mb-lifecycle-fields .full{grid-column:1/-1}.mb-lifecycle-panel-actions{display:flex;justify-content:flex-end;gap:8px}.mb-lifecycle-packet{display:grid;gap:0;margin:0;padding:0;border:0}.mb-lifecycle-packet legend{margin-bottom:7px;font-size:.85rem;font-weight:800}.mb-lifecycle-packet>label{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:10px;padding:10px 2px;border-top:1px solid var(--mb-border)}.mb-lifecycle-packet>label>input{width:16px;min-height:16px}.mb-lifecycle-packet>label>span{display:grid}.mb-lifecycle-packet button{border:0;background:transparent;color:var(--mb-accent);cursor:pointer;font:inherit}.mb-lifecycle-message,.mb-lifecycle-error,.mb-lifecycle-loading{padding:12px 14px;border-radius:9px}.mb-lifecycle-message.success{background:#edf9f2;color:#217449}.mb-lifecycle-message.error,.mb-lifecycle-error{background:#fff0ef;color:#9d3029}.mb-lifecycle-error{display:flex;align-items:center;gap:12px}.mb-lifecycle-error span{flex:1}.mb-lifecycle-error button{border:1px solid currentColor;border-radius:7px;background:transparent;color:inherit;padding:7px 10px}
3619
+ .mb-payment-total{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-radius:9px;background:var(--mb-soft)}.mb-payment-total strong{font-size:1.12rem}
3557
3620
  @media(max-width:700px){.mb-lifecycle-head,.mb-lifecycle-actions-sheet,.mb-lifecycle-card header{align-items:stretch;flex-direction:column}.mb-lifecycle-head>.mb-lifecycle-button{width:100%}.mb-lifecycle-actions-sheet>div:last-child{justify-content:stretch}.mb-lifecycle-actions-sheet .mb-lifecycle-button{width:100%}.mb-lifecycle-fields.two{grid-template-columns:1fr}.mb-lifecycle-fields .full{grid-column:auto}.mb-lifecycle-dialog-backdrop{align-items:end;padding:0}.mb-lifecycle-dialog{max-height:92vh}.mb-lifecycle-dialog .mb-lifecycle-panel{border-radius:18px 18px 0 0}.mb-lifecycle-tabs button{font-size:.9rem}.mb-lifecycle-title h2{font-size:1.4rem}}
3558
3621
  `;
3559
3622