@mindbill/react 0.13.1 → 0.14.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.ts CHANGED
@@ -133,6 +133,9 @@ type BillReviewLineItem = {
133
133
  units: number;
134
134
  charge: number;
135
135
  feeSchedule?: number;
136
+ serviceDate?: string | null;
137
+ serviceDateEnd?: string | null;
138
+ diagnosisPointers?: number[];
136
139
  };
137
140
  /** Keeps completed/partial lines plus one keyboard-ready empty row. */
138
141
  declare function ensureTrailingProcedureLine(lines: readonly BillReviewLineItem[]): BillReviewLineItem[];
@@ -174,6 +177,7 @@ type BillReviewClaimPatternStatus = {
174
177
  type BillReviewData = {
175
178
  bill: {
176
179
  id: string;
180
+ billingMode: "med_legal" | "professional";
177
181
  billNumber: string | number;
178
182
  status: string;
179
183
  transmissionState?: string;
@@ -237,13 +241,53 @@ type BillReviewSaveInput = {
237
241
  code: string;
238
242
  modifiers: string[];
239
243
  units: number;
244
+ charge?: number;
245
+ serviceDate?: string | null;
246
+ serviceDateEnd?: string | null;
247
+ diagnosisPointers?: number[];
240
248
  }>;
241
249
  };
242
250
  type BillSubmissionRoute = "ebill" | "fax" | "mail" | "email";
251
+ type BillDeliveryOption = {
252
+ route: BillSubmissionRoute;
253
+ label: string;
254
+ detail: string;
255
+ fallback: boolean;
256
+ confidence: string;
257
+ payerName: string;
258
+ target?: string;
259
+ chKey?: string;
260
+ payerId?: string;
261
+ printAndMail?: boolean;
262
+ costUsd?: number;
263
+ };
264
+ type BillDeliveryOptions = {
265
+ payerName: string;
266
+ recommended: BillDeliveryOption;
267
+ options: BillDeliveryOption[];
268
+ contacts: {
269
+ faxNumber?: string | null;
270
+ claimsEmail?: string | null;
271
+ portalUrl?: string | null;
272
+ mailingAddress?: string | null;
273
+ };
274
+ };
275
+ type BillSubmissionInput = {
276
+ route: BillSubmissionRoute;
277
+ destination?: {
278
+ faxNumber?: string;
279
+ email?: string;
280
+ mailingAddress?: string;
281
+ };
282
+ attention?: string;
283
+ subject?: string;
284
+ note?: string;
285
+ };
243
286
  type BillReviewFormProps = {
244
287
  data: BillReviewData;
245
288
  onSave: (input: BillReviewSaveInput) => Promise<BillReviewData | void>;
246
- onSubmit: (input: BillReviewSaveInput, route: BillSubmissionRoute) => Promise<void>;
289
+ onSubmit: (input: BillReviewSaveInput, submission: BillSubmissionInput) => Promise<void>;
290
+ onGetDeliveryOptions: () => Promise<BillDeliveryOptions>;
247
291
  onAddAttachment: (file: File, documentType: BillReviewDocumentType, description?: string) => Promise<void>;
248
292
  onRemoveAttachment: (attachmentId: string) => Promise<void>;
249
293
  onOpenAttachment?: (attachment: BillReviewAttachment) => void;
@@ -276,7 +320,7 @@ type BillReviewDraft = {
276
320
  lineItems: BillReviewLineItem[];
277
321
  };
278
322
  declare function buildBillReviewSaveInput(draft: BillReviewDraft): BillReviewSaveInput;
279
- declare function BillReviewForm({ data, onSave, onSubmit, onAddAttachment, onRemoveAttachment, onOpenAttachment, onSearchClaimsAdministrators, className, style, appearance, features, disabled, }: BillReviewFormProps): ReactElement;
323
+ declare function BillReviewForm({ data, onSave, onSubmit, onGetDeliveryOptions, onAddAttachment, onRemoveAttachment, onOpenAttachment, onSearchClaimsAdministrators, className, style, appearance, features, disabled, }: BillReviewFormProps): ReactElement;
280
324
  type BillStatusSummaryProps = {
281
325
  status: string;
282
326
  submittedAt?: string | null;
@@ -377,6 +421,7 @@ type UseBillLifecycleResult = {
377
421
  isMutating: boolean;
378
422
  refresh: () => Promise<void>;
379
423
  searchClaimsAdministrators: BillLifecycleClient["searchClaimsAdministrators"];
424
+ getDeliveryOptions: BillLifecycleClient["getDeliveryOptions"];
380
425
  saveReview: BillLifecycleClient["saveReview"];
381
426
  submitBill: BillLifecycleClient["submitBill"];
382
427
  addAttachment: BillLifecycleClient["addAttachment"];
package/dist/index.js CHANGED
@@ -102,7 +102,7 @@ function mindBillAppearanceStyle(appearance, style) {
102
102
 
103
103
  // src/native-bill-review.tsx
104
104
  import { useEffect, useId, useMemo, useRef, useState } from "react";
105
- import { jsx, jsxs } from "react/jsx-runtime";
105
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
106
106
  var EMPTY_PROCEDURE_LINE = {
107
107
  code: "",
108
108
  modifiers: [],
@@ -110,7 +110,7 @@ var EMPTY_PROCEDURE_LINE = {
110
110
  charge: 0
111
111
  };
112
112
  function isEmptyProcedureLine(line) {
113
- return !line.code.trim() && line.modifiers.length === 0 && line.units === 1;
113
+ return !line.code.trim() && line.modifiers.length === 0 && line.units === 1 && !line.serviceDate && !line.serviceDateEnd && !line.charge && !line.diagnosisPointers?.length;
114
114
  }
115
115
  function ensureTrailingProcedureLine(lines) {
116
116
  const entered = lines.filter((line) => !isEmptyProcedureLine(line)).map((line) => ({ ...line, modifiers: [...line.modifiers] }));
@@ -226,11 +226,15 @@ function buildBillReviewSaveInput(draft) {
226
226
  billingProvider: { ...draft.billingProvider },
227
227
  renderingProvider: { ...draft.clinician },
228
228
  placeOfService: { ...draft.location },
229
- lineItems: draft.lineItems.filter((line) => line.code.trim()).map(({ id, code, modifiers, units }) => ({
229
+ lineItems: draft.lineItems.filter((line) => line.code.trim()).map(({ id, code, modifiers, units, charge, serviceDate, serviceDateEnd, diagnosisPointers }) => ({
230
230
  ...id ? { id } : {},
231
231
  code: code.trim().toUpperCase(),
232
232
  modifiers,
233
- units
233
+ units,
234
+ ...charge ? { charge } : {},
235
+ ...serviceDate ? { serviceDate } : {},
236
+ ...serviceDateEnd ? { serviceDateEnd } : {},
237
+ ...diagnosisPointers?.length ? { diagnosisPointers } : {}
234
238
  }))
235
239
  };
236
240
  }
@@ -391,6 +395,7 @@ function BillReviewForm({
391
395
  data,
392
396
  onSave,
393
397
  onSubmit,
398
+ onGetDeliveryOptions,
394
399
  onAddAttachment,
395
400
  onRemoveAttachment,
396
401
  onOpenAttachment,
@@ -407,13 +412,15 @@ function BillReviewForm({
407
412
  );
408
413
  const [payerResults, setPayerResults] = useState([]);
409
414
  const [payerBusy, setPayerBusy] = useState(false);
410
- const [route, setRoute] = useState("ebill");
415
+ const [deliveryOptions, setDeliveryOptions] = useState(null);
416
+ const [submission, setSubmission] = useState({ route: "ebill" });
417
+ const [showSubmit, setShowSubmit] = useState(false);
418
+ const [deliveryBusy, setDeliveryBusy] = useState(false);
411
419
  const [file, setFile] = useState(null);
412
420
  const [documentType, setDocumentType] = useState("other");
413
421
  const [busy, setBusy] = useState("");
414
422
  const [error, setError] = useState("");
415
423
  const [notice, setNotice] = useState("");
416
- const routeName = useId();
417
424
  const editable = data.bill.status === "incomplete" && !disabled;
418
425
  useEffect(() => {
419
426
  setDraft(toDraft(data));
@@ -479,7 +486,7 @@ function BillReviewForm({
479
486
  if (!draft.claimNumber.trim()) result.push("Claim number");
480
487
  if (!draft.doi) result.push("Date of injury");
481
488
  if (!adjFormatValid) result.push("Valid WCAB / ADJ number");
482
- if (!draft.dos) result.push("Date of service");
489
+ if (data.bill.billingMode === "med_legal" && !draft.dos) result.push("Date of service");
483
490
  if (!draft.billingProvider.name.trim()) result.push("Practice name");
484
491
  if (!draft.billingProvider.taxId.trim()) result.push("Tax ID");
485
492
  if (!draft.billingProvider.npi.trim()) result.push("Billing NPI");
@@ -487,8 +494,11 @@ function BillReviewForm({
487
494
  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
495
  const completedLines = draft.lineItems.filter((line) => line.code.trim());
489
496
  if (!completedLines.length || completedLines.some((line) => line.units <= 0)) result.push("Valid procedure line");
497
+ if (data.bill.billingMode === "professional" && completedLines.some((line) => !line.serviceDate || line.charge <= 0)) {
498
+ result.push("Service date and charge on every procedure line");
499
+ }
490
500
  return result;
491
- }, [adjFormatValid, draft]);
501
+ }, [adjFormatValid, data.bill.billingMode, draft]);
492
502
  const canSubmit = blockers.length === 0;
493
503
  const updateBillingProvider = (key, value) => setDraft((current) => ({
494
504
  ...current,
@@ -524,7 +534,33 @@ function BillReviewForm({
524
534
  if (updated) setDraft(toDraft(updated));
525
535
  });
526
536
  };
527
- const handleSubmit = () => run("submit", () => onSubmit(buildBillReviewSaveInput(draft), route));
537
+ const openSubmit = async () => {
538
+ setDeliveryBusy(true);
539
+ setError("");
540
+ try {
541
+ const next = await onGetDeliveryOptions();
542
+ setDeliveryOptions(next);
543
+ const recommended = next.recommended ?? next.options[0];
544
+ if (!recommended) throw new Error("No delivery route is available for this payer.");
545
+ setSubmission({ route: recommended.route });
546
+ setShowSubmit(true);
547
+ } catch (cause) {
548
+ setError(cause instanceof Error ? cause.message : "Delivery routes could not be loaded.");
549
+ } finally {
550
+ setDeliveryBusy(false);
551
+ }
552
+ };
553
+ const selectedDelivery = deliveryOptions?.options.find((option) => option.route === submission.route);
554
+ const destinationLabel = submission.route === "fax" ? "Fax number" : submission.route === "email" ? "Email address" : submission.route === "mail" ? "Mailing address" : "";
555
+ 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 ?? "" : "";
556
+ const setDestination = (value) => setSubmission((current) => {
557
+ const destination = current.route === "fax" ? { faxNumber: value } : current.route === "email" ? { email: value } : { mailingAddress: value };
558
+ return { ...current, destination };
559
+ });
560
+ const handleSubmit = () => run("submit", async () => {
561
+ await onSubmit(buildBillReviewSaveInput(draft), submission);
562
+ setShowSubmit(false);
563
+ });
528
564
  const attach = async () => {
529
565
  if (!file) return;
530
566
  setBusy("attachment");
@@ -550,6 +586,7 @@ function BillReviewForm({
550
586
  children: [
551
587
  /* @__PURE__ */ jsx("style", { children: NATIVE_BILL_REVIEW_STYLES }),
552
588
  /* @__PURE__ */ jsx("style", { children: NATIVE_THEME_OVERRIDE_STYLES }),
589
+ /* @__PURE__ */ jsx("style", { children: NATIVE_SUBMISSION_DIALOG_STYLES }),
553
590
  /* @__PURE__ */ jsxs("header", { className: "mb-native-heading", children: [
554
591
  /* @__PURE__ */ jsxs("div", { children: [
555
592
  /* @__PURE__ */ jsx("span", { className: "mb-native-eyebrow", children: "Billing review" }),
@@ -717,30 +754,32 @@ function BillReviewForm({
717
754
  /* @__PURE__ */ jsxs("section", { className: sectionClass, children: [
718
755
  /* @__PURE__ */ jsx("div", { className: "mb-native-section-head", children: /* @__PURE__ */ jsxs("div", { children: [
719
756
  /* @__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." })
757
+ /* @__PURE__ */ jsxs("p", { children: [
758
+ 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.",
759
+ " A new row appears as you type."
760
+ ] })
721
761
  ] }) }),
722
- features?.codingPresets === false ? null : /* @__PURE__ */ jsxs("div", { className: "mb-native-presets", role: "group", "aria-label": "Evaluation billing profile", children: [
762
+ data.bill.billingMode === "professional" || features?.codingPresets === false ? null : /* @__PURE__ */ jsxs("div", { className: "mb-native-presets", role: "group", "aria-label": "Evaluation billing profile", children: [
723
763
  [["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
764
  /* @__PURE__ */ jsx("span", { children: "Sets evaluator modifiers across med-legal lines. You can still edit each line." })
725
765
  ] }),
726
- /* @__PURE__ */ jsx("div", { className: "mb-native-lines", children: draft.lineItems.map((line, index) => /* @__PURE__ */ jsxs("div", { className: "mb-native-line", children: [
766
+ /* @__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
767
  /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
728
768
  /* @__PURE__ */ jsx("span", { children: "Procedure" }),
729
- /* @__PURE__ */ jsxs("select", { disabled: !editable, value: line.code, onChange: (event) => {
769
+ data.bill.billingMode === "professional" ? /* @__PURE__ */ jsx("input", { disabled: !editable, placeholder: "CPT / HCPCS code", value: line.code, onChange: (event) => {
770
+ const code = event.target.value.toUpperCase();
771
+ setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, code } : item)) }));
772
+ } }) : /* @__PURE__ */ jsxs("select", { disabled: !editable, value: line.code, onChange: (event) => {
730
773
  const code = event.target.value;
731
774
  setDraft((current) => {
732
775
  const lineItems = current.lineItems.map((item, itemIndex) => {
733
776
  if (itemIndex !== index) return item;
734
- const presetLine = applyPreset(
735
- [{ ...item, code }],
736
- inferPreset(current.lineItems)
737
- )[0];
777
+ const presetLine = applyPreset([{ ...item, code }], inferPreset(current.lineItems))[0];
738
778
  return { ...item, code, modifiers: presetLine?.modifiers || [] };
739
779
  });
740
780
  return { ...current, lineItems: ensureTrailingProcedureLine(lineItems) };
741
781
  });
742
782
  }, children: [
743
- line.code && !PROCEDURES.some(([code]) => code === line.code) ? /* @__PURE__ */ jsx("option", { value: line.code, children: line.code }) : null,
744
783
  /* @__PURE__ */ jsx("option", { value: "", children: "Select code\u2026" }),
745
784
  PROCEDURES.map(([code, label]) => /* @__PURE__ */ jsxs("option", { value: code, children: [
746
785
  code,
@@ -748,10 +787,16 @@ function BillReviewForm({
748
787
  label
749
788
  ] }, code))
750
789
  ] }),
751
- line.code ? /* @__PURE__ */ jsx("small", { children: PROCEDURES.find(([code]) => code === line.code)?.[1] }) : null
790
+ data.bill.billingMode === "med_legal" && line.code ? /* @__PURE__ */ jsx("small", { children: PROCEDURES.find(([code]) => code === line.code)?.[1] }) : null
752
791
  ] }),
753
792
  /* @__PURE__ */ jsxs("div", { className: "mb-native-modifiers", children: [
754
- /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
793
+ data.bill.billingMode === "professional" ? /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
794
+ /* @__PURE__ */ jsx("span", { children: "Modifiers" }),
795
+ /* @__PURE__ */ jsx("input", { disabled: !editable, placeholder: "e.g. 25, 59", value: line.modifiers.join(", "), onChange: (event) => {
796
+ const modifiers = event.target.value.toUpperCase().split(/[ ,]+/).map((value) => value.replace(/^-/, "")).filter(Boolean);
797
+ setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, modifiers } : item)) }));
798
+ } })
799
+ ] }) : /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
755
800
  /* @__PURE__ */ jsx("span", { children: "Modifiers" }),
756
801
  /* @__PURE__ */ jsxs("select", { disabled: !editable, value: "", onChange: (event) => {
757
802
  const modifier = event.target.value;
@@ -767,16 +812,43 @@ function BillReviewForm({
767
812
  ] }, value))
768
813
  ] })
769
814
  ] }),
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: [
815
+ /* @__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
816
  "-",
772
817
  modifier,
773
818
  " \xD7"
774
- ] }, modifier)) })
819
+ ] }, modifier)) : null })
775
820
  ] }),
776
821
  /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
777
822
  /* @__PURE__ */ jsx("span", { children: "Units" }),
778
823
  /* @__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
824
  ] }),
825
+ data.bill.billingMode === "professional" ? /* @__PURE__ */ jsxs(Fragment, { children: [
826
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
827
+ /* @__PURE__ */ jsx("span", { children: "Service date" }),
828
+ /* @__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)) })) })
829
+ ] }),
830
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
831
+ /* @__PURE__ */ jsxs("span", { children: [
832
+ "End date ",
833
+ /* @__PURE__ */ jsx("small", { children: "Optional" })
834
+ ] }),
835
+ /* @__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)) })) })
836
+ ] }),
837
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
838
+ /* @__PURE__ */ jsx("span", { children: "Charge" }),
839
+ /* @__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)) })) })
840
+ ] }),
841
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
842
+ /* @__PURE__ */ jsxs("span", { children: [
843
+ "Diagnosis pointers ",
844
+ /* @__PURE__ */ jsx("small", { children: "1\u201312" })
845
+ ] }),
846
+ /* @__PURE__ */ jsx("input", { inputMode: "numeric", disabled: !editable, value: (line.diagnosisPointers || []).join(", "), onChange: (event) => {
847
+ const diagnosisPointers = event.target.value.split(/[ ,]+/).map(Number).filter((value) => Number.isInteger(value) && value >= 1 && value <= 12);
848
+ setDraft((current) => ({ ...current, lineItems: ensureTrailingProcedureLine(current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, diagnosisPointers } : item)) }));
849
+ } })
850
+ ] })
851
+ ] }) : null,
780
852
  /* @__PURE__ */ jsxs("div", { className: "mb-native-allowed", children: [
781
853
  /* @__PURE__ */ jsx("span", { children: "Allowed" }),
782
854
  /* @__PURE__ */ jsx("strong", { children: money(line.charge) })
@@ -824,13 +896,6 @@ function BillReviewForm({
824
896
  /* @__PURE__ */ jsx("h3", { children: "Submit this bill" }),
825
897
  /* @__PURE__ */ jsx("p", { children: "After submission, status, payments, denials, and resubmissions stay available here." })
826
898
  ] }),
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
899
  error ? /* @__PURE__ */ jsx("div", { className: "mb-native-message error", role: "alert", children: error }) : null,
835
900
  notice ? /* @__PURE__ */ jsx("div", { className: "mb-native-message success", role: "status", children: notice }) : null,
836
901
  !canSubmit ? /* @__PURE__ */ jsxs("div", { className: "mb-native-blockers", role: "status", children: [
@@ -839,9 +904,43 @@ function BillReviewForm({
839
904
  ] }) : null,
840
905
  /* @__PURE__ */ jsxs("div", { className: "mb-native-actions", children: [
841
906
  /* @__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" })
907
+ /* @__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
908
  ] })
844
- ] })
909
+ ] }),
910
+ showSubmit && deliveryOptions ? /* @__PURE__ */ jsx("div", { className: "mb-native-modal-backdrop", role: "presentation", onMouseDown: (event) => {
911
+ if (event.target === event.currentTarget && busy !== "submit") setShowSubmit(false);
912
+ }, children: /* @__PURE__ */ jsxs("section", { className: "mb-native-modal", role: "dialog", "aria-modal": "true", "aria-labelledby": "mb-native-submit-title", children: [
913
+ /* @__PURE__ */ jsxs("header", { children: [
914
+ /* @__PURE__ */ jsxs("div", { children: [
915
+ /* @__PURE__ */ jsx("span", { className: "mb-native-eyebrow", children: "Send bill" }),
916
+ /* @__PURE__ */ jsx("h3", { id: "mb-native-submit-title", children: "Choose a delivery route" }),
917
+ /* @__PURE__ */ jsx("p", { children: deliveryOptions.payerName || "Claims administrator" })
918
+ ] }),
919
+ /* @__PURE__ */ jsx("button", { type: "button", className: "mb-native-close", "aria-label": "Close", disabled: busy === "submit", onClick: () => setShowSubmit(false), children: "\xD7" })
920
+ ] }),
921
+ /* @__PURE__ */ jsxs("fieldset", { className: "mb-native-delivery-options", children: [
922
+ /* @__PURE__ */ jsx("legend", { children: "Available delivery routes" }),
923
+ deliveryOptions.options.map((option) => /* @__PURE__ */ jsxs("label", { className: submission.route === option.route ? "selected" : "", children: [
924
+ /* @__PURE__ */ jsx("input", { type: "radio", name: "mindbill-delivery-route", checked: submission.route === option.route, onChange: () => setSubmission({ route: option.route }) }),
925
+ /* @__PURE__ */ jsxs("span", { children: [
926
+ /* @__PURE__ */ jsx("strong", { children: option.label }),
927
+ /* @__PURE__ */ jsx("small", { children: option.detail }),
928
+ option.target ? /* @__PURE__ */ jsx("code", { children: option.target }) : null
929
+ ] }),
930
+ deliveryOptions.recommended?.route === option.route ? /* @__PURE__ */ jsx("em", { children: "Recommended" }) : null
931
+ ] }, `${option.route}-${option.target || "default"}`))
932
+ ] }),
933
+ submission.route !== "ebill" ? /* @__PURE__ */ jsxs("div", { className: "mb-native-grid two", children: [
934
+ /* @__PURE__ */ jsx(Field, { label: destinationLabel, required: true, value: destinationValue, onChange: setDestination, hint: "You can override the payer directory value for this submission." }),
935
+ /* @__PURE__ */ jsx(Field, { label: "Attention", optional: true, value: submission.attention || "", onChange: (attention) => setSubmission((current) => ({ ...current, attention })) }),
936
+ submission.route === "email" ? /* @__PURE__ */ jsx(Field, { label: "Subject", optional: true, value: submission.subject || "", onChange: (subject) => setSubmission((current) => ({ ...current, subject })) }) : null
937
+ ] }) : null,
938
+ /* @__PURE__ */ jsx(Field, { label: "Delivery note", optional: true, value: submission.note || "", onChange: (note) => setSubmission((current) => ({ ...current, note })) }),
939
+ /* @__PURE__ */ jsxs("footer", { children: [
940
+ /* @__PURE__ */ jsx("button", { className: "mb-native-button secondary", type: "button", disabled: busy === "submit", onClick: () => setShowSubmit(false), children: "Cancel" }),
941
+ /* @__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}` })
942
+ ] })
943
+ ] }) }) : null
845
944
  ]
846
945
  }
847
946
  );
@@ -876,6 +975,19 @@ function BillStatusSummary({ status, submittedAt, agingDays, updatedAt, totalCha
876
975
  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
976
  ] });
878
977
  }
978
+ var NATIVE_SUBMISSION_DIALOG_STYLES = `
979
+ .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}
980
+ .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}
981
+ .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}
982
+ .mb-native-grid.two{grid-template-columns:repeat(2,minmax(0,1fr))}
983
+ .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)}
984
+ .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)}
985
+ .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)}
986
+ .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}
987
+ .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}
988
+ @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}}
989
+ @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}}
990
+ `;
879
991
  var NATIVE_BILL_REVIEW_STYLES = `
880
992
  .mb-native-review,.mb-native-status{font-family:var(--mb-font,Inter,ui-sans-serif,system-ui,sans-serif)}
881
993
  .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 +1042,7 @@ import {
930
1042
  useRef as useRef2,
931
1043
  useState as useState2
932
1044
  } from "react";
933
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1045
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
934
1046
  var DEFAULT_API_BASE_URL = "https://app.mindbill.org";
935
1047
  var DEFAULT_SESSION_ENDPOINT = "/api/mindbill/status-session";
936
1048
  var DEFAULT_REFRESH_INTERVAL = 6e4;
@@ -1153,10 +1265,10 @@ function ConnectedBillStatus({
1153
1265
  }) {
1154
1266
  const status = useBillStatus(options);
1155
1267
  if (status.isLoading && !status.data) {
1156
- return /* @__PURE__ */ jsx2(Fragment, { children: loadingFallback ?? /* @__PURE__ */ jsx2("div", { role: "status", children: "Loading bill status\u2026" }) });
1268
+ return /* @__PURE__ */ jsx2(Fragment2, { children: loadingFallback ?? /* @__PURE__ */ jsx2("div", { role: "status", children: "Loading bill status\u2026" }) });
1157
1269
  }
1158
1270
  if (status.error && !status.data) {
1159
- return /* @__PURE__ */ jsx2(Fragment, { children: errorFallback?.(status.error, status.refresh) ?? /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
1271
+ return /* @__PURE__ */ jsx2(Fragment2, { children: errorFallback?.(status.error, status.refresh) ?? /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
1160
1272
  status.error.message,
1161
1273
  " ",
1162
1274
  /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void status.refresh(), children: "Retry" })
@@ -1195,7 +1307,7 @@ import {
1195
1307
  createBillLifecycleClient
1196
1308
  } from "@mindbill/browser";
1197
1309
  import { createBillLifecycleClient as createBillLifecycleClient2 } from "@mindbill/browser";
1198
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1310
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1199
1311
  var DEFAULT_REFRESH_INTERVAL2 = 6e4;
1200
1312
  function openPdf(blob, filename) {
1201
1313
  const url = URL.createObjectURL(blob);
@@ -1296,8 +1408,12 @@ function useBillLifecycle({
1296
1408
  (query, claimNumber) => client.searchClaimsAdministrators(query, claimNumber),
1297
1409
  [client]
1298
1410
  );
1411
+ const getDeliveryOptions = useCallback2(
1412
+ () => client.getDeliveryOptions(),
1413
+ [client]
1414
+ );
1299
1415
  const submitBill = useCallback2(
1300
- (input, route) => mutate(() => client.submitBill(input, route)),
1416
+ (input, submission) => mutate(() => client.submitBill(input, submission)),
1301
1417
  [client, mutate]
1302
1418
  );
1303
1419
  const addAttachment = useCallback2(
@@ -1353,6 +1469,7 @@ function useBillLifecycle({
1353
1469
  isMutating,
1354
1470
  refresh,
1355
1471
  searchClaimsAdministrators,
1472
+ getDeliveryOptions,
1356
1473
  saveReview,
1357
1474
  submitBill,
1358
1475
  addAttachment,
@@ -1440,11 +1557,11 @@ function ConnectedBillLifecycle({
1440
1557
  }));
1441
1558
  }, [data, onChanged]);
1442
1559
  if (lifecycle.isLoading && !data) {
1443
- return /* @__PURE__ */ jsx3(Fragment2, { children: loadingFallback ?? /* @__PURE__ */ jsx3("div", { className: "mb-lifecycle-loading", children: "Loading billing\u2026" }) });
1560
+ return /* @__PURE__ */ jsx3(Fragment3, { children: loadingFallback ?? /* @__PURE__ */ jsx3("div", { className: "mb-lifecycle-loading", children: "Loading billing\u2026" }) });
1444
1561
  }
1445
1562
  if (!data) {
1446
1563
  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: [
1564
+ return /* @__PURE__ */ jsx3(Fragment3, { children: errorFallback?.(error, lifecycle.refresh) ?? /* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-error", role: "alert", children: [
1448
1565
  /* @__PURE__ */ jsx3("strong", { children: "Billing is unavailable." }),
1449
1566
  /* @__PURE__ */ jsx3("span", { children: error.message }),
1450
1567
  /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => void lifecycle.refresh(), children: "Try again" })
@@ -1488,9 +1605,10 @@ function ConnectedBillLifecycle({
1488
1605
  ...features ? { features } : {},
1489
1606
  disabled: lifecycle.isMutating,
1490
1607
  onSearchClaimsAdministrators: lifecycle.searchClaimsAdministrators,
1608
+ onGetDeliveryOptions: lifecycle.getDeliveryOptions,
1491
1609
  onSave: lifecycle.saveReview,
1492
- onSubmit: async (input, route) => {
1493
- await complete("Bill submitted.", () => lifecycle.submitBill(input, route));
1610
+ onSubmit: async (input, submission) => {
1611
+ await complete("Bill submitted.", () => lifecycle.submitBill(input, submission));
1494
1612
  },
1495
1613
  onAddAttachment: async (file, type, description) => {
1496
1614
  await lifecycle.addAttachment(file, type, description);