@mindbill/react 0.20.0 → 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 +5 -8
- package/dist/index.d.ts +13 -1
- package/dist/index.js +202 -60
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
159
|
-
-
|
|
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
|
-
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1361
|
-
|
|
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":
|
|
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
|
-
|
|
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(
|
|
1423
|
-
const modifiers = useMemo2(() => mergeOptions(
|
|
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) =>
|
|
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 (
|
|
1609
|
+
if (query.trim().length < 2) return;
|
|
1610
|
+
const search = onSearchDiagnoses ?? referenceClient?.searchDiagnosisCodes;
|
|
1611
|
+
if (!search) return;
|
|
1488
1612
|
setDiagnosisLoading(true);
|
|
1489
|
-
void
|
|
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
|
-
|
|
1495
|
-
|
|
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
|
|
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: "
|
|
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 } : {}
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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: [
|
|
@@ -2167,7 +2305,7 @@ var lifecycleSurfaceStyles = `
|
|
|
2167
2305
|
.mb-surface-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:16px}.mb-surface-heading>div{display:grid;gap:2px}.mb-surface-heading strong{font-size:16px}.mb-surface-heading span,.mb-empty{color:var(--mb-muted);font-size:13px}.mb-surface-heading>span{border-radius:999px;background:var(--mb-soft);font-weight:750;padding:4px 8px}
|
|
2168
2306
|
.mb-lifecycle-actions{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-start}.mb-lifecycle-action{display:grid;gap:5px;max-width:260px}.mb-action-button{appearance:none;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius,8px);background:var(--mb-surface);color:var(--mb-text);font:inherit;font-weight:700;line-height:1.2;padding:11px 15px;cursor:pointer}.mb-action-button:hover:not(:disabled){border-color:var(--mb-accent);color:var(--mb-accent)}.mb-action-button:focus-visible{outline:3px solid color-mix(in srgb,var(--mb-accent) 28%,transparent);outline-offset:2px}.mb-action-button.is-primary{background:var(--mb-accent);border-color:var(--mb-accent);color:var(--mb-accent-contrast)}.mb-action-button:disabled{cursor:not-allowed;opacity:.55}.mb-action-reason{color:var(--mb-muted);font-size:12px;line-height:1.35}
|
|
2169
2307
|
.mb-activity-list{list-style:none;margin:0;padding:0}.mb-activity-item{display:grid;grid-template-columns:18px minmax(0,1fr);gap:12px;position:relative;padding:0 0 22px}.mb-activity-item:last-child{padding-bottom:0}.mb-activity-item:not(:last-child)::before{background:var(--mb-border);content:"";left:8px;position:absolute;top:10px;bottom:0;width:1px}.mb-activity-marker{background:var(--mb-surface);border:3px solid var(--mb-accent);border-radius:999px;height:11px;margin-top:4px;position:relative;width:11px;z-index:1}.mb-activity-content{display:grid;gap:4px;min-width:0}.mb-activity-content strong{font-size:15px;line-height:1.35}.mb-activity-content p{color:var(--mb-text);font-size:14px;line-height:1.5;margin:0}.mb-activity-content span,.mb-activity-empty{color:var(--mb-muted);font-size:13px;line-height:1.45}.mb-activity-empty,.mb-empty{margin:0}
|
|
2170
|
-
.mb-progress-list{display:grid;grid-template-columns:repeat(
|
|
2308
|
+
.mb-progress-list{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));list-style:none;margin:0;padding:0}.mb-progress-list li{display:grid;gap:7px;position:relative;text-align:center;color:var(--mb-muted);font-size:12px}.mb-progress-list li:not(:last-child)::after{content:"";position:absolute;left:calc(50% + 14px);right:calc(-50% + 14px);top:13px;height:2px;background:var(--mb-border)}.mb-progress-list li.is-complete:not(:last-child)::after{background:var(--mb-accent)}.mb-progress-list li>span{display:grid;place-items:center;justify-self:center;position:relative;z-index:1;width:28px;height:28px;border:2px solid var(--mb-border);border-radius:50%;background:var(--mb-surface);font-weight:800}.mb-progress-list li.is-complete>span,.mb-progress-list li.is-current>span{border-color:var(--mb-accent);background:var(--mb-accent);color:var(--mb-accent-contrast)}.mb-progress-list li.is-current{color:var(--mb-text)}
|
|
2171
2309
|
.mb-snapshot dl,.mb-remittance dl,.mb-contacts dl{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;margin:0}.mb-snapshot dl>div,.mb-remittance dl>div,.mb-contacts dl>div{display:grid;gap:3px;padding:10px 14px;border-left:1px solid var(--mb-border)}.mb-snapshot dl>div:nth-child(3n+1),.mb-remittance dl>div:first-child,.mb-contacts dl>div:first-child{border-left:0}.mb-snapshot dt,.mb-remittance dt,.mb-contacts dt{color:var(--mb-muted);font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.mb-snapshot dd,.mb-remittance dd,.mb-contacts dd{font-size:14px;font-weight:750;margin:0;overflow-wrap:anywhere}.mb-contacts a{color:var(--mb-accent)}.mb-denial{margin-top:16px;border-left:4px solid var(--mb-danger);border-radius:var(--mb-control-radius);background:color-mix(in srgb,var(--mb-danger) 8%,var(--mb-surface));padding:12px 14px}.mb-denial p{margin:4px 0 0}
|
|
2172
2310
|
.mb-payment-list{display:grid}.mb-payment-list article{display:grid;grid-template-columns:1fr auto;gap:5px 18px;padding:12px 0;border-top:1px solid var(--mb-border)}.mb-payment-list article:first-child{border-top:0}.mb-payment-list article>div{display:grid;gap:2px}.mb-payment-list article>div:nth-child(2){text-align:right}.mb-payment-list article span{color:var(--mb-muted);font-size:12px}.mb-payment-list article p{grid-column:1/-1;margin:0;color:var(--mb-muted);font-size:13px}
|
|
2173
2311
|
@media(max-width:700px){.mb-progress-list{grid-template-columns:1fr;text-align:left}.mb-progress-list li{grid-template-columns:28px 1fr;align-items:center;text-align:left}.mb-progress-list li:not(:last-child)::after{left:13px;right:auto;top:28px;bottom:-7px;width:2px;height:auto}.mb-progress-list li>span{grid-row:1}.mb-snapshot dl,.mb-remittance dl,.mb-contacts dl{grid-template-columns:1fr 1fr}.mb-snapshot dl>div,.mb-remittance dl>div,.mb-contacts dl>div{border:0;border-top:1px solid var(--mb-border);padding:10px 0}.mb-snapshot dl>div:nth-child(-n+2),.mb-remittance dl>div:nth-child(-n+2),.mb-contacts dl>div:nth-child(-n+2){border-top:0}.mb-payment-list article{grid-template-columns:1fr}.mb-payment-list article>div:nth-child(2){text-align:left}}
|
|
@@ -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,
|