@mindbill/react 0.20.1 → 0.21.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
@@ -141,9 +141,6 @@ import { BillSubmissionForm } from "@mindbill/react";
141
141
  initialBill={bootstrap.bill}
142
142
  attachments={bootstrap.attachments}
143
143
  getSession={() => fetch("/api/mindbill/session", { method: "POST" }).then(r => r.json())}
144
- diagnosisOptions={bootstrap.diagnoses}
145
- procedureOptions={bootstrap.procedures}
146
- onLookupPostalCode={lookupPostalCode}
147
144
  appearance={{ preset: "qme-companion" }}
148
145
  onSubmit={({ bill, sourceAttachmentIds, uploads }) =>
149
146
  submitBill({ bill, sourceAttachmentIds, uploads })
@@ -155,14 +152,14 @@ The component includes the interaction model, not just the markup:
155
152
 
156
153
  - a responsive two-column review form (one column on narrow screens);
157
154
  - paste-friendly `MM/DD/YYYY` date fields and required-field asterisks;
158
- - ZIP-to-city/state completion through `onLookupPostalCode`;
159
- - searchable ICD-10 multi-select with removable chips;
155
+ - ZIP-to-city/state completion through MindBill's authenticated postal directory;
156
+ - complete, server-backed ICD-10 search, common-injury quick picks, and removable chips;
160
157
  - canonical claims-administrator search through the authenticated MindBill payer directory;
161
158
  - QME, AME, and Psych QME evaluation modes with medical-legal modifier defaults;
162
- - searchable procedure/modifier controls, fee-schedule amounts, totals, and an automatically maintained empty line;
163
- - auto-attached source documents, practice W-9 treatment, and click, panel-drop, or whole-page PDF upload.
159
+ - searchable workers-comp procedure/modifier controls, medical-legal fee-schedule amounts, totals, valid manual CPT/HCPCS entry, and an automatically maintained empty line;
160
+ - removable source documents, a locked auto-attached practice W-9, and click, panel-drop, or whole-page PDF upload.
164
161
 
165
- Partners supply tenant-specific bootstrap data and server callbacks. Required fields, validation, payer selection, service-line behavior, attachments, and submission UX stay inside `@mindbill/react`, so every integration receives the same billing workflow.
162
+ Partners supply tenant-specific bootstrap data, one short-lived browser session callback, and the final server submission callback. Required fields, validation, ZIP lookup, ICD-10 and payer directories, service-line behavior, attachments, and submission UX stay inside `@mindbill/react`, so every integration receives the same billing workflow. Optional `diagnosisOptions`, `procedureOptions`, `modifierOptions`, and lookup callbacks extend or replace defaults when a partner has licensed or organization-specific data.
166
163
 
167
164
  `BILL_SUBMISSION_REQUIRED_FIELDS` and `validateBillSubmission` expose the same contract for tests and non-visual integrations. The component never creates a draft; its callback fires only when the user submits a locally valid snapshot.
168
165
 
package/dist/index.d.ts CHANGED
@@ -504,6 +504,18 @@ declare function applyBillSubmissionEvaluationModifiers(lines: BillSubmissionInp
504
504
  declare function validateBillSubmission(bill: BillSubmissionInput): BillSubmissionValidation;
505
505
  declare function BillSubmissionForm({ initialBill, attachments, onSubmit, getSession, sessionEndpoint, apiBaseUrl, fetch: fetchOverride, onSearchClaimsAdministrators, diagnosisOptions, onSearchDiagnoses, onLookupPostalCode, procedureOptions, modifierOptions, appearance, className, style, disabled, submitLabel, heading, description, }: BillSubmissionFormProps): ReactElement;
506
506
 
507
+ /** Public-domain and MindBill-owned metadata. CPT descriptions are intentionally limited to the curated catalog. */
508
+ declare const DEFAULT_BILL_SUBMISSION_PROCEDURES: BillSubmissionProcedureOption[];
509
+ declare const DEFAULT_BILL_SUBMISSION_MODIFIERS: BillSubmissionModifierOption[];
510
+ declare const BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS: Array<BillSubmissionDiagnosisOption & {
511
+ label: string;
512
+ }>;
513
+ declare function calculateBillSubmissionAllowedAmount(line: {
514
+ code: string;
515
+ modifiers?: string[];
516
+ units?: number;
517
+ }, procedures?: BillSubmissionProcedureOption[]): number | undefined;
518
+
507
519
  type BillStatusData = {
508
520
  billId: string;
509
521
  state: string;
@@ -668,4 +680,4 @@ type MindBillWidgetProps = {
668
680
  declare function MindBillBillTimeline(props: MindBillWidgetProps): ReactElement;
669
681
  declare function MindBillBillReview(props: MindBillWidgetProps): ReactElement;
670
682
 
671
- export { BILL_SUBMISSION_DOCUMENT_TYPES, BILL_SUBMISSION_REQUIRED_FIELDS, type BillActivityEvent, BillActivityTimeline, type BillActivityTimelineProps, BillLifecycleActions, type BillLifecycleActionsProps, BillLifecycleProgress, type BillLifecycleProgressProps, type BillLifecycleStage, BillPayerContactCard, type BillPayerContactCardProps, BillPaymentLedger, type BillPaymentLedgerProps, BillReadOnlyForm, type BillReadOnlyFormProps, BillRemittanceCard, type BillRemittanceCardProps, type BillReviewAttachment, type BillReviewBillingProvider, type BillReviewClinician, type BillReviewData, type BillReviewDocumentType, type BillReviewDraft, type BillReviewFeatures, BillReviewForm, type BillReviewFormProps, type BillReviewLineItem, type BillReviewLocation, type BillReviewPayer, type BillReviewSaveInput, BillSnapshotSummary, type BillSnapshotSummaryProps, type BillStatusAction, type BillStatusClient, type BillStatusClientOptions, type BillStatusData, type BillStatusSession, type BillStatusSessionProvider, type BillStatusSessionRequest, BillStatusSummary, type BillStatusSummaryProps, type BillSubmissionAddress, type BillSubmissionDiagnosisOption, type BillSubmissionDocumentType, type BillSubmissionEvaluationType, BillSubmissionForm, type BillSubmissionFormProps, type BillSubmissionFormValue, type BillSubmissionInput, type BillSubmissionModifierOption, type BillSubmissionPostalPlace, type BillSubmissionProcedureOption, type BillSubmissionRoute, type BillSubmissionSourceAttachment, type BillSubmissionUpload, type BillSubmissionValidation, ConnectedBillLifecycle, type ConnectedBillLifecycleProps, ConnectedBillStatus, type ConnectedBillStatusProps, MindBillBillReview, MindBillBillTimeline, type MindBillReactAppearance, type MindBillThemePreset, type MindBillWidgetProps, type UseBillLifecycleOptions, type UseBillLifecycleResult, type UseBillStatusOptions, type UseBillStatusResult, applyBillSubmissionEvaluationModifiers, billActivityEventLabel, billLifecycleStage, buildBillReviewSaveInput, createBillStatusClient, ensureTrailingBillSubmissionLine, ensureTrailingProcedureLine, formatBillSubmissionDate, mindBillAppearanceStyle, mindBillThemePresets, parseBillSubmissionDate, resolveMindBillAppearance, useBillLifecycle, useBillStatus, validateBillSubmission, visibleBillLifecycleActions };
683
+ export { BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS, BILL_SUBMISSION_DOCUMENT_TYPES, BILL_SUBMISSION_REQUIRED_FIELDS, type BillActivityEvent, BillActivityTimeline, type BillActivityTimelineProps, BillLifecycleActions, type BillLifecycleActionsProps, BillLifecycleProgress, type BillLifecycleProgressProps, type BillLifecycleStage, BillPayerContactCard, type BillPayerContactCardProps, BillPaymentLedger, type BillPaymentLedgerProps, BillReadOnlyForm, type BillReadOnlyFormProps, BillRemittanceCard, type BillRemittanceCardProps, type BillReviewAttachment, type BillReviewBillingProvider, type BillReviewClinician, type BillReviewData, type BillReviewDocumentType, type BillReviewDraft, type BillReviewFeatures, BillReviewForm, type BillReviewFormProps, type BillReviewLineItem, type BillReviewLocation, type BillReviewPayer, type BillReviewSaveInput, BillSnapshotSummary, type BillSnapshotSummaryProps, type BillStatusAction, type BillStatusClient, type BillStatusClientOptions, type BillStatusData, type BillStatusSession, type BillStatusSessionProvider, type BillStatusSessionRequest, BillStatusSummary, type BillStatusSummaryProps, type BillSubmissionAddress, type BillSubmissionDiagnosisOption, type BillSubmissionDocumentType, type BillSubmissionEvaluationType, BillSubmissionForm, type BillSubmissionFormProps, type BillSubmissionFormValue, type BillSubmissionInput, type BillSubmissionModifierOption, type BillSubmissionPostalPlace, type BillSubmissionProcedureOption, type BillSubmissionRoute, type BillSubmissionSourceAttachment, type BillSubmissionUpload, type BillSubmissionValidation, ConnectedBillLifecycle, type ConnectedBillLifecycleProps, ConnectedBillStatus, type ConnectedBillStatusProps, DEFAULT_BILL_SUBMISSION_MODIFIERS, DEFAULT_BILL_SUBMISSION_PROCEDURES, MindBillBillReview, MindBillBillTimeline, type MindBillReactAppearance, type MindBillThemePreset, type MindBillWidgetProps, type UseBillLifecycleOptions, type UseBillLifecycleResult, type UseBillStatusOptions, type UseBillStatusResult, applyBillSubmissionEvaluationModifiers, billActivityEventLabel, billLifecycleStage, buildBillReviewSaveInput, calculateBillSubmissionAllowedAmount, createBillStatusClient, ensureTrailingBillSubmissionLine, ensureTrailingProcedureLine, formatBillSubmissionDate, mindBillAppearanceStyle, mindBillThemePresets, parseBillSubmissionDate, resolveMindBillAppearance, useBillLifecycle, useBillStatus, validateBillSubmission, visibleBillLifecycleActions };
package/dist/index.js CHANGED
@@ -1159,6 +1159,127 @@ import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useRef as us
1159
1159
  import {
1160
1160
  createBillReferenceClient
1161
1161
  } from "@mindbill/browser";
1162
+
1163
+ // src/billing-catalog.ts
1164
+ var DEFAULT_BILL_SUBMISSION_PROCEDURES = [
1165
+ { code: "ML200", description: "Missed appointment for a medical-legal evaluation", allowedAmount: 503.75 },
1166
+ { code: "ML201", description: "Comprehensive medical-legal evaluation", allowedAmount: 2015 },
1167
+ { code: "ML202", description: "Follow-up medical-legal evaluation", allowedAmount: 1316.25 },
1168
+ { code: "ML203", description: "Supplemental medical-legal evaluation", allowedAmount: 650 },
1169
+ { code: "ML204", description: "Medical-legal testimony", allowedAmount: 113.75 },
1170
+ { code: "ML205", description: "Review of sub rosa recordings", allowedAmount: 81.25 },
1171
+ { code: "MLPRR", description: "Medical-legal record review", allowedAmount: 3 },
1172
+ { code: "90791", description: "Psychiatric diagnostic evaluation" },
1173
+ { code: "90792", description: "Psychiatric diagnostic evaluation with medical services" },
1174
+ { code: "90832", description: "Psychotherapy, 30 minutes" },
1175
+ { code: "90834", description: "Psychotherapy, 45 minutes" },
1176
+ { code: "90837", description: "Psychotherapy, 60 minutes" },
1177
+ { code: "90846", description: "Family psychotherapy without patient" },
1178
+ { code: "90847", description: "Family psychotherapy with patient" },
1179
+ { code: "90853", description: "Group psychotherapy" },
1180
+ { code: "90785", description: "Interactive complexity" },
1181
+ { code: "90833", description: "Psychotherapy add-on, 30 minutes" },
1182
+ { code: "90836", description: "Psychotherapy add-on, 45 minutes" },
1183
+ { code: "90838", description: "Psychotherapy add-on, 60 minutes" },
1184
+ { code: "99202", description: "New patient office visit, level 2" },
1185
+ { code: "99203", description: "New patient office visit, level 3" },
1186
+ { code: "99204", description: "New patient office visit, level 4" },
1187
+ { code: "99205", description: "New patient office visit, level 5", allowedAmount: 349.48 },
1188
+ { code: "99211", description: "Established patient office visit, level 1" },
1189
+ { code: "99212", description: "Established patient office visit, level 2" },
1190
+ { code: "99213", description: "Established patient office visit, level 3" },
1191
+ { code: "99214", description: "Established patient office visit, level 4" },
1192
+ { code: "99215", description: "Established patient office visit, level 5" },
1193
+ { code: "96130", description: "Psychological testing evaluation, first hour" },
1194
+ { code: "96131", description: "Psychological testing evaluation, each additional hour", allowedAmount: 131.96 },
1195
+ { code: "96136", description: "Psychological or neuropsychological testing, first 30 minutes" },
1196
+ { code: "96137", description: "Psychological or neuropsychological testing, each additional 30 minutes" },
1197
+ { code: "97161", description: "Physical therapy evaluation, low complexity" },
1198
+ { code: "97162", description: "Physical therapy evaluation, moderate complexity" },
1199
+ { code: "97163", description: "Physical therapy evaluation, high complexity" },
1200
+ { code: "97110", description: "Therapeutic exercises" },
1201
+ { code: "97112", description: "Neuromuscular reeducation" },
1202
+ { code: "97140", description: "Manual therapy techniques" },
1203
+ { code: "97530", description: "Therapeutic activities" },
1204
+ { code: "98940", description: "Chiropractic manipulative treatment, 1-2 regions" },
1205
+ { code: "98941", description: "Chiropractic manipulative treatment, 3-4 regions" },
1206
+ { code: "98942", description: "Chiropractic manipulative treatment, 5 regions" },
1207
+ { code: "72100", description: "Spine radiograph, lumbosacral, 2-3 views" },
1208
+ { code: "73030", description: "Shoulder radiograph, complete" },
1209
+ { code: "72141", description: "MRI cervical spine without contrast" },
1210
+ { code: "72148", description: "MRI lumbar spine without contrast" },
1211
+ { code: "73721", description: "MRI lower-extremity joint without contrast" },
1212
+ { code: "20610", description: "Major joint injection or aspiration" },
1213
+ { code: "20552", description: "Trigger point injection, 1-2 muscles" },
1214
+ { code: "64483", description: "Transforaminal epidural injection, lumbar or sacral" },
1215
+ { code: "64635", description: "Destruction by neurolytic agent, paravertebral facet joint nerve" },
1216
+ { code: "99070", description: "Supplies and materials" },
1217
+ { code: "L0650", description: "Lumbar orthosis" },
1218
+ { code: "A4556", description: "Electrodes" }
1219
+ ];
1220
+ var DEFAULT_BILL_SUBMISSION_MODIFIERS = [
1221
+ { code: "92", description: "Primary Treating Physician evaluation" },
1222
+ { code: "93", description: "Interpreter required" },
1223
+ { code: "94", description: "Agreed Medical Evaluator" },
1224
+ { code: "95", description: "Qualified Medical Evaluator" },
1225
+ { code: "96", description: "Psychiatric/psychological evaluation" },
1226
+ { code: "97", description: "Toxicology evaluation" },
1227
+ { code: "98", description: "Oncology evaluation" },
1228
+ { code: "59", description: "Distinct procedural service" },
1229
+ { code: "XE", description: "Separate encounter" },
1230
+ { code: "XS", description: "Separate structure" },
1231
+ { code: "XP", description: "Separate practitioner" },
1232
+ { code: "XU", description: "Unusual non-overlapping service" }
1233
+ ];
1234
+ var BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS = [
1235
+ { label: "Back", code: "M54.50", description: "Low back pain, unspecified" },
1236
+ { label: "Neck", code: "M54.2", description: "Cervicalgia" },
1237
+ { label: "Left hand", code: "M79.642", description: "Pain in left hand" },
1238
+ { label: "Right hand", code: "M79.641", description: "Pain in right hand" },
1239
+ { label: "Left knee", code: "M25.562", description: "Pain in left knee" },
1240
+ { label: "Right knee", code: "M25.561", description: "Pain in right knee" }
1241
+ ];
1242
+ var COMPOSITE_MULTIPLIERS = {
1243
+ "93+94+96": 2.45,
1244
+ "93+94+97": 1.95,
1245
+ "93+94+98": 1.95,
1246
+ "92+93": 1.1,
1247
+ "93+95": 1.1,
1248
+ "93+94": 1.45,
1249
+ "93+96": 2.1,
1250
+ "93+97": 1.6,
1251
+ "93+98": 1.6,
1252
+ "94+96": 2.35,
1253
+ "94+97": 1.85,
1254
+ "94+98": 1.85
1255
+ };
1256
+ var MED_LEGAL_MODIFIER_MULTIPLIERS = {
1257
+ "92": 1,
1258
+ "93": 1.1,
1259
+ "94": 1.35,
1260
+ "95": 1,
1261
+ "96": 2,
1262
+ "97": 1.5,
1263
+ "98": 1.5
1264
+ };
1265
+ function medicalLegalMultiplier(modifiers) {
1266
+ const priced = modifiers.filter((item) => MED_LEGAL_MODIFIER_MULTIPLIERS[item] !== 1);
1267
+ if (priced.length === 0) return 1;
1268
+ const composite = COMPOSITE_MULTIPLIERS[priced.join("+")];
1269
+ if (composite != null) return composite;
1270
+ return priced.reduce((total, item) => total * (MED_LEGAL_MODIFIER_MULTIPLIERS[item] ?? 1), 1);
1271
+ }
1272
+ function calculateBillSubmissionAllowedAmount(line, procedures = DEFAULT_BILL_SUBMISSION_PROCEDURES) {
1273
+ const procedure = procedures.find((item) => item.code.toUpperCase() === line.code.trim().toUpperCase());
1274
+ if (procedure?.allowedAmount == null) return void 0;
1275
+ const code = procedure.code.toUpperCase();
1276
+ const units = Math.max(1, line.units ?? 1);
1277
+ const normalized = [...new Set((line.modifiers ?? []).map((item) => item.replace(/^-/, "").toUpperCase()))].sort();
1278
+ const multiplier = ["ML200", "ML201", "ML202", "ML203"].includes(code) ? medicalLegalMultiplier(normalized) : 1;
1279
+ return Math.round(procedure.allowedAmount * units * multiplier * 100) / 100;
1280
+ }
1281
+
1282
+ // src/bill-submission-form.tsx
1162
1283
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1163
1284
  var BILL_SUBMISSION_DOCUMENT_TYPES = [
1164
1285
  "final_report",
@@ -1185,25 +1306,6 @@ var BILL_SUBMISSION_REQUIRED_FIELDS = [
1185
1306
  "serviceLines[].code",
1186
1307
  "serviceLines[].units"
1187
1308
  ];
1188
- var PROCEDURES2 = [
1189
- { code: "ML200", description: "Missed appointment for a medical-legal evaluation" },
1190
- { code: "ML201", description: "Comprehensive medical-legal evaluation" },
1191
- { code: "ML202", description: "Follow-up medical-legal evaluation" },
1192
- { code: "ML203", description: "Supplemental medical-legal evaluation" },
1193
- { code: "ML204", description: "Medical-legal testimony" },
1194
- { code: "ML205", description: "Review of sub rosa recordings" },
1195
- { code: "MLPRR", description: "Medical-legal record review" }
1196
- ];
1197
- var MODIFIERS2 = [
1198
- { code: "92", description: "Primary Treating Physician evaluation" },
1199
- { code: "93", description: "Interpreter required" },
1200
- { code: "94", description: "Agreed Medical Evaluator" },
1201
- { code: "95", description: "Qualified Medical Evaluator" },
1202
- { code: "96", description: "Psychiatric/psychological evaluation" },
1203
- { code: "97", description: "Toxicology evaluation" },
1204
- { code: "98", description: "Oncology evaluation" },
1205
- { code: "59", description: "Distinct procedural service" }
1206
- ];
1207
1309
  var documentLabels = {
1208
1310
  final_report: "Final report",
1209
1311
  proof_of_service: "Proof of service",
@@ -1313,12 +1415,12 @@ var css = `
1313
1415
  .mbsf{display:grid;gap:20px;color:var(--mb-text);font-family:var(--mb-font);font-size:15px}.mbsf *{box-sizing:border-box}
1314
1416
  .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)}
1315
1417
  .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-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-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)}
1316
- .mbsf-combo{position:relative}.mbsf-menu{position:absolute;z-index:20;top:calc(100% + 5px);left:0;right:0;max-height:300px;overflow:auto;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;width:100%;gap:2px;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 small{color:var(--mb-muted)}
1317
- .mbsf-chips{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:8px}.mbsf-chip{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}
1418
+ .mbsf-combo{position:relative}.mbsf-menu{position:absolute;z-index:20;top:calc(100% + 5px);left:0;right:0;max-height:min(300px,42vh);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;width:100%;gap:2px;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 small{color:var(--mb-muted)}
1419
+ .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)}
1318
1420
  .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)}
1319
1421
  .mbsf-lines{margin-top:18px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius);overflow:visible}.mbsf-line-head,.mbsf-line{display:grid;grid-template-columns:minmax(190px,1.05fr) minmax(220px,1.5fr) 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-money{padding-top:12px;text-align:right;font-variant-numeric:tabular-nums}.mbsf-total{display:flex;justify-content:flex-end;gap:45px;padding:16px 56px 16px 16px;font-size:17px;font-weight:760}
1320
1422
  .mbsf-icon-btn{width:40px;height:42px;border:0;background:transparent;color:var(--mb-text);font-size:22px;cursor:pointer}.mbsf-secondary{min-height:40px;padding:8px 14px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius);background:var(--mb-surface);color:var(--mb-text);font:inherit;font-weight:680;cursor:pointer}.mbsf-attach-list{display:grid;gap:10px;margin-bottom:18px}.mbsf-attach-row{padding:14px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius)}.mbsf-attach-row[data-auto=true]{border-color:color-mix(in srgb,#159447 45%,var(--mb-border));background:color-mix(in srgb,#159447 5%,var(--mb-surface))}.mbsf-file{min-width:0}.mbsf-file strong{overflow-wrap:anywhere}.mbsf-badge{display:inline-block;margin-left:8px;padding:2px 7px;border:1px solid var(--mb-border);border-radius:7px;color:var(--mb-muted);font-size:12px;font-weight:600}.mbsf-drop{display:grid;place-items:center;min-height:180px;padding:24px;border:2px dashed color-mix(in srgb,var(--mb-muted) 55%,transparent);border-radius:var(--mb-control-radius);background:color-mix(in srgb,var(--mb-accent) 3%,var(--mb-surface));text-align:center;cursor:pointer}.mbsf-drop[data-active=true]{border-color:var(--mb-accent);background:color-mix(in srgb,var(--mb-accent) 10%,var(--mb-surface))}.mbsf-alert{padding:12px 14px;border-radius:var(--mb-control-radius);background:color-mix(in srgb,var(--mb-danger) 10%,transparent);color:var(--mb-danger)}.mbsf-actions{justify-content:flex-end}.mbsf-submit{min-width:180px;min-height:48px;padding:11px 24px;border:0;border-radius:var(--mb-control-radius);background:var(--mb-accent);color:var(--mb-accent-contrast);font:inherit;font-weight:780;cursor:pointer}
1321
- @media(max-width:820px){.mbsf-grid{grid-template-columns:1fr}.mbsf-span{grid-column:auto}.mbsf-card{padding:18px}.mbsf-line-head{display:none}.mbsf-line{grid-template-columns:1fr 1fr}.mbsf-line>*:nth-child(1),.mbsf-line>*:nth-child(2){grid-column:1/-1}.mbsf-money{text-align:left}.mbsf-line .mbsf-icon-btn{justify-self:end}.mbsf-total{padding-right:18px}.mbsf-head{align-items:flex-start}.mbsf-segments{grid-template-columns:1fr}.mbsf-segment{border-right:0;border-bottom:1px solid var(--mb-border)}.mbsf-segment:last-child{border-bottom:0}}
1423
+ @media(max-width:820px){.mbsf{gap:16px}.mbsf-grid{grid-template-columns:1fr}.mbsf-span{grid-column:auto}.mbsf-card{padding:18px 16px}.mbsf-line-head{display:none}.mbsf-line{position:relative;display:grid;grid-template-columns:minmax(0,1fr) 86px;gap:14px;padding:18px 16px}.mbsf-line>div:before{display:block;margin-bottom:6px;color:var(--mb-muted);font-size:12px;font-weight:700;content:attr(data-label)}.mbsf-line>div:nth-child(1),.mbsf-line>div:nth-child(2){grid-column:1/-1}.mbsf-money{align-self:end;padding:0 0 12px;text-align:right}.mbsf-line .mbsf-icon-btn{position:absolute;right:8px;bottom:3px}.mbsf-total{padding:16px 18px;gap:24px}.mbsf-head{align-items:flex-start}.mbsf-segments{grid-template-columns:repeat(3,minmax(0,1fr))}.mbsf-segment{min-width:0;padding:8px 4px;border-right:1px solid var(--mb-border);border-bottom:0;font-size:13px}.mbsf-segment:last-child{border-right:0}.mbsf-attach-row{align-items:flex-start;flex-wrap:wrap}.mbsf-actions{position:sticky;bottom:86px;z-index:10}.mbsf-submit{width:100%}}
1322
1424
  `;
1323
1425
  function RequiredMark() {
1324
1426
  return /* @__PURE__ */ jsx3("span", { className: "mbsf-star", children: " *" });
@@ -1352,24 +1454,26 @@ function TextDateInput({ value, onChange, disabled, required, ariaLabel }) {
1352
1454
  invalid ? /* @__PURE__ */ jsx3("small", { className: "mbsf-error", children: "Use MM/DD/YYYY" }) : null
1353
1455
  ] });
1354
1456
  }
1355
- function ComboBox({ value, placeholder, options, disabled, loading, onQuery, onSelect, ariaLabel }) {
1457
+ function ComboBox({ value, placeholder, options, disabled, loading, onQuery, onSelect, createOption, ariaLabel }) {
1356
1458
  const [open, setOpen] = useState2(false);
1357
1459
  const [query, setQuery] = useState2("");
1358
1460
  const visible = useMemo2(() => {
1359
1461
  const q = query.trim().toLowerCase();
1360
- return q ? options.filter((option) => `${option.id} ${option.label} ${option.detail ?? ""}`.toLowerCase().includes(q)) : options;
1361
- }, [options, query]);
1462
+ const matches = q ? options.filter((option) => `${option.id} ${option.label} ${option.detail ?? ""}`.toLowerCase().includes(q)) : options;
1463
+ const custom = createOption?.(query) ?? null;
1464
+ return custom && !matches.some((option) => option.id.toUpperCase() === custom.id.toUpperCase()) ? [...matches, custom] : matches;
1465
+ }, [createOption, options, query]);
1466
+ const showMenu = open && (loading || visible.length > 0 || query.trim().length >= 2);
1362
1467
  return /* @__PURE__ */ jsxs3("div", { className: "mbsf-combo", children: [
1363
- /* @__PURE__ */ jsx3("input", { className: "mbsf-input", role: "combobox", "aria-label": ariaLabel, "aria-expanded": open, autoComplete: "off", disabled, placeholder, value: open ? query : value, onFocus: () => {
1468
+ /* @__PURE__ */ jsx3("input", { className: "mbsf-input", role: "combobox", "aria-label": ariaLabel, "aria-expanded": showMenu, autoComplete: "off", disabled, placeholder, value: open ? query : value, onFocus: () => {
1364
1469
  setOpen(true);
1365
1470
  setQuery("");
1366
- onQuery?.("");
1367
1471
  }, onChange: (event) => {
1368
1472
  setOpen(true);
1369
1473
  setQuery(event.target.value);
1370
1474
  onQuery?.(event.target.value);
1371
1475
  }, onBlur: () => setTimeout(() => setOpen(false), 120) }),
1372
- open ? /* @__PURE__ */ jsx3("div", { className: "mbsf-menu", role: "listbox", children: loading ? /* @__PURE__ */ jsx3("div", { className: "mbsf-option", children: "Searching\u2026" }) : visible.length ? visible.map((option) => /* @__PURE__ */ jsxs3("button", { className: "mbsf-option", type: "button", role: "option", onMouseDown: (event) => event.preventDefault(), onClick: () => {
1476
+ showMenu ? /* @__PURE__ */ jsx3("div", { className: "mbsf-menu", role: "listbox", children: loading ? /* @__PURE__ */ jsx3("div", { className: "mbsf-option", children: "Searching\u2026" }) : visible.length ? visible.map((option) => /* @__PURE__ */ jsxs3("button", { className: "mbsf-option", type: "button", role: "option", onMouseDown: (event) => event.preventDefault(), onClick: () => {
1373
1477
  onSelect(option);
1374
1478
  setOpen(false);
1375
1479
  setQuery("");
@@ -1379,6 +1483,11 @@ function ComboBox({ value, placeholder, options, disabled, loading, onQuery, onS
1379
1483
  ] }, option.id)) : /* @__PURE__ */ jsx3("div", { className: "mbsf-option", children: "No matches" }) }) : null
1380
1484
  ] });
1381
1485
  }
1486
+ function customProcedureOption(query) {
1487
+ const code = query.trim().toUpperCase().replace(/\s+/g, "");
1488
+ if (!/^(?:\d{5}|[A-Z]\d{4}|ML(?:20[0-5]|PRR))$/.test(code)) return null;
1489
+ return { id: code, label: code, detail: "Use this CPT, HCPCS, or medical-legal code" };
1490
+ }
1382
1491
  function mergeOptions(defaults, supplied) {
1383
1492
  const map = new Map(defaults.map((item) => [item.code.toUpperCase(), item]));
1384
1493
  supplied?.forEach((item) => map.set(item.code.toUpperCase(), item));
@@ -1407,7 +1516,8 @@ function BillSubmissionForm({
1407
1516
  description = "Review the bill details, add attachments, and submit."
1408
1517
  }) {
1409
1518
  const [bill, setBill] = useState2(() => cloneBill(initialBill));
1410
- const [selectedIds, setSelectedIds] = useState2(() => attachments.filter((item) => item.selected !== false || item.autoAttached).map((item) => item.id));
1519
+ const [selectedIds, setSelectedIds] = useState2(() => attachments.filter((item) => item.selected !== false || item.autoAttached || item.documentType === "w9").map((item) => item.id));
1520
+ const [removedSourceIds, setRemovedSourceIds] = useState2([]);
1411
1521
  const [uploads, setUploads] = useState2([]);
1412
1522
  const [errors, setErrors] = useState2({});
1413
1523
  const [formError, setFormError] = useState2(null);
@@ -1419,14 +1529,15 @@ function BillSubmissionForm({
1419
1529
  const [postalStatus, setPostalStatus] = useState2(null);
1420
1530
  const [dragActive, setDragActive] = useState2(false);
1421
1531
  const fileInput = useRef2(null);
1422
- const procedures = useMemo2(() => mergeOptions(PROCEDURES2, procedureOptions), [procedureOptions]);
1423
- const modifiers = useMemo2(() => mergeOptions(MODIFIERS2, modifierOptions), [modifierOptions]);
1532
+ const procedures = useMemo2(() => mergeOptions(DEFAULT_BILL_SUBMISSION_PROCEDURES, procedureOptions), [procedureOptions]);
1533
+ const modifiers = useMemo2(() => mergeOptions(DEFAULT_BILL_SUBMISSION_MODIFIERS, modifierOptions), [modifierOptions]);
1424
1534
  const [evaluationType, setEvaluationType] = useState2(() => initialBill.renderingProvider?.isAme ? "ame" : initialBill.renderingProvider?.specialty?.toLowerCase().includes("psych") ? "psych_qme" : "qme");
1425
1535
  const referenceClient = useMemo2(() => getSession ? createBillReferenceClient({ getSession, sessionEndpoint, apiBaseUrl, fetch: fetchOverride }) : null, [getSession, sessionEndpoint, apiBaseUrl, fetchOverride]);
1426
1536
  const locked = disabled || submitting;
1427
1537
  useEffect2(() => {
1428
1538
  setBill(cloneBill(initialBill));
1429
- setSelectedIds(attachments.filter((item) => item.selected !== false || item.autoAttached).map((item) => item.id));
1539
+ setSelectedIds(attachments.filter((item) => item.selected !== false || item.autoAttached || item.documentType === "w9").map((item) => item.id));
1540
+ setRemovedSourceIds([]);
1430
1541
  setUploads([]);
1431
1542
  setErrors({});
1432
1543
  setFormError(null);
@@ -1471,7 +1582,18 @@ function BillSubmissionForm({
1471
1582
  };
1472
1583
  }, [addFiles]);
1473
1584
  const setAddress = (patch) => setBill((current) => ({ ...current, patient: { ...current.patient, address: { ...current.patient.address, ...patch } } }));
1474
- const setLine = (index, patch) => setBill((current) => ({ ...current, serviceLines: ensureTrailingBillSubmissionLine(current.serviceLines.map((line, lineIndex) => lineIndex === index ? { ...line, ...patch } : line)) }));
1585
+ const setLine = (index, patch) => setBill((current) => ({ ...current, serviceLines: ensureTrailingBillSubmissionLine(current.serviceLines.map((line, lineIndex) => {
1586
+ if (lineIndex !== index) return line;
1587
+ const next = { ...line, ...patch };
1588
+ const charge = calculateBillSubmissionAllowedAmount(next, procedures);
1589
+ if (charge != null) return { ...next, charge };
1590
+ if (Object.hasOwn(patch, "code")) {
1591
+ const withoutCharge = { ...next };
1592
+ delete withoutCharge.charge;
1593
+ return withoutCharge;
1594
+ }
1595
+ return next;
1596
+ })) }));
1475
1597
  const text = (value, onChange, options = {}) => /* @__PURE__ */ jsx3("input", { className: "mbsf-input", disabled: locked, value: value ?? "", onChange: (event) => onChange(event.target.value), ...options });
1476
1598
  const searchPayers = (query) => {
1477
1599
  if (query.trim().length < 2) return;
@@ -1484,15 +1606,19 @@ function BillSubmissionForm({
1484
1606
  void search(query, bill.claim.claimNumber).then(setPayerResults).catch((caught) => setFormError(caught instanceof Error ? caught.message : "Claims administrator search is unavailable.")).finally(() => setPayerLoading(false));
1485
1607
  };
1486
1608
  const searchDiagnoses = (query) => {
1487
- if (!onSearchDiagnoses) return;
1609
+ if (query.trim().length < 2) return;
1610
+ const search = onSearchDiagnoses ?? referenceClient?.searchDiagnosisCodes;
1611
+ if (!search) return;
1488
1612
  setDiagnosisLoading(true);
1489
- void onSearchDiagnoses(query).then(setDiagnosisResults).catch(() => setDiagnosisResults([])).finally(() => setDiagnosisLoading(false));
1613
+ void search(query).then(setDiagnosisResults).catch(() => setDiagnosisResults([])).finally(() => setDiagnosisLoading(false));
1490
1614
  };
1491
1615
  const updatePostalCode = (postalCode) => {
1492
1616
  setAddress({ postalCode });
1493
1617
  setPostalStatus(null);
1494
- if (!onLookupPostalCode || !/^\d{5}$/.test(postalCode)) return;
1495
- void onLookupPostalCode(postalCode).then((place) => {
1618
+ const lookup = onLookupPostalCode ?? referenceClient?.lookupPostalCode;
1619
+ if (!lookup || !/^\d{5}$/.test(postalCode)) return;
1620
+ setPostalStatus("Looking up ZIP\u2026");
1621
+ void lookup(postalCode).then((place) => {
1496
1622
  if (!place) return setPostalStatus("ZIP not found");
1497
1623
  setAddress({ city: place.city, state: place.state.toUpperCase() });
1498
1624
  setPostalStatus(`${place.city}, ${place.state.toUpperCase()} filled from ZIP`);
@@ -1502,9 +1628,13 @@ function BillSubmissionForm({
1502
1628
  setEvaluationType(type);
1503
1629
  setBill((current) => ({ ...current, renderingProvider: { ...current.renderingProvider, isAme: type === "ame", isQme: type !== "ame", ...type === "psych_qme" && !current.renderingProvider?.specialty ? { specialty: "Psychiatry" } : {} }, serviceLines: applyBillSubmissionEvaluationModifiers(current.serviceLines, type) }));
1504
1630
  };
1505
- const total = submittedLines(bill.serviceLines).reduce((sum, line) => sum + (Number.isFinite(line.charge) ? Number(line.charge) : 0), 0);
1631
+ const lineCharge = (line) => calculateBillSubmissionAllowedAmount(line, procedures) ?? (Number.isFinite(line.charge) ? Number(line.charge) : void 0);
1632
+ const total = submittedLines(bill.serviceLines).reduce((sum, line) => sum + (lineCharge(line) ?? 0), 0);
1506
1633
  async function submit() {
1507
- const clean = { ...cloneBill(bill), serviceLines: submittedLines(bill.serviceLines) };
1634
+ const clean = { ...cloneBill(bill), serviceLines: submittedLines(bill.serviceLines).map((line) => {
1635
+ const charge = lineCharge(line);
1636
+ return charge == null ? line : { ...line, charge };
1637
+ }) };
1508
1638
  const validation = validateBillSubmission(clean);
1509
1639
  setErrors(validation.fieldErrors);
1510
1640
  setFormError(null);
@@ -1562,15 +1692,23 @@ function BillSubmissionForm({
1562
1692
  /* @__PURE__ */ jsx3(Field2, { label: "Claims administrator", required: true, span: true, error: errors["claim.claimsAdministrator"], children: /* @__PURE__ */ jsx3(ComboBox, { ariaLabel: "Claims administrator", disabled: locked, loading: payerLoading, value: bill.claim.claimsAdministrator?.name ?? "", placeholder: "Search the payer directory\u2026", options: payerResults.map((payer) => ({ id: payer.id, label: payer.name, detail: [payer.hasElectronic ? "Electronic" : "Work comp", ...payer.states ?? []].join(" \xB7 ") })), onQuery: searchPayers, onSelect: (option) => setBill((c) => ({ ...c, claim: { ...c.claim, claimsAdministrator: { id: option.id, name: option.label } } })) }) }),
1563
1693
  /* @__PURE__ */ jsx3(Field2, { label: "Injury description (optional)", span: true, children: text(bill.claim.description, (description2) => setBill((c) => ({ ...c, claim: { ...c.claim, description: description2 } }))) }),
1564
1694
  /* @__PURE__ */ jsxs3(Field2, { label: "Diagnosis codes (ICD-10)", span: true, children: [
1695
+ /* @__PURE__ */ jsx3("div", { className: "mbsf-quick-picks", "aria-label": "Common diagnosis codes", children: BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS.map((option) => {
1696
+ const selected = (bill.diagnoses ?? []).includes(option.code);
1697
+ return /* @__PURE__ */ jsxs3("button", { className: "mbsf-quick-pick", "data-selected": selected, type: "button", "aria-pressed": selected, title: `${option.code} \u2014 ${option.description}`, onClick: () => setBill((current) => ({ ...current, diagnoses: selected ? (current.diagnoses ?? []).filter((code) => code !== option.code) : [.../* @__PURE__ */ new Set([...current.diagnoses ?? [], option.code])] })), children: [
1698
+ selected ? "\u2713" : "+",
1699
+ " ",
1700
+ option.label
1701
+ ] }, option.code);
1702
+ }) }),
1565
1703
  /* @__PURE__ */ jsx3("div", { className: "mbsf-chips", children: (bill.diagnoses ?? []).map((code) => {
1566
- const option = [...diagnosisOptions, ...diagnosisResults].find((item) => item.code === code);
1704
+ const option = [...BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS, ...diagnosisOptions, ...diagnosisResults].find((item) => item.code === code);
1567
1705
  return /* @__PURE__ */ jsxs3("span", { className: "mbsf-chip", children: [
1568
1706
  /* @__PURE__ */ jsx3("strong", { children: code }),
1569
1707
  option?.description ? ` ${option.description}` : "",
1570
1708
  /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": `Remove ${code}`, onClick: () => setBill((c) => ({ ...c, diagnoses: (c.diagnoses ?? []).filter((item) => item !== code) })), children: "\xD7" })
1571
1709
  ] }, code);
1572
1710
  }) }),
1573
- /* @__PURE__ */ jsx3(ComboBox, { ariaLabel: "Add diagnosis code", disabled: locked, loading: diagnosisLoading, value: "", placeholder: bill.diagnoses?.length ?? 0 ? `${bill.diagnoses.length} selected \u2014 add more\u2026` : "Search ICD-10 codes\u2026", options: [...new Map([...diagnosisOptions, ...diagnosisResults].map((item) => [item.code, item])).values()].filter((item) => !(bill.diagnoses ?? []).includes(item.code)).map((item) => ({ id: item.code, label: item.code, detail: item.description })), onQuery: searchDiagnoses, onSelect: (option) => setBill((c) => ({ ...c, diagnoses: [.../* @__PURE__ */ new Set([...c.diagnoses ?? [], option.id])] })) })
1711
+ /* @__PURE__ */ jsx3(ComboBox, { ariaLabel: "Add diagnosis code", disabled: locked, loading: diagnosisLoading, value: "", placeholder: bill.diagnoses?.length ?? 0 ? `${bill.diagnoses.length} selected \u2014 add more\u2026` : "Search ICD-10 codes\u2026", options: [...new Map([...BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS, ...diagnosisOptions, ...diagnosisResults].map((item) => [item.code, item])).values()].filter((item) => !(bill.diagnoses ?? []).includes(item.code)).map((item) => ({ id: item.code, label: item.code, detail: item.description })), onQuery: searchDiagnoses, onSelect: (option) => setBill((c) => ({ ...c, diagnoses: [.../* @__PURE__ */ new Set([...c.diagnoses ?? [], option.id])] })) })
1574
1712
  ] })
1575
1713
  ] })
1576
1714
  ] }),
@@ -1605,16 +1743,15 @@ function BillSubmissionForm({
1605
1743
  " "
1606
1744
  ] }),
1607
1745
  bill.serviceLines.map((line, index) => /* @__PURE__ */ jsxs3("div", { className: "mbsf-line", children: [
1608
- /* @__PURE__ */ jsxs3("div", { children: [
1609
- /* @__PURE__ */ jsx3(ComboBox, { ariaLabel: `Procedure code ${index + 1}`, disabled: locked, value: line.code, placeholder: "Code\u2026", options: procedures.map((item) => ({ id: item.code, label: item.code, detail: item.description })), onSelect: (option) => {
1610
- const selected = procedures.find((item) => item.code === option.id);
1746
+ /* @__PURE__ */ jsxs3("div", { "data-label": "Procedure code", children: [
1747
+ /* @__PURE__ */ jsx3(ComboBox, { ariaLabel: `Procedure code ${index + 1}`, disabled: locked, value: line.code, placeholder: "Search or enter code\u2026", options: procedures.map((item) => ({ id: item.code, label: item.code, detail: item.description })), createOption: customProcedureOption, onSelect: (option) => {
1611
1748
  const auto = evaluationModifier(evaluationType, option.id);
1612
- setLine(index, { code: option.id, ...auto ? { modifiers: [auto, ...(line.modifiers ?? []).filter((item) => !["94", "95", "96"].includes(item.replace(/^-/, "")))] } : line.modifiers ? { modifiers: line.modifiers } : {}, ...selected?.allowedAmount != null ? { charge: selected.allowedAmount * (line.units ?? 1) } : {} });
1749
+ setLine(index, { code: option.id, ...auto ? { modifiers: [auto, ...(line.modifiers ?? []).filter((item) => !["94", "95", "96"].includes(item.replace(/^-/, "")))] } : line.modifiers ? { modifiers: line.modifiers } : {} });
1613
1750
  } }),
1614
- line.code ? /* @__PURE__ */ jsx3("small", { className: "mbsf-help", children: procedures.find((item) => item.code === line.code)?.description }) : null,
1751
+ line.code ? /* @__PURE__ */ jsx3("small", { className: "mbsf-help", children: procedures.find((item) => item.code === line.code)?.description ?? "Custom CPT, HCPCS, or medical-legal code" }) : null,
1615
1752
  errors[`serviceLines.${index}.code`] ? /* @__PURE__ */ jsx3("small", { className: "mbsf-error", children: errors[`serviceLines.${index}.code`] }) : null
1616
1753
  ] }),
1617
- /* @__PURE__ */ jsxs3("div", { children: [
1754
+ /* @__PURE__ */ jsxs3("div", { "data-label": "Modifiers", children: [
1618
1755
  /* @__PURE__ */ jsx3("div", { className: "mbsf-chips", children: (line.modifiers ?? []).map((modifier) => /* @__PURE__ */ jsxs3("span", { className: "mbsf-chip", children: [
1619
1756
  "\u2212",
1620
1757
  modifier.replace(/^-/, ""),
@@ -1622,15 +1759,11 @@ function BillSubmissionForm({
1622
1759
  ] }, modifier)) }),
1623
1760
  /* @__PURE__ */ jsx3(ComboBox, { ariaLabel: `Modifiers ${index + 1}`, disabled: locked, value: "", placeholder: line.modifiers?.length ?? 0 ? `${line.modifiers.length} modifier${line.modifiers.length === 1 ? "" : "s"}` : "Add modifiers\u2026", options: modifiers.filter((item) => !(line.modifiers ?? []).includes(item.code)).map((item) => ({ id: item.code, label: `\u2212${item.code}`, detail: item.description })), onSelect: (option) => setLine(index, { modifiers: [.../* @__PURE__ */ new Set([...line.modifiers ?? [], option.id])] }) })
1624
1761
  ] }),
1625
- /* @__PURE__ */ jsxs3("div", { children: [
1626
- /* @__PURE__ */ jsx3("input", { className: "mbsf-input", "aria-label": `Units ${index + 1}`, type: "number", min: 1, value: line.units ?? 1, onChange: (event) => {
1627
- const units = Number(event.target.value);
1628
- const selected = procedures.find((item) => item.code === line.code);
1629
- setLine(index, { units, ...selected?.allowedAmount != null ? { charge: selected.allowedAmount * units } : {} });
1630
- } }),
1762
+ /* @__PURE__ */ jsxs3("div", { "data-label": "Units", children: [
1763
+ /* @__PURE__ */ jsx3("input", { className: "mbsf-input", "aria-label": `Units ${index + 1}`, type: "number", min: 1, value: line.units ?? 1, onChange: (event) => setLine(index, { units: Number(event.target.value) }) }),
1631
1764
  errors[`serviceLines.${index}.units`] ? /* @__PURE__ */ jsx3("small", { className: "mbsf-error", children: errors[`serviceLines.${index}.units`] }) : null
1632
1765
  ] }),
1633
- /* @__PURE__ */ jsx3("div", { className: "mbsf-money", children: line.charge == null ? "\u2014" : line.charge.toLocaleString(void 0, { style: "currency", currency: "USD" }) }),
1766
+ /* @__PURE__ */ jsx3("div", { className: "mbsf-money", "data-label": "Allowed", children: lineCharge(line) == null ? "\u2014" : lineCharge(line).toLocaleString(void 0, { style: "currency", currency: "USD" }) }),
1634
1767
  /* @__PURE__ */ jsx3("button", { className: "mbsf-icon-btn", type: "button", "aria-label": `Remove service line ${index + 1}`, disabled: locked || !lineHasContent(line) && index === bill.serviceLines.length - 1, onClick: () => setBill((c) => ({ ...c, serviceLines: ensureTrailingBillSubmissionLine(c.serviceLines.filter((_, itemIndex) => itemIndex !== index)) })), children: "\xD7" })
1635
1768
  ] }, index)),
1636
1769
  /* @__PURE__ */ jsxs3("div", { className: "mbsf-total", children: [
@@ -1643,19 +1776,24 @@ function BillSubmissionForm({
1643
1776
  /* @__PURE__ */ jsxs3("fieldset", { className: "mbsf-card", disabled: locked, children: [
1644
1777
  /* @__PURE__ */ jsx3("legend", { className: "mbsf-legend", children: "Attachments" }),
1645
1778
  /* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-list", children: [
1646
- attachments.map((attachment) => {
1647
- const auto = attachment.autoAttached ?? attachment.documentType === "w9";
1779
+ attachments.filter((attachment) => !removedSourceIds.includes(attachment.id)).map((attachment) => {
1780
+ const auto = attachment.autoAttached || attachment.documentType === "w9";
1648
1781
  const selected = selectedIds.includes(attachment.id);
1782
+ const removable = !auto && attachment.removable !== false;
1649
1783
  return /* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-row", "data-auto": auto, children: [
1650
1784
  /* @__PURE__ */ jsxs3("label", { className: "mbsf-attach-row", style: { border: 0, padding: 0, flex: 1, justifyContent: "flex-start" }, children: [
1651
- /* @__PURE__ */ jsx3("input", { type: "checkbox", checked: selected, disabled: locked || auto || attachment.removable === false, onChange: (event) => setSelectedIds((current) => event.target.checked ? [.../* @__PURE__ */ new Set([...current, attachment.id])] : current.filter((id) => id !== attachment.id)) }),
1785
+ auto ? /* @__PURE__ */ jsx3("span", { "aria-label": "Always attached", role: "img", children: "\u2713" }) : /* @__PURE__ */ jsx3("input", { type: "checkbox", checked: selected, disabled: locked, onChange: (event) => setSelectedIds((current) => event.target.checked ? [.../* @__PURE__ */ new Set([...current, attachment.id])] : current.filter((id) => id !== attachment.id)) }),
1652
1786
  /* @__PURE__ */ jsxs3("span", { className: "mbsf-file", children: [
1653
1787
  /* @__PURE__ */ jsx3("strong", { children: attachment.fileName }),
1654
1788
  /* @__PURE__ */ jsx3("span", { className: "mbsf-badge", children: auto ? "Auto-attached" : documentLabels[attachment.documentType] }),
1655
- /* @__PURE__ */ jsx3("span", { className: "mbsf-help", style: { display: "block" }, children: attachment.description || (auto ? "Included automatically with this bill." : documentLabels[attachment.documentType]) })
1789
+ /* @__PURE__ */ jsx3("span", { className: "mbsf-help", style: { display: "block" }, children: attachment.description || (auto ? "Included automatically with every bill." : documentLabels[attachment.documentType]) })
1656
1790
  ] })
1657
1791
  ] }),
1658
- attachment.previewUrl ? /* @__PURE__ */ jsx3("a", { className: "mbsf-secondary", href: attachment.previewUrl, target: "_blank", rel: "noreferrer", children: "View" }) : null
1792
+ attachment.previewUrl ? /* @__PURE__ */ jsx3("a", { className: "mbsf-secondary", href: attachment.previewUrl, target: "_blank", rel: "noreferrer", children: "View" }) : null,
1793
+ removable ? /* @__PURE__ */ jsx3("button", { className: "mbsf-icon-btn", type: "button", "aria-label": `Remove ${attachment.fileName}`, disabled: locked, onClick: () => {
1794
+ setSelectedIds((current) => current.filter((id) => id !== attachment.id));
1795
+ setRemovedSourceIds((current) => [.../* @__PURE__ */ new Set([...current, attachment.id])]);
1796
+ }, children: "\xD7" }) : null
1659
1797
  ] }, attachment.id);
1660
1798
  }),
1661
1799
  uploads.map((upload, index) => /* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-row", children: [
@@ -2581,6 +2719,7 @@ function MindBillBillReview(props) {
2581
2719
  return widget("mindbill-bill-review", props);
2582
2720
  }
2583
2721
  export {
2722
+ BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS,
2584
2723
  BILL_SUBMISSION_DOCUMENT_TYPES,
2585
2724
  BILL_SUBMISSION_REQUIRED_FIELDS,
2586
2725
  BillActivityTimeline,
@@ -2596,12 +2735,15 @@ export {
2596
2735
  BillSubmissionForm,
2597
2736
  ConnectedBillLifecycle,
2598
2737
  ConnectedBillStatus,
2738
+ DEFAULT_BILL_SUBMISSION_MODIFIERS,
2739
+ DEFAULT_BILL_SUBMISSION_PROCEDURES,
2599
2740
  MindBillBillReview,
2600
2741
  MindBillBillTimeline,
2601
2742
  applyBillSubmissionEvaluationModifiers,
2602
2743
  billActivityEventLabel,
2603
2744
  billLifecycleStage,
2604
2745
  buildBillReviewSaveInput,
2746
+ calculateBillSubmissionAllowedAmount,
2605
2747
  createBillLifecycleClient2 as createBillLifecycleClient,
2606
2748
  createBillStatusClient,
2607
2749
  ensureTrailingBillSubmissionLine,