@mindbill/react 0.13.1 → 0.14.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/dist/index.d.ts CHANGED
@@ -115,6 +115,7 @@ type BillReviewClinician = {
115
115
  active?: boolean;
116
116
  };
117
117
  type BillReviewLocation = {
118
+ billingProviderId?: string;
118
119
  name: string;
119
120
  nickname?: string;
120
121
  street: string;
@@ -133,6 +134,9 @@ type BillReviewLineItem = {
133
134
  units: number;
134
135
  charge: number;
135
136
  feeSchedule?: number;
137
+ serviceDate?: string | null;
138
+ serviceDateEnd?: string | null;
139
+ diagnosisPointers?: number[];
136
140
  };
137
141
  /** Keeps completed/partial lines plus one keyboard-ready empty row. */
138
142
  declare function ensureTrailingProcedureLine(lines: readonly BillReviewLineItem[]): BillReviewLineItem[];
@@ -174,6 +178,7 @@ type BillReviewClaimPatternStatus = {
174
178
  type BillReviewData = {
175
179
  bill: {
176
180
  id: string;
181
+ billingMode: "med_legal" | "professional";
177
182
  billNumber: string | number;
178
183
  status: string;
179
184
  transmissionState?: string;
@@ -237,13 +242,53 @@ type BillReviewSaveInput = {
237
242
  code: string;
238
243
  modifiers: string[];
239
244
  units: number;
245
+ charge?: number;
246
+ serviceDate?: string | null;
247
+ serviceDateEnd?: string | null;
248
+ diagnosisPointers?: number[];
240
249
  }>;
241
250
  };
242
251
  type BillSubmissionRoute = "ebill" | "fax" | "mail" | "email";
252
+ type BillDeliveryOption = {
253
+ route: BillSubmissionRoute;
254
+ label: string;
255
+ detail: string;
256
+ fallback: boolean;
257
+ confidence: string;
258
+ payerName: string;
259
+ target?: string;
260
+ chKey?: string;
261
+ payerId?: string;
262
+ printAndMail?: boolean;
263
+ costUsd?: number;
264
+ };
265
+ type BillDeliveryOptions = {
266
+ payerName: string;
267
+ recommended: BillDeliveryOption;
268
+ options: BillDeliveryOption[];
269
+ contacts: {
270
+ faxNumber?: string | null;
271
+ claimsEmail?: string | null;
272
+ portalUrl?: string | null;
273
+ mailingAddress?: string | null;
274
+ };
275
+ };
276
+ type BillSubmissionInput = {
277
+ route: BillSubmissionRoute;
278
+ destination?: {
279
+ faxNumber?: string;
280
+ email?: string;
281
+ mailingAddress?: string;
282
+ };
283
+ attention?: string;
284
+ subject?: string;
285
+ note?: string;
286
+ };
243
287
  type BillReviewFormProps = {
244
288
  data: BillReviewData;
245
289
  onSave: (input: BillReviewSaveInput) => Promise<BillReviewData | void>;
246
- onSubmit: (input: BillReviewSaveInput, route: BillSubmissionRoute) => Promise<void>;
290
+ onSubmit: (input: BillReviewSaveInput, submission: BillSubmissionInput) => Promise<void>;
291
+ onGetDeliveryOptions: () => Promise<BillDeliveryOptions>;
247
292
  onAddAttachment: (file: File, documentType: BillReviewDocumentType, description?: string) => Promise<void>;
248
293
  onRemoveAttachment: (attachmentId: string) => Promise<void>;
249
294
  onOpenAttachment?: (attachment: BillReviewAttachment) => void;
@@ -276,7 +321,7 @@ type BillReviewDraft = {
276
321
  lineItems: BillReviewLineItem[];
277
322
  };
278
323
  declare function buildBillReviewSaveInput(draft: BillReviewDraft): BillReviewSaveInput;
279
- declare function BillReviewForm({ data, onSave, onSubmit, onAddAttachment, onRemoveAttachment, onOpenAttachment, onSearchClaimsAdministrators, className, style, appearance, features, disabled, }: BillReviewFormProps): ReactElement;
324
+ declare function BillReviewForm({ data, onSave, onSubmit, onGetDeliveryOptions, onAddAttachment, onRemoveAttachment, onOpenAttachment, onSearchClaimsAdministrators, className, style, appearance, features, disabled, }: BillReviewFormProps): ReactElement;
280
325
  type BillStatusSummaryProps = {
281
326
  status: string;
282
327
  submittedAt?: string | null;
@@ -377,6 +422,7 @@ type UseBillLifecycleResult = {
377
422
  isMutating: boolean;
378
423
  refresh: () => Promise<void>;
379
424
  searchClaimsAdministrators: BillLifecycleClient["searchClaimsAdministrators"];
425
+ getDeliveryOptions: BillLifecycleClient["getDeliveryOptions"];
380
426
  saveReview: BillLifecycleClient["saveReview"];
381
427
  submitBill: BillLifecycleClient["submitBill"];
382
428
  addAttachment: BillLifecycleClient["addAttachment"];
package/dist/index.js CHANGED
@@ -101,8 +101,9 @@ function mindBillAppearanceStyle(appearance, style) {
101
101
  }
102
102
 
103
103
  // src/native-bill-review.tsx
104
+ import { sanitizeBillReviewSaveInput } from "@mindbill/browser";
104
105
  import { useEffect, useId, useMemo, useRef, useState } from "react";
105
- import { jsx, jsxs } from "react/jsx-runtime";
106
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
106
107
  var EMPTY_PROCEDURE_LINE = {
107
108
  code: "",
108
109
  modifiers: [],
@@ -110,7 +111,7 @@ var EMPTY_PROCEDURE_LINE = {
110
111
  charge: 0
111
112
  };
112
113
  function isEmptyProcedureLine(line) {
113
- return !line.code.trim() && line.modifiers.length === 0 && line.units === 1;
114
+ return !line.code.trim() && line.modifiers.length === 0 && line.units === 1 && !line.serviceDate && !line.serviceDateEnd && !line.charge && !line.diagnosisPointers?.length;
114
115
  }
115
116
  function ensureTrailingProcedureLine(lines) {
116
117
  const entered = lines.filter((line) => !isEmptyProcedureLine(line)).map((line) => ({ ...line, modifiers: [...line.modifiers] }));
@@ -204,7 +205,7 @@ function toDraft(data) {
204
205
  };
205
206
  }
206
207
  function buildBillReviewSaveInput(draft) {
207
- return {
208
+ return sanitizeBillReviewSaveInput({
208
209
  claimsAdminId: draft.claimsAdminId,
209
210
  patientOverrides: {
210
211
  firstName: draft.patientFirstName.trim(),
@@ -226,13 +227,17 @@ function buildBillReviewSaveInput(draft) {
226
227
  billingProvider: { ...draft.billingProvider },
227
228
  renderingProvider: { ...draft.clinician },
228
229
  placeOfService: { ...draft.location },
229
- lineItems: draft.lineItems.filter((line) => line.code.trim()).map(({ id, code, modifiers, units }) => ({
230
+ lineItems: draft.lineItems.filter((line) => line.code.trim()).map(({ id, code, modifiers, units, charge, serviceDate, serviceDateEnd, diagnosisPointers }) => ({
230
231
  ...id ? { id } : {},
231
232
  code: code.trim().toUpperCase(),
232
233
  modifiers,
233
- units
234
+ units,
235
+ ...charge ? { charge } : {},
236
+ ...serviceDate ? { serviceDate } : {},
237
+ ...serviceDateEnd ? { serviceDateEnd } : {},
238
+ ...diagnosisPointers?.length ? { diagnosisPointers } : {}
234
239
  }))
235
- };
240
+ });
236
241
  }
237
242
  function money(value) {
238
243
  return new Intl.NumberFormat("en-US", {
@@ -391,6 +396,7 @@ function BillReviewForm({
391
396
  data,
392
397
  onSave,
393
398
  onSubmit,
399
+ onGetDeliveryOptions,
394
400
  onAddAttachment,
395
401
  onRemoveAttachment,
396
402
  onOpenAttachment,
@@ -407,13 +413,15 @@ function BillReviewForm({
407
413
  );
408
414
  const [payerResults, setPayerResults] = useState([]);
409
415
  const [payerBusy, setPayerBusy] = useState(false);
410
- const [route, setRoute] = useState("ebill");
416
+ const [deliveryOptions, setDeliveryOptions] = useState(null);
417
+ const [submission, setSubmission] = useState({ route: "ebill" });
418
+ const [showSubmit, setShowSubmit] = useState(false);
419
+ const [deliveryBusy, setDeliveryBusy] = useState(false);
411
420
  const [file, setFile] = useState(null);
412
421
  const [documentType, setDocumentType] = useState("other");
413
422
  const [busy, setBusy] = useState("");
414
423
  const [error, setError] = useState("");
415
424
  const [notice, setNotice] = useState("");
416
- const routeName = useId();
417
425
  const editable = data.bill.status === "incomplete" && !disabled;
418
426
  useEffect(() => {
419
427
  setDraft(toDraft(data));
@@ -479,7 +487,7 @@ function BillReviewForm({
479
487
  if (!draft.claimNumber.trim()) result.push("Claim number");
480
488
  if (!draft.doi) result.push("Date of injury");
481
489
  if (!adjFormatValid) result.push("Valid WCAB / ADJ number");
482
- if (!draft.dos) result.push("Date of service");
490
+ if (data.bill.billingMode === "med_legal" && !draft.dos) result.push("Date of service");
483
491
  if (!draft.billingProvider.name.trim()) result.push("Practice name");
484
492
  if (!draft.billingProvider.taxId.trim()) result.push("Tax ID");
485
493
  if (!draft.billingProvider.npi.trim()) result.push("Billing NPI");
@@ -487,8 +495,11 @@ function BillReviewForm({
487
495
  if (![draft.location.name, draft.location.street, draft.location.city, draft.location.state, draft.location.zip].every((value) => value.trim())) result.push("Service location");
488
496
  const completedLines = draft.lineItems.filter((line) => line.code.trim());
489
497
  if (!completedLines.length || completedLines.some((line) => line.units <= 0)) result.push("Valid procedure line");
498
+ if (data.bill.billingMode === "professional" && completedLines.some((line) => !line.serviceDate || line.charge <= 0)) {
499
+ result.push("Service date and charge on every procedure line");
500
+ }
490
501
  return result;
491
- }, [adjFormatValid, draft]);
502
+ }, [adjFormatValid, data.bill.billingMode, draft]);
492
503
  const canSubmit = blockers.length === 0;
493
504
  const updateBillingProvider = (key, value) => setDraft((current) => ({
494
505
  ...current,
@@ -524,7 +535,33 @@ function BillReviewForm({
524
535
  if (updated) setDraft(toDraft(updated));
525
536
  });
526
537
  };
527
- const handleSubmit = () => run("submit", () => onSubmit(buildBillReviewSaveInput(draft), route));
538
+ const openSubmit = async () => {
539
+ setDeliveryBusy(true);
540
+ setError("");
541
+ try {
542
+ const next = await onGetDeliveryOptions();
543
+ setDeliveryOptions(next);
544
+ const recommended = next.recommended ?? next.options[0];
545
+ if (!recommended) throw new Error("No delivery route is available for this payer.");
546
+ setSubmission({ route: recommended.route });
547
+ setShowSubmit(true);
548
+ } catch (cause) {
549
+ setError(cause instanceof Error ? cause.message : "Delivery routes could not be loaded.");
550
+ } finally {
551
+ setDeliveryBusy(false);
552
+ }
553
+ };
554
+ const selectedDelivery = deliveryOptions?.options.find((option) => option.route === submission.route);
555
+ const destinationLabel = submission.route === "fax" ? "Fax number" : submission.route === "email" ? "Email address" : submission.route === "mail" ? "Mailing address" : "";
556
+ const destinationValue = submission.route === "fax" ? submission.destination?.faxNumber ?? selectedDelivery?.target ?? deliveryOptions?.contacts.faxNumber ?? "" : submission.route === "email" ? submission.destination?.email ?? selectedDelivery?.target ?? deliveryOptions?.contacts.claimsEmail ?? "" : submission.route === "mail" ? submission.destination?.mailingAddress ?? selectedDelivery?.target ?? deliveryOptions?.contacts.mailingAddress ?? "" : "";
557
+ const setDestination = (value) => setSubmission((current) => {
558
+ const destination = current.route === "fax" ? { faxNumber: value } : current.route === "email" ? { email: value } : { mailingAddress: value };
559
+ return { ...current, destination };
560
+ });
561
+ const handleSubmit = () => run("submit", async () => {
562
+ await onSubmit(buildBillReviewSaveInput(draft), submission);
563
+ setShowSubmit(false);
564
+ });
528
565
  const attach = async () => {
529
566
  if (!file) return;
530
567
  setBusy("attachment");
@@ -550,6 +587,7 @@ function BillReviewForm({
550
587
  children: [
551
588
  /* @__PURE__ */ jsx("style", { children: NATIVE_BILL_REVIEW_STYLES }),
552
589
  /* @__PURE__ */ jsx("style", { children: NATIVE_THEME_OVERRIDE_STYLES }),
590
+ /* @__PURE__ */ jsx("style", { children: NATIVE_SUBMISSION_DIALOG_STYLES }),
553
591
  /* @__PURE__ */ jsxs("header", { className: "mb-native-heading", children: [
554
592
  /* @__PURE__ */ jsxs("div", { children: [
555
593
  /* @__PURE__ */ jsx("span", { className: "mb-native-eyebrow", children: "Billing review" }),
@@ -717,30 +755,32 @@ function BillReviewForm({
717
755
  /* @__PURE__ */ jsxs("section", { className: sectionClass, children: [
718
756
  /* @__PURE__ */ jsx("div", { className: "mb-native-section-head", children: /* @__PURE__ */ jsxs("div", { children: [
719
757
  /* @__PURE__ */ jsx("h3", { children: "Procedure lines" }),
720
- /* @__PURE__ */ jsx("p", { children: "Choose a billing profile, then review the codes and modifiers. A new row appears as you type; allowed amounts recalculate on save." })
758
+ /* @__PURE__ */ jsxs("p", { children: [
759
+ data.bill.billingMode === "professional" ? "Enter the professional services billed. Each line may carry its own date, charge, and diagnosis pointers." : "Choose a billing profile, then review the codes and modifiers.",
760
+ " A new row appears as you type."
761
+ ] })
721
762
  ] }) }),
722
- features?.codingPresets === false ? null : /* @__PURE__ */ jsxs("div", { className: "mb-native-presets", role: "group", "aria-label": "Evaluation billing profile", children: [
763
+ data.bill.billingMode === "professional" || features?.codingPresets === false ? null : /* @__PURE__ */ jsxs("div", { className: "mb-native-presets", role: "group", "aria-label": "Evaluation billing profile", children: [
723
764
  [["qme", "QME"], ["ame", "AME"], ["psych_qme", "Psych QME"]].map(([value, label]) => /* @__PURE__ */ jsx("button", { type: "button", className: inferPreset(draft.lineItems) === value ? "active" : "", disabled: !editable, onClick: () => setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(applyPreset(current.lineItems, value)) })), children: label }, value)),
724
765
  /* @__PURE__ */ jsx("span", { children: "Sets evaluator modifiers across med-legal lines. You can still edit each line." })
725
766
  ] }),
726
- /* @__PURE__ */ jsx("div", { className: "mb-native-lines", children: draft.lineItems.map((line, index) => /* @__PURE__ */ jsxs("div", { className: "mb-native-line", children: [
767
+ /* @__PURE__ */ jsx("div", { className: "mb-native-lines", children: draft.lineItems.map((line, index) => /* @__PURE__ */ jsxs("div", { className: `mb-native-line ${data.bill.billingMode === "professional" ? "professional" : ""}`, children: [
727
768
  /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
728
769
  /* @__PURE__ */ jsx("span", { children: "Procedure" }),
729
- /* @__PURE__ */ jsxs("select", { disabled: !editable, value: line.code, onChange: (event) => {
770
+ data.bill.billingMode === "professional" ? /* @__PURE__ */ jsx("input", { disabled: !editable, placeholder: "CPT / HCPCS code", value: line.code, onChange: (event) => {
771
+ const code = event.target.value.toUpperCase();
772
+ setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, code } : item)) }));
773
+ } }) : /* @__PURE__ */ jsxs("select", { disabled: !editable, value: line.code, onChange: (event) => {
730
774
  const code = event.target.value;
731
775
  setDraft((current) => {
732
776
  const lineItems = current.lineItems.map((item, itemIndex) => {
733
777
  if (itemIndex !== index) return item;
734
- const presetLine = applyPreset(
735
- [{ ...item, code }],
736
- inferPreset(current.lineItems)
737
- )[0];
778
+ const presetLine = applyPreset([{ ...item, code }], inferPreset(current.lineItems))[0];
738
779
  return { ...item, code, modifiers: presetLine?.modifiers || [] };
739
780
  });
740
781
  return { ...current, lineItems: ensureTrailingProcedureLine(lineItems) };
741
782
  });
742
783
  }, children: [
743
- line.code && !PROCEDURES.some(([code]) => code === line.code) ? /* @__PURE__ */ jsx("option", { value: line.code, children: line.code }) : null,
744
784
  /* @__PURE__ */ jsx("option", { value: "", children: "Select code\u2026" }),
745
785
  PROCEDURES.map(([code, label]) => /* @__PURE__ */ jsxs("option", { value: code, children: [
746
786
  code,
@@ -748,10 +788,16 @@ function BillReviewForm({
748
788
  label
749
789
  ] }, code))
750
790
  ] }),
751
- line.code ? /* @__PURE__ */ jsx("small", { children: PROCEDURES.find(([code]) => code === line.code)?.[1] }) : null
791
+ data.bill.billingMode === "med_legal" && line.code ? /* @__PURE__ */ jsx("small", { children: PROCEDURES.find(([code]) => code === line.code)?.[1] }) : null
752
792
  ] }),
753
793
  /* @__PURE__ */ jsxs("div", { className: "mb-native-modifiers", children: [
754
- /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
794
+ data.bill.billingMode === "professional" ? /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
795
+ /* @__PURE__ */ jsx("span", { children: "Modifiers" }),
796
+ /* @__PURE__ */ jsx("input", { disabled: !editable, placeholder: "e.g. 25, 59", value: line.modifiers.join(", "), onChange: (event) => {
797
+ const modifiers = event.target.value.toUpperCase().split(/[ ,]+/).map((value) => value.replace(/^-/, "")).filter(Boolean);
798
+ setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, modifiers } : item)) }));
799
+ } })
800
+ ] }) : /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
755
801
  /* @__PURE__ */ jsx("span", { children: "Modifiers" }),
756
802
  /* @__PURE__ */ jsxs("select", { disabled: !editable, value: "", onChange: (event) => {
757
803
  const modifier = event.target.value;
@@ -767,16 +813,43 @@ function BillReviewForm({
767
813
  ] }, value))
768
814
  ] })
769
815
  ] }),
770
- /* @__PURE__ */ jsx("div", { className: "mb-native-chips", children: line.modifiers.map((modifier) => /* @__PURE__ */ jsxs("button", { type: "button", disabled: !editable, onClick: () => setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, modifiers: item.modifiers.filter((value) => value !== modifier) } : item)) })), children: [
816
+ /* @__PURE__ */ jsx("div", { className: "mb-native-chips", children: data.bill.billingMode === "med_legal" ? line.modifiers.map((modifier) => /* @__PURE__ */ jsxs("button", { type: "button", disabled: !editable, onClick: () => setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, modifiers: item.modifiers.filter((value) => value !== modifier) } : item)) })), children: [
771
817
  "-",
772
818
  modifier,
773
819
  " \xD7"
774
- ] }, modifier)) })
820
+ ] }, modifier)) : null })
775
821
  ] }),
776
822
  /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
777
823
  /* @__PURE__ */ jsx("span", { children: "Units" }),
778
824
  /* @__PURE__ */ jsx("input", { type: "number", min: "1", required: true, disabled: !editable, value: line.units, onChange: (event) => setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, units: Number(event.target.value) } : item)) })) })
779
825
  ] }),
826
+ data.bill.billingMode === "professional" ? /* @__PURE__ */ jsxs(Fragment, { children: [
827
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
828
+ /* @__PURE__ */ jsx("span", { children: "Service date" }),
829
+ /* @__PURE__ */ jsx("input", { type: "date", required: Boolean(line.code), disabled: !editable, value: line.serviceDate || "", onChange: (event) => setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, serviceDate: event.target.value } : item)) })) })
830
+ ] }),
831
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
832
+ /* @__PURE__ */ jsxs("span", { children: [
833
+ "End date ",
834
+ /* @__PURE__ */ jsx("small", { children: "Optional" })
835
+ ] }),
836
+ /* @__PURE__ */ jsx("input", { type: "date", disabled: !editable, value: line.serviceDateEnd || "", onChange: (event) => setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, serviceDateEnd: event.target.value } : item)) })) })
837
+ ] }),
838
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
839
+ /* @__PURE__ */ jsx("span", { children: "Charge" }),
840
+ /* @__PURE__ */ jsx("input", { type: "number", min: "0.01", step: "0.01", required: Boolean(line.code), disabled: !editable, value: line.charge || "", onChange: (event) => setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, charge: Number(event.target.value) } : item)) })) })
841
+ ] }),
842
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
843
+ /* @__PURE__ */ jsxs("span", { children: [
844
+ "Diagnosis pointers ",
845
+ /* @__PURE__ */ jsx("small", { children: "1\u201312" })
846
+ ] }),
847
+ /* @__PURE__ */ jsx("input", { inputMode: "numeric", disabled: !editable, value: (line.diagnosisPointers || []).join(", "), onChange: (event) => {
848
+ const diagnosisPointers = event.target.value.split(/[ ,]+/).map(Number).filter((value) => Number.isInteger(value) && value >= 1 && value <= 12);
849
+ setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, diagnosisPointers } : item)) }));
850
+ } })
851
+ ] })
852
+ ] }) : null,
780
853
  /* @__PURE__ */ jsxs("div", { className: "mb-native-allowed", children: [
781
854
  /* @__PURE__ */ jsx("span", { children: "Allowed" }),
782
855
  /* @__PURE__ */ jsx("strong", { children: money(line.charge) })
@@ -824,13 +897,6 @@ function BillReviewForm({
824
897
  /* @__PURE__ */ jsx("h3", { children: "Submit this bill" }),
825
898
  /* @__PURE__ */ jsx("p", { children: "After submission, status, payments, denials, and resubmissions stay available here." })
826
899
  ] }),
827
- /* @__PURE__ */ jsxs("fieldset", { children: [
828
- /* @__PURE__ */ jsx("legend", { children: "Send via" }),
829
- ["ebill", "fax", "mail", "email"].map((value) => /* @__PURE__ */ jsxs("label", { children: [
830
- /* @__PURE__ */ jsx("input", { type: "radio", name: routeName, value, checked: route === value, onChange: () => setRoute(value) }),
831
- value === "ebill" ? "E-bill" : value.charAt(0).toUpperCase() + value.slice(1)
832
- ] }, value))
833
- ] }),
834
900
  error ? /* @__PURE__ */ jsx("div", { className: "mb-native-message error", role: "alert", children: error }) : null,
835
901
  notice ? /* @__PURE__ */ jsx("div", { className: "mb-native-message success", role: "status", children: notice }) : null,
836
902
  !canSubmit ? /* @__PURE__ */ jsxs("div", { className: "mb-native-blockers", role: "status", children: [
@@ -839,9 +905,43 @@ function BillReviewForm({
839
905
  ] }) : null,
840
906
  /* @__PURE__ */ jsxs("div", { className: "mb-native-actions", children: [
841
907
  /* @__PURE__ */ jsx("button", { className: "mb-native-button secondary", type: "submit", disabled: !editable || busy !== "", children: busy === "save" ? "Saving\u2026" : "Save changes" }),
842
- /* @__PURE__ */ jsx("button", { className: "mb-native-button primary", type: "button", disabled: !editable || !canSubmit || busy !== "", onClick: () => void handleSubmit(), children: busy === "submit" ? "Submitting\u2026" : "Submit bill" })
908
+ /* @__PURE__ */ jsx("button", { className: "mb-native-button primary", type: "button", disabled: !editable || !canSubmit || busy !== "" || deliveryBusy, onClick: () => void openSubmit(), children: deliveryBusy ? "Loading delivery\u2026" : "Review delivery" })
843
909
  ] })
844
- ] })
910
+ ] }),
911
+ showSubmit && deliveryOptions ? /* @__PURE__ */ jsx("div", { className: "mb-native-modal-backdrop", role: "presentation", onMouseDown: (event) => {
912
+ if (event.target === event.currentTarget && busy !== "submit") setShowSubmit(false);
913
+ }, children: /* @__PURE__ */ jsxs("section", { className: "mb-native-modal", role: "dialog", "aria-modal": "true", "aria-labelledby": "mb-native-submit-title", children: [
914
+ /* @__PURE__ */ jsxs("header", { children: [
915
+ /* @__PURE__ */ jsxs("div", { children: [
916
+ /* @__PURE__ */ jsx("span", { className: "mb-native-eyebrow", children: "Send bill" }),
917
+ /* @__PURE__ */ jsx("h3", { id: "mb-native-submit-title", children: "Choose a delivery route" }),
918
+ /* @__PURE__ */ jsx("p", { children: deliveryOptions.payerName || "Claims administrator" })
919
+ ] }),
920
+ /* @__PURE__ */ jsx("button", { type: "button", className: "mb-native-close", "aria-label": "Close", disabled: busy === "submit", onClick: () => setShowSubmit(false), children: "\xD7" })
921
+ ] }),
922
+ /* @__PURE__ */ jsxs("fieldset", { className: "mb-native-delivery-options", children: [
923
+ /* @__PURE__ */ jsx("legend", { children: "Available delivery routes" }),
924
+ deliveryOptions.options.map((option) => /* @__PURE__ */ jsxs("label", { className: submission.route === option.route ? "selected" : "", children: [
925
+ /* @__PURE__ */ jsx("input", { type: "radio", name: "mindbill-delivery-route", checked: submission.route === option.route, onChange: () => setSubmission({ route: option.route }) }),
926
+ /* @__PURE__ */ jsxs("span", { children: [
927
+ /* @__PURE__ */ jsx("strong", { children: option.label }),
928
+ /* @__PURE__ */ jsx("small", { children: option.detail }),
929
+ option.target ? /* @__PURE__ */ jsx("code", { children: option.target }) : null
930
+ ] }),
931
+ deliveryOptions.recommended?.route === option.route ? /* @__PURE__ */ jsx("em", { children: "Recommended" }) : null
932
+ ] }, `${option.route}-${option.target || "default"}`))
933
+ ] }),
934
+ submission.route !== "ebill" ? /* @__PURE__ */ jsxs("div", { className: "mb-native-grid two", children: [
935
+ /* @__PURE__ */ jsx(Field, { label: destinationLabel, required: true, value: destinationValue, onChange: setDestination, hint: "You can override the payer directory value for this submission." }),
936
+ /* @__PURE__ */ jsx(Field, { label: "Attention", optional: true, value: submission.attention || "", onChange: (attention) => setSubmission((current) => ({ ...current, attention })) }),
937
+ submission.route === "email" ? /* @__PURE__ */ jsx(Field, { label: "Subject", optional: true, value: submission.subject || "", onChange: (subject) => setSubmission((current) => ({ ...current, subject })) }) : null
938
+ ] }) : null,
939
+ /* @__PURE__ */ jsx(Field, { label: "Delivery note", optional: true, value: submission.note || "", onChange: (note) => setSubmission((current) => ({ ...current, note })) }),
940
+ /* @__PURE__ */ jsxs("footer", { children: [
941
+ /* @__PURE__ */ jsx("button", { className: "mb-native-button secondary", type: "button", disabled: busy === "submit", onClick: () => setShowSubmit(false), children: "Cancel" }),
942
+ /* @__PURE__ */ jsx("button", { className: "mb-native-button primary", type: "button", disabled: busy === "submit" || submission.route !== "ebill" && !destinationValue.trim(), onClick: () => void handleSubmit(), children: busy === "submit" ? "Submitting\u2026" : `Send via ${selectedDelivery?.label || submission.route}` })
943
+ ] })
944
+ ] }) }) : null
845
945
  ]
846
946
  }
847
947
  );
@@ -876,6 +976,19 @@ function BillStatusSummary({ status, submittedAt, agingDays, updatedAt, totalCha
876
976
  actions.length ? /* @__PURE__ */ jsx("div", { className: "mb-native-status-actions", children: actions.map((action) => /* @__PURE__ */ jsx("button", { type: "button", className: `mb-native-button ${action.primary ? "primary" : "secondary"}`, disabled: action.disabled, onClick: action.onClick, children: action.label }, action.id)) }) : null
877
977
  ] });
878
978
  }
979
+ var NATIVE_SUBMISSION_DIALOG_STYLES = `
980
+ .mb-native-field select{width:100%;min-height:43px;border:1px solid var(--mb-border);border-radius:8px;background:#fff;color:var(--mb-text);font:inherit;padding:10px 12px}
981
+ .mb-native-field select:focus{border-color:var(--mb-accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--mb-accent) 14%,transparent);outline:0}
982
+ .mb-native-line.professional{grid-template-columns:minmax(140px,1fr) minmax(140px,1fr) 86px 150px 150px 120px minmax(130px,1fr) 120px 28px;overflow-x:auto}
983
+ .mb-native-grid.two{grid-template-columns:repeat(2,minmax(0,1fr))}
984
+ .mb-native-modal-backdrop{position:fixed;z-index:9999;inset:0;display:grid;place-items:center;padding:20px;background:rgba(20,38,46,.55);backdrop-filter:blur(3px)}
985
+ .mb-native-modal{display:grid;gap:18px;width:min(720px,100%);max-height:min(820px,calc(100vh - 40px));overflow:auto;padding:22px;border:1px solid var(--mb-border);border-radius:16px;background:#fff;box-shadow:0 28px 80px rgba(14,35,44,.3)}
986
+ .mb-native-modal>header,.mb-native-modal>footer{display:flex;align-items:start;justify-content:space-between;gap:16px}.mb-native-modal>footer{justify-content:flex-end}.mb-native-modal h3{margin:3px 0;font-size:22px}.mb-native-modal p{margin:0;color:var(--mb-muted)}
987
+ .mb-native-close{border:1px solid var(--mb-border);border-radius:8px;background:#fff;color:var(--mb-text);cursor:pointer;font-size:23px;line-height:1;padding:8px 12px}
988
+ .mb-native-delivery-options{display:grid;gap:9px;margin:0;padding:0;border:0}.mb-native-delivery-options legend{margin-bottom:8px;font-weight:800}.mb-native-delivery-options label{display:grid;grid-template-columns:auto 1fr auto;align-items:start;gap:12px;padding:14px;border:1px solid var(--mb-border);border-radius:10px;cursor:pointer}.mb-native-delivery-options label.selected{border-color:var(--mb-accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--mb-accent) 14%,transparent)}.mb-native-delivery-options label>span{display:grid;gap:2px}.mb-native-delivery-options small{color:var(--mb-muted)}.mb-native-delivery-options code{margin-top:4px;color:var(--mb-text);font:12px/1.4 ui-monospace,SFMono-Regular,monospace}.mb-native-delivery-options em{border-radius:999px;background:var(--mb-soft);color:var(--mb-accent-dark);font-size:10px;font-style:normal;font-weight:800;padding:5px 8px;text-transform:uppercase}
989
+ @media(max-width:1100px){.mb-native-line.professional{grid-template-columns:repeat(2,minmax(0,1fr))}.mb-native-line.professional .mb-native-allowed{text-align:left}}
990
+ @media(max-width:620px){.mb-native-grid.two,.mb-native-line.professional{grid-template-columns:1fr}.mb-native-modal-backdrop{padding:0}.mb-native-modal{width:100%;max-height:100vh;border-radius:0;padding:18px}.mb-native-delivery-options label{grid-template-columns:auto 1fr}.mb-native-delivery-options em{grid-column:2}}
991
+ `;
879
992
  var NATIVE_BILL_REVIEW_STYLES = `
880
993
  .mb-native-review,.mb-native-status{font-family:var(--mb-font,Inter,ui-sans-serif,system-ui,sans-serif)}
881
994
  .mb-native-review,.mb-native-status{--mb-accent:#238dbd;--mb-accent-dark:#176f98;--mb-text:#203743;--mb-muted:#657982;--mb-border:#dbe6ea;--mb-soft:#f3f8fa;--mb-surface:#fff;color:var(--mb-text);font:14px/1.45 Inter,ui-sans-serif,system-ui,sans-serif}.mb-native-review *,.mb-native-status *{box-sizing:border-box}.mb-native-review{display:grid;gap:16px}.mb-native-heading{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;padding:6px 2px}.mb-native-heading h2,.mb-native-section h3,.mb-native-submit h3,.mb-native-status h3{margin:3px 0 2px;line-height:1.2}.mb-native-heading h2{font-size:25px}.mb-native-heading p,.mb-native-section p,.mb-native-submit p,.mb-native-status p{margin:0;color:var(--mb-muted)}.mb-native-eyebrow{color:#59727d;font-size:11px;font-weight:800;letter-spacing:.14em;text-transform:uppercase}.mb-native-total{display:flex;align-items:center;gap:18px}.mb-native-total span,.mb-native-section-head>span{border-radius:999px;background:var(--mb-soft);color:#58717c;font-size:11px;font-weight:800;padding:6px 10px;text-transform:capitalize}.mb-native-total strong{font-size:24px}.mb-native-summary{display:grid;grid-template-columns:repeat(4,1fr);margin:0;border:1px solid var(--mb-border);border-radius:12px;background:var(--mb-surface);overflow:hidden}.mb-native-summary div{padding:17px 20px;border-right:1px solid var(--mb-border)}.mb-native-summary div:last-child{border:0}.mb-native-summary dt,.mb-native-allowed span{color:#647982;font-size:10px;font-weight:800;letter-spacing:.12em;text-transform:uppercase}.mb-native-summary dd{margin:5px 0 0;font-weight:750}.mb-native-section{padding:20px;border:1px solid var(--mb-border);border-radius:14px;background:var(--mb-surface);box-shadow:0 8px 24px rgba(28,58,72,.04)}.mb-native-section-head{display:flex;align-items:start;justify-content:space-between;gap:16px;margin-bottom:17px}.mb-native-section h3,.mb-native-submit h3,.mb-native-status h3{font-size:19px}.mb-native-grid{display:grid;gap:14px}.mb-native-grid.three{grid-template-columns:repeat(3,minmax(0,1fr))}.mb-native-field{display:grid;gap:6px;min-width:0;color:var(--mb-text);font-size:12px;font-weight:750}.mb-native-field small{color:var(--mb-muted);font-size:inherit;font-weight:500}.mb-native-field input,.mb-native-attach select,.mb-native-attach input{width:100%;min-height:43px;border:1px solid var(--mb-border);border-radius:8px;background:#fff;color:var(--mb-text);font:inherit;padding:10px 12px}.mb-native-field input:focus,.mb-native-attach select:focus,.mb-native-attach input:focus{border-color:var(--mb-accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--mb-accent) 14%,transparent);outline:0}.mb-native-lines{display:grid;gap:10px}.mb-native-line{display:grid;grid-template-columns:1.1fr 1.1fr 110px 120px 28px;align-items:end;gap:12px;padding:13px;background:var(--mb-soft);border:1px solid #e3edf0;border-radius:10px}.mb-native-allowed{display:grid;gap:5px;padding:0 8px 11px;text-align:right}.mb-native-allowed strong{font-size:16px}.mb-native-remove{border:0;background:transparent;color:#667d86;cursor:pointer;font-size:20px;padding:7px}.mb-native-note{padding:13px 15px;border:1px solid #bdd9e4;border-radius:9px;background:#f2f9fc;color:#526d78}.mb-native-note strong{color:var(--mb-text);margin-right:12px}.mb-native-documents{list-style:none;margin:14px 0;padding:0}.mb-native-documents li{display:grid;grid-template-columns:42px 1fr auto 28px;align-items:center;gap:12px;padding:12px 4px;border-bottom:1px solid var(--mb-border)}.mb-native-documents li>div{display:grid}.mb-native-documents li span{color:var(--mb-muted);font-size:12px}.mb-native-file{display:grid;place-items:center;width:40px;height:40px;border-radius:8px;background:#eaf5f9;color:var(--mb-accent)!important;font-size:11px!important;font-weight:850}.mb-native-attach{display:grid;grid-template-columns:1fr 230px minmax(220px,1fr) auto;align-items:end;gap:12px;padding:15px;border-radius:10px;background:var(--mb-soft)}.mb-native-attach>div{display:grid;gap:3px}.mb-native-attach span{color:var(--mb-muted);font-size:12px}.mb-native-button{min-height:40px;border:1px solid var(--mb-border);border-radius:8px;background:#fff;color:var(--mb-text);cursor:pointer;font:inherit;font-weight:750;padding:9px 14px}.mb-native-button.primary{border-color:var(--mb-accent);background:var(--mb-accent);color:#fff}.mb-native-button.primary:hover{background:var(--mb-accent-dark)}.mb-native-button.secondary{background:#fff}.mb-native-button.quiet{min-height:auto;background:var(--mb-soft);padding:7px 11px}.mb-native-button:disabled,.mb-native-remove:disabled{cursor:not-allowed;opacity:.5}.mb-native-submit{display:grid;grid-template-columns:1fr auto;align-items:end;gap:18px;padding:22px;border:1px solid #bcd8e2;border-radius:14px;background:linear-gradient(135deg,#f3fafc,#eaf6fa)}.mb-native-submit fieldset{display:flex;gap:6px;margin:0;padding:0;border:0}.mb-native-submit legend{position:absolute;width:1px;height:1px;overflow:hidden}.mb-native-submit fieldset label{display:flex;align-items:center;gap:6px;padding:9px 11px;border:1px solid #c9dce3;border-radius:8px;background:#fff;font-weight:700}.mb-native-actions{display:flex;justify-content:flex-end;gap:10px;grid-column:1/-1}.mb-native-message{grid-column:1/-1;padding:10px 12px;border-radius:8px}.mb-native-message.error{background:#fff0ef;color:#9d3029}.mb-native-message.success{background:#edf9f2;color:#217449}.mb-native-status{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:20px;border:1px solid var(--mb-border);border-radius:12px;background:#fff}.mb-native-status h3{text-transform:capitalize}.mb-native-status dl{display:flex;margin:0}.mb-native-status dl div{min-width:110px;padding:0 18px;border-left:1px solid var(--mb-border)}.mb-native-status dt{color:var(--mb-muted);font-size:11px}.mb-native-status dd{margin:4px 0 0;font-size:17px;font-weight:800}@media(max-width:900px){.mb-native-grid.three{grid-template-columns:repeat(2,minmax(0,1fr))}.mb-native-summary{grid-template-columns:repeat(2,1fr)}.mb-native-summary div:nth-child(2){border-right:0}.mb-native-summary div:nth-child(-n+2){border-bottom:1px solid var(--mb-border)}.mb-native-line{grid-template-columns:1fr 1fr 90px}.mb-native-allowed{align-self:center}.mb-native-attach{grid-template-columns:1fr 1fr}.mb-native-submit{grid-template-columns:1fr}.mb-native-submit fieldset,.mb-native-actions{grid-column:1}.mb-native-actions{justify-content:start}}@media(max-width:620px){.mb-native-heading,.mb-native-total,.mb-native-status{align-items:start;flex-direction:column}.mb-native-grid.three,.mb-native-summary,.mb-native-line,.mb-native-attach{grid-template-columns:1fr}.mb-native-summary div,.mb-native-summary div:nth-child(2){border-right:0;border-bottom:1px solid var(--mb-border)}.mb-native-line{align-items:stretch}.mb-native-allowed{text-align:left}.mb-native-submit fieldset{display:grid;grid-template-columns:1fr 1fr}.mb-native-status dl{width:100%}.mb-native-status dl div{min-width:0;flex:1;padding:0 10px}.mb-native-status dl div:first-child{padding-left:0;border-left:0}}
@@ -930,7 +1043,7 @@ import {
930
1043
  useRef as useRef2,
931
1044
  useState as useState2
932
1045
  } from "react";
933
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1046
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
934
1047
  var DEFAULT_API_BASE_URL = "https://app.mindbill.org";
935
1048
  var DEFAULT_SESSION_ENDPOINT = "/api/mindbill/status-session";
936
1049
  var DEFAULT_REFRESH_INTERVAL = 6e4;
@@ -1153,10 +1266,10 @@ function ConnectedBillStatus({
1153
1266
  }) {
1154
1267
  const status = useBillStatus(options);
1155
1268
  if (status.isLoading && !status.data) {
1156
- return /* @__PURE__ */ jsx2(Fragment, { children: loadingFallback ?? /* @__PURE__ */ jsx2("div", { role: "status", children: "Loading bill status\u2026" }) });
1269
+ return /* @__PURE__ */ jsx2(Fragment2, { children: loadingFallback ?? /* @__PURE__ */ jsx2("div", { role: "status", children: "Loading bill status\u2026" }) });
1157
1270
  }
1158
1271
  if (status.error && !status.data) {
1159
- return /* @__PURE__ */ jsx2(Fragment, { children: errorFallback?.(status.error, status.refresh) ?? /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
1272
+ return /* @__PURE__ */ jsx2(Fragment2, { children: errorFallback?.(status.error, status.refresh) ?? /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
1160
1273
  status.error.message,
1161
1274
  " ",
1162
1275
  /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void status.refresh(), children: "Retry" })
@@ -1195,7 +1308,7 @@ import {
1195
1308
  createBillLifecycleClient
1196
1309
  } from "@mindbill/browser";
1197
1310
  import { createBillLifecycleClient as createBillLifecycleClient2 } from "@mindbill/browser";
1198
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1311
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1199
1312
  var DEFAULT_REFRESH_INTERVAL2 = 6e4;
1200
1313
  function openPdf(blob, filename) {
1201
1314
  const url = URL.createObjectURL(blob);
@@ -1296,8 +1409,12 @@ function useBillLifecycle({
1296
1409
  (query, claimNumber) => client.searchClaimsAdministrators(query, claimNumber),
1297
1410
  [client]
1298
1411
  );
1412
+ const getDeliveryOptions = useCallback2(
1413
+ () => client.getDeliveryOptions(),
1414
+ [client]
1415
+ );
1299
1416
  const submitBill = useCallback2(
1300
- (input, route) => mutate(() => client.submitBill(input, route)),
1417
+ (input, submission) => mutate(() => client.submitBill(input, submission)),
1301
1418
  [client, mutate]
1302
1419
  );
1303
1420
  const addAttachment = useCallback2(
@@ -1353,6 +1470,7 @@ function useBillLifecycle({
1353
1470
  isMutating,
1354
1471
  refresh,
1355
1472
  searchClaimsAdministrators,
1473
+ getDeliveryOptions,
1356
1474
  saveReview,
1357
1475
  submitBill,
1358
1476
  addAttachment,
@@ -1440,11 +1558,11 @@ function ConnectedBillLifecycle({
1440
1558
  }));
1441
1559
  }, [data, onChanged]);
1442
1560
  if (lifecycle.isLoading && !data) {
1443
- return /* @__PURE__ */ jsx3(Fragment2, { children: loadingFallback ?? /* @__PURE__ */ jsx3("div", { className: "mb-lifecycle-loading", children: "Loading billing\u2026" }) });
1561
+ return /* @__PURE__ */ jsx3(Fragment3, { children: loadingFallback ?? /* @__PURE__ */ jsx3("div", { className: "mb-lifecycle-loading", children: "Loading billing\u2026" }) });
1444
1562
  }
1445
1563
  if (!data) {
1446
1564
  const error = lifecycle.error ?? new Error("Bill could not be loaded.");
1447
- return /* @__PURE__ */ jsx3(Fragment2, { children: errorFallback?.(error, lifecycle.refresh) ?? /* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-error", role: "alert", children: [
1565
+ return /* @__PURE__ */ jsx3(Fragment3, { children: errorFallback?.(error, lifecycle.refresh) ?? /* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-error", role: "alert", children: [
1448
1566
  /* @__PURE__ */ jsx3("strong", { children: "Billing is unavailable." }),
1449
1567
  /* @__PURE__ */ jsx3("span", { children: error.message }),
1450
1568
  /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => void lifecycle.refresh(), children: "Try again" })
@@ -1488,9 +1606,10 @@ function ConnectedBillLifecycle({
1488
1606
  ...features ? { features } : {},
1489
1607
  disabled: lifecycle.isMutating,
1490
1608
  onSearchClaimsAdministrators: lifecycle.searchClaimsAdministrators,
1609
+ onGetDeliveryOptions: lifecycle.getDeliveryOptions,
1491
1610
  onSave: lifecycle.saveReview,
1492
- onSubmit: async (input, route) => {
1493
- await complete("Bill submitted.", () => lifecycle.submitBill(input, route));
1611
+ onSubmit: async (input, submission) => {
1612
+ await complete("Bill submitted.", () => lifecycle.submitBill(input, submission));
1494
1613
  },
1495
1614
  onAddAttachment: async (file, type, description) => {
1496
1615
  await lifecycle.addAttachment(file, type, description);