@mindbill/react 0.41.2 → 0.42.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/README.md CHANGED
@@ -191,7 +191,8 @@ The component includes the interaction model, not just the markup:
191
191
  - paste-friendly `MM/DD/YYYY` date fields and required-field asterisks;
192
192
  - ZIP-to-city/state completion through MindBill's authenticated postal directory;
193
193
  - complete, server-backed ICD-10 search with an alphabetized 100-code first page, automatic 100-code scroll paging, common-injury quick picks, and removable chips;
194
- - canonical claims-administrator matching through the authenticated MindBill payer directory: exact aliases select automatically, while fuzzy matches show up to five explicit suggestions with claim-number pattern evidence;
194
+ - an authenticated claims-administrator browser that opens to an alphabetized 50-item page, loads later pages on scroll, searches from the first character, and preserves exact-name and claim-number evidence;
195
+ - explicit routing-payer selection when the administrator requires it, with aliases, affiliated entities, claim-number hints, delivery type, clearinghouse routes, and payer identifiers shown in context;
195
196
  - QME, AME, and Psych QME evaluation modes with medical-legal modifier defaults; Psych QME also seeds `Z04.6` when no more specific diagnosis was supplied, and exposes it as a Psych quick pick;
196
197
  - a searchable rendering-provider taxonomy combobox that accepts either a human-readable specialty search or an exact 10-character taxonomy code;
197
198
  - searchable workers-comp procedure/modifier controls, medical-legal fee-schedule amounts, totals, valid manual CPT/HCPCS entry, and an automatically maintained empty line;
@@ -317,7 +318,7 @@ Never send a Partner API key or long-lived credential to React/browser code.
317
318
 
318
319
  ## Bill tasks worklist, submissions ribbon, and payer status calls
319
320
 
320
- `BillTasksDashboard` is the daisyBill-style Bill Tasks worklist: one tone-colored card per task section, rows bucketed by age (1-30 / 31-60 / 61-90 / 91-180 / 181+ days), clickable counts that carry the bill refs behind them, and a grand-total card. It is purely props-driven — aggregate your own work items with `buildBillTasksDashboard` (re-exported from `@mindbill/browser`):
321
+ `BillTasksDashboard` is a Bill Tasks worklist: one tone-colored card per task section, rows bucketed by age (1-30 / 31-60 / 61-90 / 91-180 / 181+ days), clickable counts that carry the bill refs behind them, and a grand-total card. It is purely props-driven — aggregate your own work items with `buildBillTasksDashboard` (re-exported from `@mindbill/browser`):
321
322
 
322
323
  ```tsx
323
324
  import { BillTasksDashboard, buildBillTasksDashboard } from "@mindbill/react";
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { MindBillAppearance, MindBillEventDetail, MindBillErrorDetail } from '@mindbill/embed';
2
2
  export { MindBillAppearance, MindBillErrorDetail, MindBillEventDetail } from '@mindbill/embed';
3
3
  import { CSSProperties, ReactElement, ReactNode } from 'react';
4
- import { BillReviewData as BillReviewData$1, BillLifecycleDelivery, BillReviewAttachment as BillReviewAttachment$1, BillReviewPayerOption, BrowserBillSubmissionResult, BillLifecycleSessionProvider, BillReviewPayer as BillReviewPayer$1, BillClaimsAdministratorDirectory, BrowserBillSubmissionDocument, BillDeliveryOptions as BillDeliveryOptions$1, SubmitBillInput, BillTasksDashboardData, BillTasksAgingBucket, BillHistoryEntry, ReportBillStatusInput, OrganizationProfileData, BillRemittanceSummary, BillEorDocument, BillPaymentRecord, BillLifecycleAction, BillRejection, BillLifecycleData, BillLifecycleClientOptions, BillLifecycleClient } from '@mindbill/browser';
5
- export { BILL_TASKS_AGING_BUCKETS, BillActivityRecord, BillClaimsAdministratorContact, BillClaimsAdministratorDirectory, BillClaimsAdministratorMailingAddress, BillClaimsAdministratorPattern, BillClaimsAdministratorPayer, BillEorDocument, BillLifecycleAction, BillLifecycleActionId, BillLifecycleClient, BillLifecycleClientOptions, BillLifecycleData, BillLifecycleDelivery, BillLifecycleSession, BillLifecycleSessionProvider, BillLifecycleSessionRequest, BillPaymentRecord, BillRejection, BillRemittanceSummary, BillReviewPayerOption, BillTasksAgingBucket, BillTasksDashboardData, BillTasksDashboardItem, BillTasksDashboardRow, BillTasksDashboardSection, BillTasksDashboardSectionInput, BillTasksDashboardTone, BrowserBillSubmissionResult, CloseBillInput, PostBillPaymentInput, REPORT_BILL_STATUS_OPTIONS, ReopenBillInput, ReportBillStatusContacts, ReportBillStatusId, ReportBillStatusInput, SECOND_REVIEW_REASON_TEMPLATE, SECOND_REVIEW_WINDOW_DAYS, SecondReviewDeadline, SendDuplicateBillInput, SubmitSecondReviewInput, billTasksAgingBucketIndex, buildBillTasksDashboard, createBillLifecycleClient, reportBillStatusContacts, secondReviewDeadline } from '@mindbill/browser';
4
+ import { BillReviewData as BillReviewData$1, BillLifecycleDelivery, BillReviewAttachment as BillReviewAttachment$1, BillReviewPayerOption, BrowserBillSubmissionResult, BillLifecycleSessionProvider, BillReviewPayerListInput, BillReviewPayerPage, BillReviewPayer as BillReviewPayer$1, BillClaimsAdministratorDirectory, BillClaimsAdministratorSource, BrowserBillSubmissionDocument, BillDeliveryOptions as BillDeliveryOptions$1, SubmitBillInput, BillTasksDashboardData, BillTasksAgingBucket, BillHistoryEntry, ReportBillStatusInput, OrganizationProfileData, BillRemittanceSummary, BillEorDocument, BillPaymentRecord, BillLifecycleAction, BillRejection, BillLifecycleData, BillLifecycleClientOptions, BillLifecycleClient } from '@mindbill/browser';
5
+ export { BILL_TASKS_AGING_BUCKETS, BillActivityRecord, BillClaimsAdministratorContact, BillClaimsAdministratorDirectory, BillClaimsAdministratorMailingAddress, BillClaimsAdministratorPattern, BillClaimsAdministratorPayer, BillClaimsAdministratorSource, BillEorDocument, BillLifecycleAction, BillLifecycleActionId, BillLifecycleClient, BillLifecycleClientOptions, BillLifecycleData, BillLifecycleDelivery, BillLifecycleSession, BillLifecycleSessionProvider, BillLifecycleSessionRequest, BillPaymentRecord, BillRejection, BillRemittanceSummary, BillReviewPayerOption, BillReviewPayerSuggestion, BillTasksAgingBucket, BillTasksDashboardData, BillTasksDashboardItem, BillTasksDashboardRow, BillTasksDashboardSection, BillTasksDashboardSectionInput, BillTasksDashboardTone, BrowserBillSubmissionResult, CloseBillInput, PostBillPaymentInput, REPORT_BILL_STATUS_OPTIONS, ReopenBillInput, ReportBillStatusContacts, ReportBillStatusId, ReportBillStatusInput, SECOND_REVIEW_REASON_TEMPLATE, SECOND_REVIEW_WINDOW_DAYS, SecondReviewDeadline, SendDuplicateBillInput, SubmitSecondReviewInput, billTasksAgingBucketIndex, buildBillTasksDashboard, createBillLifecycleClient, reportBillStatusContacts, secondReviewDeadline } from '@mindbill/browser';
6
6
 
7
7
  type MindBillThemePreset = "mindbill" | "qme-companion" | "orange-bright" | "clinical-blue" | "midnight-cyan";
8
8
  type MindBillReactAppearance = MindBillAppearance & {
@@ -568,9 +568,14 @@ type BillSubmissionFormProps = {
568
568
  sessionEndpoint?: string;
569
569
  apiBaseUrl?: string;
570
570
  fetch?: typeof globalThis.fetch;
571
+ /** Paginated claims-administrator directory. Empty queries return the alphabetical first page. */
572
+ onListClaimsAdministrators?: (input?: BillReviewPayerListInput) => Promise<BillReviewPayerPage>;
573
+ /** @deprecated Prefer onListClaimsAdministrators for browse and pagination support. */
571
574
  onSearchClaimsAdministrators?: (query: string, claimNumber?: string) => Promise<BillReviewPayer$1[]>;
572
575
  onGetClaimsAdministratorDirectory?: (id: string, injuryState?: string) => Promise<BillClaimsAdministratorDirectory>;
573
- /** Free-text name from the host system, shown as a hint while choosing the canonical directory entry. */
576
+ /** Host-system evidence shown without preselecting a canonical directory entry. EAMS evidence takes precedence. */
577
+ claimsAdministratorSources?: readonly BillClaimsAdministratorSource[];
578
+ /** @deprecated Prefer claimsAdministratorSources so the source label and optional URL remain explicit. */
574
579
  claimsAdministratorHint?: ReactNode;
575
580
  diagnosisOptions?: BillSubmissionDiagnosisOption[];
576
581
  onSearchDiagnoses?: (query: string, limit?: number, offset?: number) => Promise<BillSubmissionDiagnosisOption[]>;
@@ -580,7 +585,7 @@ type BillSubmissionFormProps = {
580
585
  /** Common NUCC provider taxonomies are bundled; supplied values extend or replace matching codes. */
581
586
  taxonomyOptions?: BillSubmissionTaxonomyOption[];
582
587
  /**
583
- * The daisyBill-style delivery-method dialog shown when the biller submits.
588
+ * The delivery-method dialog shown when the biller submits.
584
589
  * "auto" (default) shows it in connected mode whenever the delivery preview
585
590
  * is available; "off" submits directly on MindBill's recommended route.
586
591
  */
@@ -631,11 +636,11 @@ declare function exactClaimsAdministratorMatch(results: BillReviewPayer$1[], sup
631
636
  declare function claimsAdministratorRecommendations(results: BillReviewPayer$1[], limit?: number): BillReviewPayer$1[];
632
637
  /**
633
638
  * Form-state claims administrator for a directory pick. When the administrator
634
- * requires payer selection it carries the payer (subpayor) choices and
635
- * preselects the directory default; administrators without subpayors stay a
639
+ * requires payer selection it carries the payer (routing payer) choices and
640
+ * requires an explicit user choice; administrators without routing payers stay a
636
641
  * plain `{ id, name }` reference.
637
642
  */
638
- declare function chooseClaimsAdministrator(payer: Pick<BillReviewPayer$1, "id" | "name" | "payerSelectionRequired" | "payers">): NonNullable<BillSubmissionInput["claim"]["claimsAdministrator"]>;
643
+ declare function chooseClaimsAdministrator(payer: Pick<BillReviewPayer$1, "id" | "name" | "payerSelectionRequired" | "payers">, selectedPayerId?: string): NonNullable<BillSubmissionInput["claim"]["claimsAdministrator"]>;
639
644
  /**
640
645
  * The claims administrator reference exactly as submitted to MindBill: picker
641
646
  * metadata (payerSelectionRequired, payers) stays client-side and the chosen
@@ -654,7 +659,7 @@ declare function BillSubmissionProvidersSection(): ReactElement;
654
659
  declare function BillSubmissionServiceLinesSection(): ReactElement;
655
660
  declare function BillSubmissionAttachmentsSection(): ReactElement;
656
661
  declare function BillSubmissionActions(): ReactElement;
657
- declare function BillSubmissionForm({ initialBill, attachments, onSubmit, onSubmitted, getSession, sessionEndpoint, apiBaseUrl, fetch: fetchOverride, onSearchClaimsAdministrators, onGetClaimsAdministratorDirectory, claimsAdministratorHint, diagnosisOptions, onSearchDiagnoses, onLookupPostalCode, procedureOptions, modifierOptions, taxonomyOptions, deliveryRoutePicker, attachmentReportTypeMode, attachmentReportTypes, defaultAttachmentReportType, appearance, className, style, disabled, submitLabel, heading, description, attentionFields, attentionMessage, children, }: BillSubmissionFormProps): ReactElement;
662
+ declare function BillSubmissionForm({ initialBill, attachments, onSubmit, onSubmitted, getSession, sessionEndpoint, apiBaseUrl, fetch: fetchOverride, onListClaimsAdministrators, onSearchClaimsAdministrators, onGetClaimsAdministratorDirectory, claimsAdministratorSources, claimsAdministratorHint, diagnosisOptions, onSearchDiagnoses, onLookupPostalCode, procedureOptions, modifierOptions, taxonomyOptions, deliveryRoutePicker, attachmentReportTypeMode, attachmentReportTypes, defaultAttachmentReportType, appearance, className, style, disabled, submitLabel, heading, description, attentionFields, attentionMessage, children, }: BillSubmissionFormProps): ReactElement;
658
663
 
659
664
  /** First plausible email address inside a raw contact string, or null. */
660
665
  declare function extractSendRouteEmail(raw: string | null | undefined): string | null;
@@ -1123,6 +1128,8 @@ type ConnectedBillLifecycleProps = UseBillLifecycleOptions & {
1123
1128
  actorName?: string;
1124
1129
  /** Optional host-system claims-administrator name shown as a selection hint. */
1125
1130
  claimsAdministratorHint?: ReactNode;
1131
+ /** Host-system evidence shown without preselecting a canonical directory entry. */
1132
+ claimsAdministratorSources?: readonly BillClaimsAdministratorSource[];
1126
1133
  /**
1127
1134
  * Exposes payer-response simulation controls for an explicit sandbox
1128
1135
  * playground. Sandbox responses remain indistinguishable from live
@@ -1135,7 +1142,7 @@ type ConnectedBillLifecycleProps = UseBillLifecycleOptions & {
1135
1142
  errorFallback?: (error: Error, retry: () => Promise<void>) => ReactNode;
1136
1143
  onChanged?: (data: BillLifecycleData) => void;
1137
1144
  };
1138
- declare function ConnectedBillLifecycle({ appearance, actorName, claimsAdministratorHint, sandboxControls, className, style, loadingFallback, errorFallback, onChanged, ...options }: ConnectedBillLifecycleProps): ReactElement;
1145
+ declare function ConnectedBillLifecycle({ appearance, actorName, claimsAdministratorHint, claimsAdministratorSources, sandboxControls, className, style, loadingFallback, errorFallback, onChanged, ...options }: ConnectedBillLifecycleProps): ReactElement;
1139
1146
 
1140
1147
  type ClaimsAdministratorDirectoryDialogProps = {
1141
1148
  open: boolean;
package/dist/index.js CHANGED
@@ -1301,8 +1301,7 @@ var READ_ONLY_STYLES = `
1301
1301
  import { createContext, useCallback, useContext, useEffect as useEffect5, useMemo as useMemo3, useRef as useRef2, useState as useState5 } from "react";
1302
1302
  import {
1303
1303
  createBillReferenceClient,
1304
- createBillSubmissionClient,
1305
- defaultBillReviewPayerOption
1304
+ createBillSubmissionClient
1306
1305
  } from "@mindbill/browser";
1307
1306
 
1308
1307
  // src/send-route-dialog.tsx
@@ -1702,7 +1701,7 @@ var css2 = `
1702
1701
  .mbcad-dialog{--mbcad-accent:var(--mb-accent,#176c70);--mbcad-border:var(--mb-border,#d7e0df);--mbcad-surface:var(--mb-surface,#fff);--mbcad-text:var(--mb-text,#17282d);--mbcad-muted:var(--mb-muted,#607176);display:grid;grid-template-rows:auto auto minmax(0,1fr);width:min(1180px,100%);max-height:min(860px,92vh);overflow:hidden;border:1px solid var(--mbcad-border);border-radius:14px;background:var(--mbcad-surface);color:var(--mbcad-text);box-shadow:0 28px 80px rgba(14,31,43,.28);font-family:var(--mb-font,Inter,ui-sans-serif,system-ui,sans-serif)}
1703
1702
  .mbcad-head{display:flex;align-items:center;justify-content:space-between;gap:18px;padding:18px 22px;border-bottom:1px solid var(--mbcad-border)}.mbcad-head h2{margin:0;font-size:24px;line-height:1.2}.mbcad-close{width:40px;height:40px;border:0;border-radius:9px;background:color-mix(in srgb,var(--mbcad-muted) 9%,var(--mbcad-surface));color:var(--mbcad-accent);font:inherit;font-size:28px;line-height:1;cursor:pointer}
1704
1703
  .mbcad-tabs{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));margin:18px 22px 0;border-radius:10px;background:color-mix(in srgb,var(--mbcad-muted) 8%,var(--mbcad-surface));overflow:hidden}.mbcad-tab{min-height:64px;padding:10px;border:0;border-right:1px solid var(--mbcad-border);border-top:4px solid transparent;background:transparent;color:var(--mbcad-muted);font:inherit;font-weight:750;cursor:pointer}.mbcad-tab:last-child{border-right:0}.mbcad-tab[aria-selected=true]{border-top-color:var(--mbcad-accent);background:var(--mbcad-surface);color:var(--mbcad-text)}
1705
- .mbcad-body{overflow:auto;padding:24px 22px 28px}.mbcad-grid{display:grid;gap:0;border:1px solid var(--mbcad-border);border-radius:10px;overflow:hidden}.mbcad-row{display:grid;grid-template-columns:minmax(180px,.8fr) minmax(0,2fr);gap:18px;padding:11px 14px;border-bottom:1px solid var(--mbcad-border)}.mbcad-row:last-child{border-bottom:0}.mbcad-row strong{font-weight:750}.mbcad-list{display:grid;gap:5px;margin:0;padding:0;list-style:none}.mbcad-list a,.mbcad-table a{color:var(--mbcad-accent);overflow-wrap:anywhere}.mbcad-table{width:100%;border-collapse:collapse;border:1px solid var(--mbcad-border);border-radius:10px;overflow:hidden}.mbcad-table th,.mbcad-table td{padding:13px 14px;border-bottom:1px solid var(--mbcad-border);text-align:left;vertical-align:top}.mbcad-table th{background:color-mix(in srgb,var(--mbcad-muted) 7%,var(--mbcad-surface));font-size:13px}.mbcad-empty{padding:36px;text-align:center;color:var(--mbcad-muted)}.mbcad-notice{padding:14px 16px;border:1px solid color-mix(in srgb,var(--mbcad-accent) 70%,var(--mbcad-border));border-radius:9px;background:color-mix(in srgb,var(--mbcad-accent) 5%,var(--mbcad-surface));font-weight:650}
1704
+ .mbcad-body{overflow:auto;padding:24px 22px 28px}.mbcad-grid{display:grid;gap:0;border:1px solid var(--mbcad-border);border-radius:10px;overflow:hidden}.mbcad-row{display:grid;grid-template-columns:minmax(180px,.8fr) minmax(0,2fr);gap:18px;padding:11px 14px;border-bottom:1px solid var(--mbcad-border)}.mbcad-row:last-child{border-bottom:0}.mbcad-row strong{font-weight:750}.mbcad-list{display:grid;gap:5px;margin:0;padding:0;list-style:none}.mbcad-list a,.mbcad-table a{color:var(--mbcad-accent);overflow-wrap:anywhere}.mbcad-payers{display:grid;gap:9px;margin:0;padding:0;list-style:none}.mbcad-payer{display:grid;gap:7px;padding:12px;border:1px solid var(--mbcad-border);border-radius:9px;background:color-mix(in srgb,var(--mbcad-muted) 3%,var(--mbcad-surface))}.mbcad-payer-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.mbcad-payer-route{color:var(--mbcad-accent);font-size:13px;font-weight:750;white-space:nowrap}.mbcad-payer-meta{display:flex;flex-wrap:wrap;gap:6px}.mbcad-payer-meta span{padding:3px 7px;border:1px solid var(--mbcad-border);border-radius:999px;color:var(--mbcad-muted);font-size:12px}.mbcad-payer-note{margin:0;color:var(--mbcad-muted);font-size:13px}.mbcad-table{width:100%;border-collapse:collapse;border:1px solid var(--mbcad-border);border-radius:10px;overflow:hidden}.mbcad-table th,.mbcad-table td{padding:13px 14px;border-bottom:1px solid var(--mbcad-border);text-align:left;vertical-align:top}.mbcad-table th{background:color-mix(in srgb,var(--mbcad-muted) 7%,var(--mbcad-surface));font-size:13px}.mbcad-empty{padding:36px;text-align:center;color:var(--mbcad-muted)}.mbcad-notice{padding:14px 16px;border:1px solid color-mix(in srgb,var(--mbcad-accent) 70%,var(--mbcad-border));border-radius:9px;background:color-mix(in srgb,var(--mbcad-accent) 5%,var(--mbcad-surface));font-weight:650}
1706
1705
  @media(max-width:760px){.mbcad-backdrop{padding:8px}.mbcad-dialog{max-height:96vh}.mbcad-head{padding:14px}.mbcad-head h2{font-size:19px}.mbcad-tabs{display:flex;overflow-x:auto;margin:10px 12px 0}.mbcad-tab{min-width:145px}.mbcad-body{padding:14px 12px 18px}.mbcad-row{grid-template-columns:1fr;gap:5px}.mbcad-table{display:block;overflow-x:auto}}
1707
1706
  `;
1708
1707
  function outbound(value, kind) {
@@ -1712,6 +1711,33 @@ function outbound(value, kind) {
1712
1711
  function list(values, kind) {
1713
1712
  return values?.length ? /* @__PURE__ */ jsx4("ul", { className: "mbcad-list", children: values.map((value, index) => /* @__PURE__ */ jsx4("li", { children: kind ? outbound(value, kind) : value }, `${value}-${index}`)) }) : "\u2014";
1714
1713
  }
1714
+ function payerDetails(payer, index) {
1715
+ const identifiers = Object.entries(payer.clearinghousePayerIds ?? {}).map(([name, id]) => `${name.replace(/_/g, " ")}: ${id}`);
1716
+ const metadata = [
1717
+ payer.optionType ? `Type: ${payer.optionType}` : null,
1718
+ payer.deliveryType ? `Delivery: ${payer.deliveryType}` : null,
1719
+ payer.clearinghouse && payer.payerId ? `${payer.clearinghouse}: ${payer.payerId}` : null,
1720
+ payer.sourceClearinghouse && payer.sourcePayerId ? `Catalog route: ${payer.sourceClearinghouse} ${payer.sourcePayerId}` : null,
1721
+ ...identifiers,
1722
+ payer.preferredClearinghouse ? `Preferred: ${payer.preferredClearinghouse}` : null
1723
+ ].filter((value) => Boolean(value));
1724
+ return /* @__PURE__ */ jsxs4("li", { className: "mbcad-payer", children: [
1725
+ /* @__PURE__ */ jsxs4("div", { className: "mbcad-payer-head", children: [
1726
+ /* @__PURE__ */ jsx4("strong", { children: payer.name }),
1727
+ payer.route ? /* @__PURE__ */ jsx4("span", { className: "mbcad-payer-route", children: payer.route }) : null
1728
+ ] }),
1729
+ payer.aliases?.length ? /* @__PURE__ */ jsxs4("p", { className: "mbcad-payer-note", children: [
1730
+ "Also known as ",
1731
+ payer.aliases.join(", ")
1732
+ ] }) : null,
1733
+ payer.hint ? /* @__PURE__ */ jsx4("p", { className: "mbcad-payer-note", children: payer.hint }) : null,
1734
+ payer.affiliatedEntities?.length ? /* @__PURE__ */ jsxs4("p", { className: "mbcad-payer-note", children: [
1735
+ "Affiliated with ",
1736
+ payer.affiliatedEntities.join(", ")
1737
+ ] }) : null,
1738
+ metadata.length ? /* @__PURE__ */ jsx4("div", { className: "mbcad-payer-meta", children: metadata.map((item) => /* @__PURE__ */ jsx4("span", { children: item }, item)) }) : null
1739
+ ] }, `${payer.name}-${index}`);
1740
+ }
1715
1741
  function Main({ directory }) {
1716
1742
  return /* @__PURE__ */ jsx4("div", { className: "mbcad-grid", children: [
1717
1743
  ["Name", directory.name ?? "\u2014"],
@@ -1724,12 +1750,7 @@ function Main({ directory }) {
1724
1750
  ["Telephone numbers", list(directory.telephoneNumbers, "phone")],
1725
1751
  ["Email addresses", list(directory.emailAddresses, "email")],
1726
1752
  ["Web portals", list(directory.webPortals, "url")],
1727
- ["Payers", directory.payers?.length ? /* @__PURE__ */ jsx4("ul", { className: "mbcad-list", children: directory.payers.map((payer, index) => /* @__PURE__ */ jsxs4("li", { children: [
1728
- /* @__PURE__ */ jsx4("strong", { children: payer.name }),
1729
- payer.daisyBillPayerId ? ` \xB7 daisyBill Payer ID ${payer.daisyBillPayerId}` : "",
1730
- payer.route ? ` \xB7 ${payer.route}` : "",
1731
- payer.hint ? /* @__PURE__ */ jsx4("small", { children: payer.hint }) : null
1732
- ] }, `${payer.name}-${index}`)) }) : "\u2014"],
1753
+ ["Payers", directory.payers?.length ? /* @__PURE__ */ jsx4("ul", { className: "mbcad-payers", children: directory.payers.map(payerDetails) }) : "\u2014"],
1733
1754
  ["Bill processing workflow", directory.billProcessingWorkflow ?? "\u2014"],
1734
1755
  ["Bill processing workflow notes", directory.billProcessingWorkflowNotes ?? "\u2014"],
1735
1756
  ["Claim number hint", directory.claimNumberHint ?? "\u2014"]
@@ -2118,6 +2139,7 @@ var MAX_PDF_BYTES = 25 * 1024 * 1024;
2118
2139
  var MAX_UPLOAD_BYTES = 100 * 1024 * 1024;
2119
2140
  var MAX_DOCUMENTS = 25;
2120
2141
  var DIAGNOSIS_PAGE_SIZE = 100;
2142
+ var PAYER_PAGE_SIZE = 50;
2121
2143
  var EMPTY_ATTACHMENTS = [];
2122
2144
  function bytesToBase64(bytes) {
2123
2145
  let binary = "";
@@ -2317,8 +2339,9 @@ var css3 = `
2317
2339
  .mbsf-attention{padding:14px 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));color:var(--mb-text)}.mbsf [data-attention=true] .mbsf-input,.mbsf [data-attention=true] .mbsf-select,.mbsf [data-attention=true].mbsf-lines{border-color:var(--mb-danger);background:color-mix(in srgb,var(--mb-danger) 4%,var(--mb-input))}.mbsf [data-attention=true]>.mbsf-label{color:var(--mb-danger)}
2318
2340
  .mbsf-head,.mbsf-section-head,.mbsf-attach-row,.mbsf-actions{display:flex;align-items:center;justify-content:space-between;gap:16px}.mbsf-title{margin:0;font-size:24px}.mbsf-copy,.mbsf-help{color:var(--mb-muted);margin:5px 0 0}.mbsf-required{font-size:13px;color:var(--mb-muted);white-space:nowrap}.mbsf-star,.mbsf-error{color:var(--mb-danger)}
2319
2341
  .mbsf-card{min-width:0;margin:0;padding:24px;border:1px solid var(--mb-border);border-radius:var(--mb-radius);background:var(--mb-surface);box-shadow:var(--mb-shadow)}.mbsf-card[data-invalid=true]{border-color:var(--mb-danger)}.mbsf-legend{padding:0 10px;font-size:18px;font-weight:760}.mbsf-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px 24px}.mbsf-subhead{grid-column:1/-1;margin:6px 0 -2px;padding-top:14px;border-top:1px solid var(--mb-border);font-size:15px;font-weight:780;letter-spacing:.01em}.mbsf-subhead:first-child{margin-top:0;padding-top:0;border-top:0}.mbsf-span{grid-column:1/-1}.mbsf-field{display:grid;align-content:start;gap:7px;min-width:0}.mbsf-label{font-weight:680}.mbsf-input,.mbsf-select{width:100%;min-height:46px;padding:10px 12px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius);background:var(--mb-input);color:var(--mb-text);font:inherit}.mbsf-input:focus,.mbsf-select:focus{outline:3px solid color-mix(in srgb,var(--mb-accent) 22%,transparent);border-color:var(--mb-accent)}.mbsf-field[data-invalid=true] .mbsf-input,.mbsf-field[data-invalid=true] .mbsf-select,.mbsf-invalid-control .mbsf-input{border-color:var(--mb-danger);background:color-mix(in srgb,var(--mb-danger) 4%,var(--mb-input))}.mbsf-field[data-invalid=true] .mbsf-input:focus,.mbsf-field[data-invalid=true] .mbsf-select:focus{outline-color:color-mix(in srgb,var(--mb-danger) 24%,transparent)}
2320
- .mbsf-combo{position:relative}.mbsf-menu{position:absolute;z-index:20;top:calc(100% + 5px);left:0;right:0;max-height:min(360px,46vh);overflow:auto;overscroll-behavior:contain;padding:7px;border:1px solid var(--mb-border);border-radius:12px;background:var(--mb-surface);box-shadow:0 14px 35px rgba(17,38,49,.16)}.mbsf-option{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:14px;width:100%;padding:10px;border:0;border-radius:8px;background:transparent;color:var(--mb-text);font:inherit;text-align:left;cursor:pointer}.mbsf-option:hover,.mbsf-option:focus{background:color-mix(in srgb,var(--mb-accent) 9%,var(--mb-surface))}.mbsf-option-main{display:grid;gap:2px;min-width:0}.mbsf-option small{color:var(--mb-muted);overflow-wrap:anywhere}.mbsf-option-route{align-self:center;color:var(--mb-accent);font-size:13px;font-weight:750;white-space:nowrap}.mbsf-menu-status{padding:12px;text-align:center;color:var(--mb-muted);font-size:13px}.mbsf-directory-link{justify-self:start;border:0;padding:0;background:transparent;color:var(--mb-accent);font:inherit;font-weight:700;text-align:left;text-decoration:underline;cursor:pointer}
2342
+ .mbsf-combo{position:relative}.mbsf-menu{position:absolute;z-index:20;top:calc(100% + 5px);left:0;right:0;max-height:min(420px,52vh);overflow:auto;overscroll-behavior:contain;padding:7px;border:1px solid var(--mb-border);border-radius:12px;background:var(--mb-surface);box-shadow:0 14px 35px rgba(17,38,49,.16)}.mbsf-option{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:14px;width:100%;padding:11px 12px;border:0;border-radius:8px;background:transparent;color:var(--mb-text);font:inherit;text-align:left;cursor:pointer}.mbsf-option+.mbsf-option{border-top:1px solid color-mix(in srgb,var(--mb-border) 65%,transparent)}.mbsf-option:hover,.mbsf-option:focus{background:color-mix(in srgb,var(--mb-accent) 9%,var(--mb-surface));outline:0}.mbsf-option-main{display:grid;gap:5px;min-width:0}.mbsf-option small{color:var(--mb-muted);overflow-wrap:anywhere;line-height:1.35}.mbsf-option-route{align-self:start;margin-top:2px;color:var(--mb-accent);font-size:13px;font-weight:750;white-space:nowrap}.mbsf-option-badges{display:flex;flex-wrap:wrap;gap:5px}.mbsf-option-badge{padding:2px 7px;border:1px solid var(--mb-border);border-radius:999px;color:var(--mb-muted);font-size:11px;line-height:1.35}.mbsf-option-affiliates{display:block}.mbsf-option-affiliates strong{color:var(--mb-text);font-size:12px}.mbsf-menu-status{padding:12px;text-align:center;color:var(--mb-muted);font-size:13px}.mbsf-directory-link{justify-self:start;border:0;padding:0;background:transparent;color:var(--mb-accent);font:inherit;font-weight:700;text-align:left;text-decoration:underline;cursor:pointer}
2321
2343
  .mbsf-payer-status{display:flex;align-items:center;gap:7px;color:#087f5b;font-size:13px;font-weight:650}.mbsf-payer-intro{margin:4px 0 0;color:var(--mb-muted)}.mbsf-payer-list{display:grid;gap:8px}.mbsf-payer-option{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:11px 12px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius);background:color-mix(in srgb,var(--mb-accent) 3%,var(--mb-surface))}.mbsf-payer-option-main{display:grid;gap:5px;min-width:0}.mbsf-payer-option-main strong{overflow-wrap:anywhere}.mbsf-payer-signals{display:flex;flex-wrap:wrap;gap:6px}.mbsf-payer-signal{padding:2px 7px;border:1px solid var(--mb-border);border-radius:999px;color:var(--mb-muted);font-size:12px}.mbsf-payer-signal[data-state=match]{border-color:color-mix(in srgb,#159447 45%,var(--mb-border));color:#087f5b}.mbsf-payer-signal[data-state=warning]{border-color:color-mix(in srgb,#c56a00 55%,var(--mb-border));color:#9a5200}
2344
+ .mbsf-source-evidence{display:grid;gap:4px;color:var(--mb-muted);font-size:13px}.mbsf-source-evidence a{color:var(--mb-accent);font-weight:700}.mbsf-source-evidence q{color:var(--mb-text)}.mbsf-suggestions{display:flex;align-items:center;flex-wrap:wrap;gap:7px;color:var(--mb-muted);font-size:13px}.mbsf-suggestion{padding:5px 10px;border:1px solid color-mix(in srgb,var(--mb-accent) 55%,var(--mb-border));border-radius:999px;background:color-mix(in srgb,var(--mb-accent) 7%,var(--mb-surface));color:var(--mb-accent);font:inherit;font-weight:700;cursor:pointer}.mbsf-suggestion:hover,.mbsf-suggestion:focus{outline:2px solid color-mix(in srgb,var(--mb-accent) 25%,transparent)}.mbsf-claim-patterns{display:grid;gap:4px;margin-top:2px;font-size:13px}.mbsf-claim-patterns[data-state=match]{color:#087f5b}.mbsf-claim-patterns[data-state=warning]{color:#9a5200}.mbsf-claim-pattern-list{color:var(--mb-muted)}
2322
2345
  .mbsf-chips,.mbsf-quick-picks{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:8px}.mbsf-chip,.mbsf-quick-pick{display:inline-flex;align-items:center;gap:7px;padding:5px 9px;border:1px solid var(--mb-border);border-radius:999px;background:var(--mb-input)}.mbsf-chip button{border:0;background:transparent;color:var(--mb-muted);cursor:pointer;font:inherit}.mbsf-quick-pick{color:var(--mb-text);font:inherit;cursor:pointer}.mbsf-quick-pick[data-selected=true]{border-color:var(--mb-accent);color:var(--mb-accent)}
2323
2346
  .mbsf-segments{display:grid;grid-template-columns:repeat(3,1fr);border:1px solid var(--mb-border);border-radius:var(--mb-control-radius);overflow:hidden}.mbsf-segment{min-height:44px;border:0;border-right:1px solid var(--mb-border);background:var(--mb-input);color:var(--mb-text);font:inherit;font-weight:700;cursor:pointer}.mbsf-segment:last-child{border-right:0}.mbsf-segment[aria-pressed=true]{background:var(--mb-accent);color:var(--mb-accent-contrast)}
2324
2347
  .mbsf-lines{margin-top:18px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius);overflow:visible}.mbsf-lines[data-invalid=true]{border-color:var(--mb-danger)}.mbsf-line-head,.mbsf-line{display:grid;grid-template-columns:minmax(190px,1.05fr) minmax(190px,1.3fr) minmax(112px,.7fr) 100px 120px 42px;gap:12px;align-items:start;padding:12px}.mbsf-line-head{color:var(--mb-muted);font-size:13px;font-weight:700;border-bottom:1px solid var(--mb-border)}.mbsf-line{border-bottom:1px solid var(--mb-border)}.mbsf-line:last-child{border-bottom:0}.mbsf-line [data-invalid=true] .mbsf-input{border-color:var(--mb-danger);background:color-mix(in srgb,var(--mb-danger) 4%,var(--mb-input))}.mbsf-money{padding-top:12px;text-align:right;font-variant-numeric:tabular-nums}.mbsf-dx{display:flex;flex-wrap:wrap;gap:5px;padding-top:6px}.mbsf-dx-chip{width:30px;height:30px;border:1px solid var(--mb-border);border-radius:8px;background:var(--mb-surface);color:var(--mb-muted);font:inherit;font-size:13px;font-weight:750;cursor:pointer}.mbsf-dx-chip[data-active=true]{border-color:var(--mb-accent);background:color-mix(in srgb,var(--mb-accent) 10%,var(--mb-surface));color:var(--mb-accent)}.mbsf-total{display:flex;justify-content:flex-end;gap:45px;padding:16px 56px 16px 16px;font-size:17px;font-weight:760}
@@ -2357,16 +2380,16 @@ function TextDateInput({ value, onChange, disabled, required, ariaLabel }) {
2357
2380
  invalid ? /* @__PURE__ */ jsx5("small", { className: "mbsf-error", children: "Use MM/DD/YYYY" }) : null
2358
2381
  ] });
2359
2382
  }
2360
- function ComboBox({ value, placeholder, options, disabled, loading, loadingMore, invalid, preserveValueOnOpen = false, onOpen, onQuery, onEndReached, onSelect, createOption, ariaLabel }) {
2383
+ function ComboBox({ value, placeholder, options, disabled, loading, loadingMore, invalid, preserveValueOnOpen = false, filterOptions = true, onOpen, onQuery, onEndReached, onSelect, createOption, ariaLabel }) {
2361
2384
  const [open, setOpen] = useState5(false);
2362
2385
  const [query, setQuery] = useState5("");
2363
2386
  const visible = useMemo3(() => {
2364
2387
  const q = query.trim().toLowerCase();
2365
- const matches = q ? options.filter((option) => `${option.id} ${option.label} ${option.detail ?? ""} ${option.trailing ?? ""}`.toLowerCase().includes(q)) : options;
2388
+ const matches = q && filterOptions ? options.filter((option) => `${option.id} ${option.label} ${option.detail ?? ""} ${(option.badges ?? []).join(" ")} ${(option.affiliatedEntities ?? []).join(" ")} ${option.trailing ?? ""}`.toLowerCase().includes(q)) : options;
2366
2389
  const custom = createOption?.(query) ?? null;
2367
2390
  return custom && !matches.some((option) => option.id.toUpperCase() === custom.id.toUpperCase()) ? [...matches, custom] : matches;
2368
- }, [createOption, options, query]);
2369
- const showMenu = open && (loading || visible.length > 0 || query.trim().length >= 2);
2391
+ }, [createOption, filterOptions, options, query]);
2392
+ const showMenu = open;
2370
2393
  return /* @__PURE__ */ jsxs5("div", { className: "mbsf-combo", children: [
2371
2394
  /* @__PURE__ */ jsx5("input", { className: "mbsf-input", role: "combobox", "aria-label": ariaLabel, "aria-invalid": invalid, "aria-expanded": showMenu, autoComplete: "off", disabled, placeholder, value: open ? query : value, onFocus: () => {
2372
2395
  const next = preserveValueOnOpen ? value : "";
@@ -2390,7 +2413,13 @@ function ComboBox({ value, placeholder, options, disabled, loading, loadingMore,
2390
2413
  }, children: [
2391
2414
  /* @__PURE__ */ jsxs5("span", { className: "mbsf-option-main", children: [
2392
2415
  /* @__PURE__ */ jsx5("strong", { children: option.label }),
2393
- option.detail ? /* @__PURE__ */ jsx5("small", { children: option.detail }) : null
2416
+ option.detail ? /* @__PURE__ */ jsx5("small", { children: option.detail }) : null,
2417
+ option.badges?.length ? /* @__PURE__ */ jsx5("span", { className: "mbsf-option-badges", children: option.badges.map((badge) => /* @__PURE__ */ jsx5("span", { className: "mbsf-option-badge", children: badge }, badge)) }) : null,
2418
+ option.affiliatedEntities?.length ? /* @__PURE__ */ jsxs5("small", { className: "mbsf-option-affiliates", children: [
2419
+ /* @__PURE__ */ jsx5("strong", { children: "Affiliated entities:" }),
2420
+ " ",
2421
+ option.affiliatedEntities.join(", ")
2422
+ ] }) : null
2394
2423
  ] }),
2395
2424
  option.trailing ? /* @__PURE__ */ jsx5("span", { className: "mbsf-option-route", children: option.trailing }) : null
2396
2425
  ] }, option.id)) : /* @__PURE__ */ jsx5("div", { className: "mbsf-option", children: "No matches" }),
@@ -2440,16 +2469,24 @@ function exactClaimsAdministratorMatch(results, suppliedName) {
2440
2469
  function claimsAdministratorRecommendations(results, limit = 5) {
2441
2470
  return [...results].sort((left, right) => Number(Boolean(right.recommended)) - Number(Boolean(left.recommended))).slice(0, Math.max(0, limit));
2442
2471
  }
2443
- function chooseClaimsAdministrator(payer) {
2472
+ function claimNumberPatternMatches(pattern, claimNumber) {
2473
+ const example = pattern.example?.trim();
2474
+ if (example && /9{2,}/.test(example)) {
2475
+ const expression = [...example].map((character) => character === "9" ? "\\d" : character.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("");
2476
+ return new RegExp(`^${expression}$`, "i").test(claimNumber.trim());
2477
+ }
2478
+ return pattern.matches ?? null;
2479
+ }
2480
+ function chooseClaimsAdministrator(payer, selectedPayerId) {
2444
2481
  if (!payer.payerSelectionRequired) return { id: payer.id, name: payer.name };
2445
2482
  const payers = (payer.payers ?? []).map((option) => ({ ...option }));
2446
- const preselected = defaultBillReviewPayerOption(payer);
2483
+ const resolvedPayerId = selectedPayerId && payers.some((option) => option.id === selectedPayerId) ? selectedPayerId : void 0;
2447
2484
  return {
2448
2485
  id: payer.id,
2449
2486
  name: payer.name,
2450
2487
  payerSelectionRequired: true,
2451
2488
  ...payers.length ? { payers } : {},
2452
- ...preselected ? { payerId: preselected.id } : {}
2489
+ ...resolvedPayerId ? { payerId: resolvedPayerId } : {}
2453
2490
  };
2454
2491
  }
2455
2492
  function submittedClaimsAdministrator(administrator) {
@@ -2495,8 +2532,10 @@ function BillSubmissionForm({
2495
2532
  sessionEndpoint,
2496
2533
  apiBaseUrl,
2497
2534
  fetch: fetchOverride,
2535
+ onListClaimsAdministrators,
2498
2536
  onSearchClaimsAdministrators,
2499
2537
  onGetClaimsAdministratorDirectory,
2538
+ claimsAdministratorSources,
2500
2539
  claimsAdministratorHint,
2501
2540
  diagnosisOptions = [],
2502
2541
  onSearchDiagnoses,
@@ -2532,6 +2571,11 @@ function BillSubmissionForm({
2532
2571
  const [routeError, setRouteError] = useState5(null);
2533
2572
  const [payerResults, setPayerResults] = useState5([]);
2534
2573
  const [payerLoading, setPayerLoading] = useState5(false);
2574
+ const [payerSuggestions, setPayerSuggestions] = useState5([]);
2575
+ const [selectedPayerMetadata, setSelectedPayerMetadata] = useState5(null);
2576
+ const [payerLoadingMore, setPayerLoadingMore] = useState5(false);
2577
+ const [payerQuery, setPayerQuery] = useState5(null);
2578
+ const [payerHasMore, setPayerHasMore] = useState5(true);
2535
2579
  const [directoryOpen, setDirectoryOpen] = useState5(false);
2536
2580
  const [directory, setDirectory] = useState5(null);
2537
2581
  const [directoryLoading, setDirectoryLoading] = useState5(false);
@@ -2548,7 +2592,10 @@ function BillSubmissionForm({
2548
2592
  const diagnosisRequest = useRef2(0);
2549
2593
  const diagnosisAppendPending = useRef2(false);
2550
2594
  const payerRequest = useRef2(0);
2595
+ const payerAppendPending = useRef2(false);
2551
2596
  const procedures = useMemo3(() => mergeOptions(DEFAULT_BILL_SUBMISSION_PROCEDURES, procedureOptions), [procedureOptions]);
2597
+ const orderedClaimsAdministratorSources = useMemo3(() => [...claimsAdministratorSources ?? []].filter((source) => source.name.trim()).sort((left, right) => Number(right.source.toLowerCase() === "eams") - Number(left.source.toLowerCase() === "eams")), [claimsAdministratorSources]);
2598
+ const sourceClaimsAdministratorName = orderedClaimsAdministratorSources[0]?.name.trim() ?? "";
2552
2599
  const modifiers = useMemo3(() => mergeOptions(DEFAULT_BILL_SUBMISSION_MODIFIERS, modifierOptions), [modifierOptions]);
2553
2600
  const taxonomies = useMemo3(() => mergeOptions(DEFAULT_BILL_SUBMISSION_TAXONOMIES, taxonomyOptions), [taxonomyOptions]);
2554
2601
  const [evaluationType, setEvaluationType] = useState5(() => initialEvaluationType(initialBill));
@@ -2575,7 +2622,14 @@ function BillSubmissionForm({
2575
2622
  setDiagnosisHasMore(true);
2576
2623
  diagnosisRequest.current += 1;
2577
2624
  diagnosisAppendPending.current = false;
2578
- }, [initialBill, attachments]);
2625
+ setPayerResults([]);
2626
+ setPayerSuggestions([]);
2627
+ setSelectedPayerMetadata(null);
2628
+ setPayerQuery(null);
2629
+ setPayerHasMore(true);
2630
+ payerRequest.current += 1;
2631
+ payerAppendPending.current = false;
2632
+ }, [initialBill, attachments, sourceClaimsAdministratorName]);
2579
2633
  useEffect5(() => {
2580
2634
  if (!validationActive) return;
2581
2635
  const next = validateBillSubmission(bill).fieldErrors;
@@ -2649,33 +2703,50 @@ function BillSubmissionForm({
2649
2703
  return next;
2650
2704
  })) }));
2651
2705
  const text = (value, onChange, options = {}) => /* @__PURE__ */ jsx5("input", { className: "mbsf-input", disabled: locked, value: value ?? "", onChange: (event) => onChange(event.target.value), ...options });
2652
- const runPayerSearch = useCallback(async (query) => {
2706
+ const loadPayers = useCallback((query, append = false) => {
2653
2707
  const trimmed = query.trim();
2654
- if (trimmed.length < 2) {
2655
- setPayerResults([]);
2656
- return;
2657
- }
2658
- const search = onSearchClaimsAdministrators ?? referenceClient?.searchClaimsAdministrators;
2659
- if (!search) return;
2708
+ const list2 = onListClaimsAdministrators ?? referenceClient?.listClaimsAdministrators;
2709
+ const legacySearch = onSearchClaimsAdministrators ?? referenceClient?.searchClaimsAdministrators;
2710
+ if (!list2 && !legacySearch) return;
2711
+ const continuing = append && payerQuery === trimmed;
2712
+ if (continuing && (!payerHasMore || payerAppendPending.current)) return;
2713
+ const offset = continuing ? payerResults.length : 0;
2660
2714
  const request = ++payerRequest.current;
2661
- setPayerLoading(true);
2662
- try {
2663
- const results = await search(trimmed, bill.claim.claimNumber);
2715
+ if (continuing) {
2716
+ payerAppendPending.current = true;
2717
+ setPayerLoadingMore(true);
2718
+ } else {
2719
+ setPayerLoading(true);
2720
+ setPayerLoadingMore(false);
2721
+ setPayerQuery(trimmed);
2722
+ setPayerHasMore(true);
2723
+ }
2724
+ const page = list2 ? list2({ query: trimmed, claimNumber: bill.claim.claimNumber, ...sourceClaimsAdministratorName ? { sourceClaimsAdministratorName } : {}, ...bill.claim.employer ? { employerName: bill.claim.employer } : {}, limit: PAYER_PAGE_SIZE, offset }) : legacySearch(trimmed, bill.claim.claimNumber).then((results) => ({ results, total: results.length }));
2725
+ void page.then((result) => {
2664
2726
  if (request !== payerRequest.current) return;
2665
- setPayerResults(results);
2666
- } catch (caught) {
2727
+ setPayerResults((current) => {
2728
+ const combined = continuing ? [...current, ...result.results] : result.results;
2729
+ return [...new Map(combined.map((payer) => [payer.id, payer])).values()];
2730
+ });
2731
+ if (!continuing) setPayerSuggestions(result.suggestions ?? []);
2732
+ setPayerHasMore(result.nextOffset != null ? result.nextOffset > offset : offset + result.results.length < result.total);
2733
+ }).catch((caught) => {
2667
2734
  if (request === payerRequest.current) setFormError(caught instanceof Error ? caught.message : "Claims administrator search is unavailable.");
2668
- } finally {
2669
- if (request === payerRequest.current) setPayerLoading(false);
2670
- }
2671
- }, [bill.claim.claimNumber, onSearchClaimsAdministrators, referenceClient]);
2735
+ }).finally(() => {
2736
+ if (request !== payerRequest.current) return;
2737
+ payerAppendPending.current = false;
2738
+ setPayerLoading(false);
2739
+ setPayerLoadingMore(false);
2740
+ });
2741
+ }, [bill.claim.claimNumber, bill.claim.employer, onListClaimsAdministrators, onSearchClaimsAdministrators, payerHasMore, payerQuery, payerResults.length, referenceClient, sourceClaimsAdministratorName]);
2672
2742
  const searchPayers = (query) => {
2743
+ setSelectedPayerMetadata(null);
2673
2744
  setBill((current) => {
2674
2745
  const selected = current.claim.claimsAdministrator;
2675
2746
  if (selected?.id && selected.name === query) return current;
2676
2747
  return { ...current, claim: { ...current.claim, claimsAdministrator: { name: query } } };
2677
2748
  });
2678
- void runPayerSearch(query);
2749
+ loadPayers(query);
2679
2750
  };
2680
2751
  const loadDiagnoses = (query, append = false) => {
2681
2752
  const trimmed = query.trim();
@@ -2817,8 +2888,19 @@ function BillSubmissionForm({
2817
2888
  }
2818
2889
  }
2819
2890
  const claimsAdministratorError = errors["claim.claimsAdministrator"];
2820
- const choosePayer = (payer) => setBill((current) => ({ ...current, claim: { ...current.claim, claimsAdministrator: chooseClaimsAdministrator(payer) } }));
2891
+ const choosePayer = (payer, selectedPayerId) => {
2892
+ setSelectedPayerMetadata(payer);
2893
+ setBill((current) => ({ ...current, claim: { ...current.claim, claimsAdministrator: chooseClaimsAdministrator(payer, selectedPayerId) } }));
2894
+ };
2821
2895
  const administrator = bill.claim.claimsAdministrator;
2896
+ const displayedPayerMetadata = selectedPayerMetadata?.id === administrator?.id ? selectedPayerMetadata : null;
2897
+ const displayedClaimPatterns = (displayedPayerMetadata?.claimNumberPatterns ?? []).map((pattern) => ({
2898
+ ...pattern,
2899
+ matches: claimNumberPatternMatches(pattern, bill.claim.claimNumber)
2900
+ }));
2901
+ const evaluatedClaimPatterns = displayedClaimPatterns.filter((pattern) => pattern.matches != null);
2902
+ const claimNumberMatches = evaluatedClaimPatterns.some((pattern) => pattern.matches);
2903
+ const claimNumberPatternState = evaluatedClaimPatterns.length ? claimNumberMatches ? "match" : "warning" : null;
2822
2904
  const subpayorOptions = administrator?.payerSelectionRequired ? administrator.payers ?? [] : [];
2823
2905
  const subpayorError = errors["claim.claimsAdministrator.payerId"];
2824
2906
  const selectedSubpayor = subpayorOptions.find((option) => option.id === administrator?.payerId);
@@ -2876,14 +2958,40 @@ function BillSubmissionForm({
2876
2958
  ] }),
2877
2959
  /* @__PURE__ */ jsx5(Field2, { path: "claim.dateOfInjury", label: "Date of injury", required: true, error: errors["claim.dateOfInjury"], children: /* @__PURE__ */ jsx5(TextDateInput, { ariaLabel: "Date of injury", value: bill.claim.dateOfInjury, disabled: locked, required: true, onChange: (dateOfInjury) => setBill((c) => ({ ...c, claim: { ...c.claim, dateOfInjury } })) }) }),
2878
2960
  /* @__PURE__ */ jsx5(Field2, { path: "claim.employer", label: "Employer name", required: true, error: errors["claim.employer"], children: text(bill.claim.employer, (employer) => setBill((c) => ({ ...c, claim: { ...c.claim, employer } }))) }),
2879
- /* @__PURE__ */ jsx5(Field2, { path: "claim.claimNumber", label: "Claim number", required: true, error: errors["claim.claimNumber"], children: text(bill.claim.claimNumber, (claimNumber) => setBill((c) => ({ ...c, claim: { ...c.claim, claimNumber } }))) }),
2961
+ /* @__PURE__ */ jsxs5(Field2, { path: "claim.claimNumber", label: "Claim number", required: true, error: errors["claim.claimNumber"], children: [
2962
+ text(bill.claim.claimNumber, (claimNumber) => setBill((c) => ({ ...c, claim: { ...c.claim, claimNumber } }))),
2963
+ displayedClaimPatterns.length ? /* @__PURE__ */ jsxs5("div", { className: "mbsf-claim-patterns", "data-state": claimNumberPatternState ?? void 0, role: "status", children: [
2964
+ claimNumberPatternState === "match" ? /* @__PURE__ */ jsx5("strong", { children: "\u2713 Matches a known claim number pattern" }) : claimNumberPatternState === "warning" ? /* @__PURE__ */ jsx5("strong", { children: "\u26A0 Does not match the known claim number patterns" }) : /* @__PURE__ */ jsx5("strong", { children: "Known claim number patterns" }),
2965
+ /* @__PURE__ */ jsx5("span", { className: "mbsf-claim-pattern-list", children: displayedClaimPatterns.map((pattern) => `${pattern.pattern}${pattern.example ? ` (example: ${pattern.example})` : ""}`).join(" \xB7 ") })
2966
+ ] }) : null
2967
+ ] }),
2880
2968
  /* @__PURE__ */ jsx5(Field2, { label: "WCAB / ADJ number (optional)", children: text(bill.claim.adjNumber, (adjNumber) => setBill((c) => ({ ...c, claim: { ...c.claim, adjNumber } }))) }),
2881
2969
  /* @__PURE__ */ jsxs5(Field2, { path: "claim.claimsAdministrator", label: "Claims administrator", required: true, span: true, error: claimsAdministratorError, invalid: !administrator?.id, children: [
2882
- /* @__PURE__ */ jsx5(ComboBox, { ariaLabel: "Claims administrator", invalid: Boolean(claimsAdministratorError) || !administrator?.id, disabled: locked, loading: payerLoading, preserveValueOnOpen: true, value: administrator?.name ?? "", placeholder: "Search the claims administrator directory\u2026", options: payerResults.map((payer) => ({ id: payer.id, label: payer.name, detail: [payer.aliases?.length ? `Also known as ${payer.aliases.join(", ")}` : "", payer.claimNumberHint ?? "", payer.affiliatedEntities?.length ? `Affiliated with ${payer.affiliatedEntities.join(", ")}` : ""].filter(Boolean).join(" \xB7 ") || "Claims administrator", ...payer.route ? { trailing: payer.route } : {} })), onQuery: searchPayers, onSelect: (option) => choosePayer(payerResults.find((payer) => payer.id === option.id) ?? { id: option.id, name: option.label }) }),
2970
+ /* @__PURE__ */ jsx5(ComboBox, { ariaLabel: "Claims administrator", invalid: Boolean(claimsAdministratorError) || !administrator?.id, disabled: locked, loading: payerLoading, loadingMore: payerLoadingMore, filterOptions: false, value: administrator?.name ?? "", placeholder: "Browse or search claims administrators\u2026", options: payerResults.map((payer) => {
2971
+ const patternDetail = payer.claimNumberPatterns?.map((pattern) => `${pattern.pattern}${pattern.example ? ` (example: ${pattern.example})` : ""}`).join(" \xB7 ") ?? payer.claimNumberHint ?? "";
2972
+ return { id: payer.id, label: payer.name, detail: [payer.aliases?.length ? `Also known as ${payer.aliases.join(", ")}` : "", patternDetail].filter(Boolean).join(" \xB7 ") || "Claims administrator", ...payer.affiliatedEntities?.length ? { affiliatedEntities: payer.affiliatedEntities } : {}, ...payer.route ? { trailing: payer.route } : {} };
2973
+ }), onOpen: () => {
2974
+ if (payerQuery !== "") loadPayers("");
2975
+ }, onQuery: searchPayers, onEndReached: () => loadPayers(payerQuery ?? "", true), onSelect: (option) => choosePayer(payerResults.find((payer) => payer.id === option.id) ?? { id: option.id, name: option.label }) }),
2976
+ orderedClaimsAdministratorSources.length ? /* @__PURE__ */ jsx5("div", { className: "mbsf-source-evidence", children: orderedClaimsAdministratorSources.map((source, index) => /* @__PURE__ */ jsxs5("span", { children: [
2977
+ source.url ? /* @__PURE__ */ jsx5("a", { href: source.url, target: "_blank", rel: "noopener noreferrer", children: source.label }) : /* @__PURE__ */ jsx5("strong", { children: source.label }),
2978
+ ": ",
2979
+ /* @__PURE__ */ jsx5("q", { children: source.name })
2980
+ ] }, `${source.source}-${source.name}-${index}`)) }) : null,
2883
2981
  claimsAdministratorHint ? /* @__PURE__ */ jsxs5("small", { className: "mbsf-help", children: [
2884
2982
  "Claims administrator in your system: ",
2885
2983
  claimsAdministratorHint
2886
2984
  ] }) : null,
2985
+ payerSuggestions.length ? /* @__PURE__ */ jsxs5("div", { className: "mbsf-suggestions", children: [
2986
+ /* @__PURE__ */ jsx5("strong", { children: "Suggested:" }),
2987
+ payerSuggestions.slice(0, 5).map((suggestion) => {
2988
+ const suggestedSubpayor = suggestion.payers?.find((option) => option.id === suggestion.selectedPayerId);
2989
+ return /* @__PURE__ */ jsxs5("button", { className: "mbsf-suggestion", type: "button", title: suggestion.reason, onClick: () => choosePayer(suggestion, suggestion.selectedPayerId), children: [
2990
+ suggestion.name,
2991
+ suggestedSubpayor ? ` \xB7 ${suggestedSubpayor.label}` : ""
2992
+ ] }, `${suggestion.id}-${suggestion.selectedPayerId ?? "admin"}`);
2993
+ })
2994
+ ] }) : null,
2887
2995
  administrator?.id ? /* @__PURE__ */ jsxs5("button", { className: "mbsf-directory-link", type: "button", onClick: () => {
2888
2996
  void openAdministratorDirectory();
2889
2997
  }, children: [
@@ -2891,16 +2999,27 @@ function BillSubmissionForm({
2891
2999
  administrator.name
2892
3000
  ] }) : /* @__PURE__ */ jsx5("small", { className: "mbsf-help", children: "Search the directory and choose a claims administrator." })
2893
3001
  ] }),
2894
- administrator?.payerSelectionRequired && subpayorOptions.length ? /* @__PURE__ */ jsxs5(Field2, { path: "claim.claimsAdministrator.payerId", label: "Payer", required: true, span: true, error: subpayorError, children: [
2895
- /* @__PURE__ */ jsx5(ComboBox, { ariaLabel: "Payer", invalid: Boolean(subpayorError), disabled: locked, preserveValueOnOpen: true, value: selectedSubpayor?.label ?? "", placeholder: "Select the payer for this claims administrator\u2026", options: subpayorOptions.map((option) => {
2896
- const detail = [option.aliases?.length ? `Also known as ${option.aliases.join(", ")}` : "", option.hint ?? "", option.affiliatedEntities?.length ? `Affiliated with ${option.affiliatedEntities.join(", ")}` : "", option.default ? "Default" : ""].filter(Boolean).join(" \xB7 ");
2897
- return { id: option.id, label: option.label, ...detail ? { detail } : {}, ...option.route ? { trailing: option.route } : {} };
2898
- }), onSelect: (option) => chooseSubpayor(option.id) }),
3002
+ administrator?.payerSelectionRequired ? /* @__PURE__ */ jsxs5(Field2, { path: "claim.claimsAdministrator.payerId", label: "Payer", required: true, span: true, error: subpayorError, children: [
3003
+ subpayorOptions.length ? /* @__PURE__ */ jsx5(ComboBox, { ariaLabel: "Payer", invalid: Boolean(subpayorError), disabled: locked, value: selectedSubpayor?.label ?? "", placeholder: "Select the payer named on the claim or report\u2026", options: subpayorOptions.map((option) => {
3004
+ const identifiers = Object.entries(option.clearinghousePayerIds ?? {}).map(([name, id]) => `${name.replace(/_/g, " ")} ${id}`);
3005
+ const sourceRoute = option.sourceClearinghouse && option.sourcePayerId ? `Catalog: ${option.sourceClearinghouse} ${option.sourcePayerId}` : "";
3006
+ const detail = [option.aliases?.length ? `Also known as ${option.aliases.join(", ")}` : "", option.hint ?? "", sourceRoute].filter(Boolean).join(" \xB7 ");
3007
+ const badges = [option.optionType ? `Type: ${option.optionType}` : "", option.deliveryType ? `Delivery: ${option.deliveryType}` : "", option.clearinghouse && option.payerId ? `Delivered via ${option.clearinghouse} ${option.payerId}` : "", ...identifiers, option.preferredClearinghouse ? `Preferred: ${option.preferredClearinghouse}` : "", option.default ? "Directory default" : ""].filter(Boolean);
3008
+ return { id: option.id, label: option.label, ...detail ? { detail } : {}, ...badges.length ? { badges } : {}, ...option.affiliatedEntities?.length ? { affiliatedEntities: option.affiliatedEntities } : {}, ...option.route ? { trailing: option.route } : {} };
3009
+ }), onSelect: (option) => chooseSubpayor(option.id) }) : /* @__PURE__ */ jsxs5("div", { className: "mbsf-error", role: "alert", children: [
3010
+ "No routing payers are available for ",
3011
+ administrator.name,
3012
+ ". Electronic submission remains blocked; contact support to correct the payer directory."
3013
+ ] }),
2899
3014
  selectedSubpayor ? /* @__PURE__ */ jsxs5("div", { className: "mbsf-payer-status", role: "status", children: [
2900
3015
  /* @__PURE__ */ jsx5("strong", { children: "\u2713 Payer set:" }),
2901
3016
  " ",
2902
- selectedSubpayor.label
2903
- ] }) : /* @__PURE__ */ jsx5("small", { className: "mbsf-help", children: "This claims administrator routes bills per payer. Choose the payer that should receive this bill." })
3017
+ selectedSubpayor.label,
3018
+ selectedSubpayor.route ? ` \xB7 ${selectedSubpayor.route}` : ""
3019
+ ] }) : /* @__PURE__ */ jsxs5("small", { className: "mbsf-help", children: [
3020
+ administrator.name,
3021
+ " administers multiple payers. Choose the payer named on the claim or report so MindBill can route the bill correctly."
3022
+ ] })
2904
3023
  ] }) : null,
2905
3024
  /* @__PURE__ */ jsx5(Field2, { label: "Injury description (optional)", span: true, children: text(bill.claim.description, (description2) => setBill((c) => ({ ...c, claim: { ...c.claim, description: description2 } }))) }),
2906
3025
  /* @__PURE__ */ jsxs5(Field2, { path: "diagnoses", label: "Diagnosis codes (ICD-10)", required: true, span: true, error: errors.diagnoses, children: [
@@ -5404,7 +5523,7 @@ function sandboxScenarios(state) {
5404
5523
  function shouldShowSandboxControls(environment, enabled = false) {
5405
5524
  return enabled && environment === "sandbox";
5406
5525
  }
5407
- function ConnectedBillLifecycle({ appearance, actorName, claimsAdministratorHint, sandboxControls = false, className, style, loadingFallback, errorFallback, onChanged, ...options }) {
5526
+ function ConnectedBillLifecycle({ appearance, actorName, claimsAdministratorHint, claimsAdministratorSources, sandboxControls = false, className, style, loadingFallback, errorFallback, onChanged, ...options }) {
5408
5527
  const lifecycle = useBillLifecycle(options);
5409
5528
  const { data } = lifecycle;
5410
5529
  const [tab, setTab] = useState11("details");
@@ -5625,6 +5744,7 @@ function ConnectedBillLifecycle({ appearance, actorName, claimsAdministratorHint
5625
5744
  onSearchClaimsAdministrators: lifecycle.searchClaimsAdministrators,
5626
5745
  onGetClaimsAdministratorDirectory: lifecycle.getClaimsAdministratorDirectory,
5627
5746
  claimsAdministratorHint,
5747
+ ...claimsAdministratorSources ? { claimsAdministratorSources } : {},
5628
5748
  attentionFields: correctionAttentionFields,
5629
5749
  attentionMessage: correctionAttentionFields.length ? "The rejected response points to the highlighted fields. Confirm every required value before resubmitting." : "Confirm the bill information below before resubmitting.",
5630
5750
  submitLabel: lifecycle.isMutating ? "Resubmitting\u2026" : "Resubmit bill",
@@ -5661,6 +5781,7 @@ function ConnectedBillLifecycle({ appearance, actorName, claimsAdministratorHint
5661
5781
  onSearchClaimsAdministrators: lifecycle.searchClaimsAdministrators,
5662
5782
  onGetClaimsAdministratorDirectory: lifecycle.getClaimsAdministratorDirectory,
5663
5783
  claimsAdministratorHint,
5784
+ ...claimsAdministratorSources ? { claimsAdministratorSources } : {},
5664
5785
  attentionMessage: "Confirm every value carried over from the closed bill before submitting the new bill.",
5665
5786
  submitLabel: lifecycle.isMutating ? "Submitting\u2026" : "Submit New Bill",
5666
5787
  heading: "New bill information",