@mindbill/react 0.20.1 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -8
- package/dist/index.d.ts +14 -1
- package/dist/index.js +220 -66
- 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 with new-tab previews, a locked auto-attached practice W-9, and a full-width click, panel-drop, or whole-page PDF upload area. Every visible source document is included until removed; uploaded PDFs do not require document-type tagging.
|
|
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
|
@@ -453,6 +453,7 @@ type BillSubmissionSourceAttachment = {
|
|
|
453
453
|
fileName: string;
|
|
454
454
|
documentType: BillSubmissionDocumentType;
|
|
455
455
|
description?: string;
|
|
456
|
+
/** @deprecated Source attachments shown in the form are included until removed. */
|
|
456
457
|
selected?: boolean;
|
|
457
458
|
/** Auto-attached documents such as a practice W-9 cannot be deselected. */
|
|
458
459
|
autoAttached?: boolean;
|
|
@@ -504,6 +505,18 @@ declare function applyBillSubmissionEvaluationModifiers(lines: BillSubmissionInp
|
|
|
504
505
|
declare function validateBillSubmission(bill: BillSubmissionInput): BillSubmissionValidation;
|
|
505
506
|
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
507
|
|
|
508
|
+
/** Public-domain and MindBill-owned metadata. CPT descriptions are intentionally limited to the curated catalog. */
|
|
509
|
+
declare const DEFAULT_BILL_SUBMISSION_PROCEDURES: BillSubmissionProcedureOption[];
|
|
510
|
+
declare const DEFAULT_BILL_SUBMISSION_MODIFIERS: BillSubmissionModifierOption[];
|
|
511
|
+
declare const BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS: Array<BillSubmissionDiagnosisOption & {
|
|
512
|
+
label: string;
|
|
513
|
+
}>;
|
|
514
|
+
declare function calculateBillSubmissionAllowedAmount(line: {
|
|
515
|
+
code: string;
|
|
516
|
+
modifiers?: string[];
|
|
517
|
+
units?: number;
|
|
518
|
+
}, procedures?: BillSubmissionProcedureOption[]): number | undefined;
|
|
519
|
+
|
|
507
520
|
type BillStatusData = {
|
|
508
521
|
billId: string;
|
|
509
522
|
state: string;
|
|
@@ -668,4 +681,4 @@ type MindBillWidgetProps = {
|
|
|
668
681
|
declare function MindBillBillTimeline(props: MindBillWidgetProps): ReactElement;
|
|
669
682
|
declare function MindBillBillReview(props: MindBillWidgetProps): ReactElement;
|
|
670
683
|
|
|
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 };
|
|
684
|
+
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",
|
|
@@ -1219,6 +1321,11 @@ var MAX_PDF_BYTES = 25 * 1024 * 1024;
|
|
|
1219
1321
|
var MAX_UPLOAD_BYTES = 100 * 1024 * 1024;
|
|
1220
1322
|
var MAX_DOCUMENTS = 25;
|
|
1221
1323
|
var EMPTY_ATTACHMENTS = [];
|
|
1324
|
+
function previewUploadedPdf(file) {
|
|
1325
|
+
const url = URL.createObjectURL(file);
|
|
1326
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1327
|
+
window.setTimeout(() => URL.revokeObjectURL(url), 6e4);
|
|
1328
|
+
}
|
|
1222
1329
|
function blankLine() {
|
|
1223
1330
|
return { code: "", modifiers: [], units: 1 };
|
|
1224
1331
|
}
|
|
@@ -1313,12 +1420,12 @@ var css = `
|
|
|
1313
1420
|
.mbsf{display:grid;gap:20px;color:var(--mb-text);font-family:var(--mb-font);font-size:15px}.mbsf *{box-sizing:border-box}
|
|
1314
1421
|
.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
1422
|
.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}
|
|
1423
|
+
.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)}
|
|
1424
|
+
.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
1425
|
.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
1426
|
.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
|
-
.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:
|
|
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
|
|
1427
|
+
.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-attach-main{display:flex;align-items:center;gap:12px;min-width:0;flex:1}.mbsf-attach-actions{display:flex;align-items:center;gap:6px;flex:0 0 auto}.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;width:100%;place-items:center;min-height:210px;padding:30px;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));color:var(--mb-text);font:inherit;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}
|
|
1428
|
+
@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-attach-main{align-items:flex-start}.mbsf-attach-actions{margin-left:auto}.mbsf-drop{min-height:190px;padding:24px 18px}.mbsf-actions{position:sticky;bottom:86px;z-index:10}.mbsf-submit{width:100%}}
|
|
1322
1429
|
`;
|
|
1323
1430
|
function RequiredMark() {
|
|
1324
1431
|
return /* @__PURE__ */ jsx3("span", { className: "mbsf-star", children: " *" });
|
|
@@ -1352,24 +1459,26 @@ function TextDateInput({ value, onChange, disabled, required, ariaLabel }) {
|
|
|
1352
1459
|
invalid ? /* @__PURE__ */ jsx3("small", { className: "mbsf-error", children: "Use MM/DD/YYYY" }) : null
|
|
1353
1460
|
] });
|
|
1354
1461
|
}
|
|
1355
|
-
function ComboBox({ value, placeholder, options, disabled, loading, onQuery, onSelect, ariaLabel }) {
|
|
1462
|
+
function ComboBox({ value, placeholder, options, disabled, loading, onQuery, onSelect, createOption, ariaLabel }) {
|
|
1356
1463
|
const [open, setOpen] = useState2(false);
|
|
1357
1464
|
const [query, setQuery] = useState2("");
|
|
1358
1465
|
const visible = useMemo2(() => {
|
|
1359
1466
|
const q = query.trim().toLowerCase();
|
|
1360
|
-
|
|
1361
|
-
|
|
1467
|
+
const matches = q ? options.filter((option) => `${option.id} ${option.label} ${option.detail ?? ""}`.toLowerCase().includes(q)) : options;
|
|
1468
|
+
const custom = createOption?.(query) ?? null;
|
|
1469
|
+
return custom && !matches.some((option) => option.id.toUpperCase() === custom.id.toUpperCase()) ? [...matches, custom] : matches;
|
|
1470
|
+
}, [createOption, options, query]);
|
|
1471
|
+
const showMenu = open && (loading || visible.length > 0 || query.trim().length >= 2);
|
|
1362
1472
|
return /* @__PURE__ */ jsxs3("div", { className: "mbsf-combo", children: [
|
|
1363
|
-
/* @__PURE__ */ jsx3("input", { className: "mbsf-input", role: "combobox", "aria-label": ariaLabel, "aria-expanded":
|
|
1473
|
+
/* @__PURE__ */ jsx3("input", { className: "mbsf-input", role: "combobox", "aria-label": ariaLabel, "aria-expanded": showMenu, autoComplete: "off", disabled, placeholder, value: open ? query : value, onFocus: () => {
|
|
1364
1474
|
setOpen(true);
|
|
1365
1475
|
setQuery("");
|
|
1366
|
-
onQuery?.("");
|
|
1367
1476
|
}, onChange: (event) => {
|
|
1368
1477
|
setOpen(true);
|
|
1369
1478
|
setQuery(event.target.value);
|
|
1370
1479
|
onQuery?.(event.target.value);
|
|
1371
1480
|
}, onBlur: () => setTimeout(() => setOpen(false), 120) }),
|
|
1372
|
-
|
|
1481
|
+
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
1482
|
onSelect(option);
|
|
1374
1483
|
setOpen(false);
|
|
1375
1484
|
setQuery("");
|
|
@@ -1379,6 +1488,11 @@ function ComboBox({ value, placeholder, options, disabled, loading, onQuery, onS
|
|
|
1379
1488
|
] }, option.id)) : /* @__PURE__ */ jsx3("div", { className: "mbsf-option", children: "No matches" }) }) : null
|
|
1380
1489
|
] });
|
|
1381
1490
|
}
|
|
1491
|
+
function customProcedureOption(query) {
|
|
1492
|
+
const code = query.trim().toUpperCase().replace(/\s+/g, "");
|
|
1493
|
+
if (!/^(?:\d{5}|[A-Z]\d{4}|ML(?:20[0-5]|PRR))$/.test(code)) return null;
|
|
1494
|
+
return { id: code, label: code, detail: "Use this CPT, HCPCS, or medical-legal code" };
|
|
1495
|
+
}
|
|
1382
1496
|
function mergeOptions(defaults, supplied) {
|
|
1383
1497
|
const map = new Map(defaults.map((item) => [item.code.toUpperCase(), item]));
|
|
1384
1498
|
supplied?.forEach((item) => map.set(item.code.toUpperCase(), item));
|
|
@@ -1407,7 +1521,8 @@ function BillSubmissionForm({
|
|
|
1407
1521
|
description = "Review the bill details, add attachments, and submit."
|
|
1408
1522
|
}) {
|
|
1409
1523
|
const [bill, setBill] = useState2(() => cloneBill(initialBill));
|
|
1410
|
-
const [selectedIds, setSelectedIds] = useState2(() => attachments.
|
|
1524
|
+
const [selectedIds, setSelectedIds] = useState2(() => attachments.map((item) => item.id));
|
|
1525
|
+
const [removedSourceIds, setRemovedSourceIds] = useState2([]);
|
|
1411
1526
|
const [uploads, setUploads] = useState2([]);
|
|
1412
1527
|
const [errors, setErrors] = useState2({});
|
|
1413
1528
|
const [formError, setFormError] = useState2(null);
|
|
@@ -1419,14 +1534,15 @@ function BillSubmissionForm({
|
|
|
1419
1534
|
const [postalStatus, setPostalStatus] = useState2(null);
|
|
1420
1535
|
const [dragActive, setDragActive] = useState2(false);
|
|
1421
1536
|
const fileInput = useRef2(null);
|
|
1422
|
-
const procedures = useMemo2(() => mergeOptions(
|
|
1423
|
-
const modifiers = useMemo2(() => mergeOptions(
|
|
1537
|
+
const procedures = useMemo2(() => mergeOptions(DEFAULT_BILL_SUBMISSION_PROCEDURES, procedureOptions), [procedureOptions]);
|
|
1538
|
+
const modifiers = useMemo2(() => mergeOptions(DEFAULT_BILL_SUBMISSION_MODIFIERS, modifierOptions), [modifierOptions]);
|
|
1424
1539
|
const [evaluationType, setEvaluationType] = useState2(() => initialBill.renderingProvider?.isAme ? "ame" : initialBill.renderingProvider?.specialty?.toLowerCase().includes("psych") ? "psych_qme" : "qme");
|
|
1425
1540
|
const referenceClient = useMemo2(() => getSession ? createBillReferenceClient({ getSession, sessionEndpoint, apiBaseUrl, fetch: fetchOverride }) : null, [getSession, sessionEndpoint, apiBaseUrl, fetchOverride]);
|
|
1426
1541
|
const locked = disabled || submitting;
|
|
1427
1542
|
useEffect2(() => {
|
|
1428
1543
|
setBill(cloneBill(initialBill));
|
|
1429
|
-
setSelectedIds(attachments.
|
|
1544
|
+
setSelectedIds(attachments.map((item) => item.id));
|
|
1545
|
+
setRemovedSourceIds([]);
|
|
1430
1546
|
setUploads([]);
|
|
1431
1547
|
setErrors({});
|
|
1432
1548
|
setFormError(null);
|
|
@@ -1471,7 +1587,18 @@ function BillSubmissionForm({
|
|
|
1471
1587
|
};
|
|
1472
1588
|
}, [addFiles]);
|
|
1473
1589
|
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) =>
|
|
1590
|
+
const setLine = (index, patch) => setBill((current) => ({ ...current, serviceLines: ensureTrailingBillSubmissionLine(current.serviceLines.map((line, lineIndex) => {
|
|
1591
|
+
if (lineIndex !== index) return line;
|
|
1592
|
+
const next = { ...line, ...patch };
|
|
1593
|
+
const charge = calculateBillSubmissionAllowedAmount(next, procedures);
|
|
1594
|
+
if (charge != null) return { ...next, charge };
|
|
1595
|
+
if (Object.hasOwn(patch, "code")) {
|
|
1596
|
+
const withoutCharge = { ...next };
|
|
1597
|
+
delete withoutCharge.charge;
|
|
1598
|
+
return withoutCharge;
|
|
1599
|
+
}
|
|
1600
|
+
return next;
|
|
1601
|
+
})) }));
|
|
1475
1602
|
const text = (value, onChange, options = {}) => /* @__PURE__ */ jsx3("input", { className: "mbsf-input", disabled: locked, value: value ?? "", onChange: (event) => onChange(event.target.value), ...options });
|
|
1476
1603
|
const searchPayers = (query) => {
|
|
1477
1604
|
if (query.trim().length < 2) return;
|
|
@@ -1484,15 +1611,23 @@ function BillSubmissionForm({
|
|
|
1484
1611
|
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
1612
|
};
|
|
1486
1613
|
const searchDiagnoses = (query) => {
|
|
1487
|
-
|
|
1614
|
+
const trimmed = query.trim();
|
|
1615
|
+
if (!trimmed) {
|
|
1616
|
+
setDiagnosisResults(diagnosisOptions);
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
const search = onSearchDiagnoses ?? referenceClient?.searchDiagnosisCodes;
|
|
1620
|
+
if (!search) return;
|
|
1488
1621
|
setDiagnosisLoading(true);
|
|
1489
|
-
void
|
|
1622
|
+
void search(trimmed).then(setDiagnosisResults).catch(() => setDiagnosisResults([])).finally(() => setDiagnosisLoading(false));
|
|
1490
1623
|
};
|
|
1491
1624
|
const updatePostalCode = (postalCode) => {
|
|
1492
1625
|
setAddress({ postalCode });
|
|
1493
1626
|
setPostalStatus(null);
|
|
1494
|
-
|
|
1495
|
-
|
|
1627
|
+
const lookup = onLookupPostalCode ?? referenceClient?.lookupPostalCode;
|
|
1628
|
+
if (!lookup || !/^\d{5}$/.test(postalCode)) return;
|
|
1629
|
+
setPostalStatus("Looking up ZIP\u2026");
|
|
1630
|
+
void lookup(postalCode).then((place) => {
|
|
1496
1631
|
if (!place) return setPostalStatus("ZIP not found");
|
|
1497
1632
|
setAddress({ city: place.city, state: place.state.toUpperCase() });
|
|
1498
1633
|
setPostalStatus(`${place.city}, ${place.state.toUpperCase()} filled from ZIP`);
|
|
@@ -1502,9 +1637,13 @@ function BillSubmissionForm({
|
|
|
1502
1637
|
setEvaluationType(type);
|
|
1503
1638
|
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
1639
|
};
|
|
1505
|
-
const
|
|
1640
|
+
const lineCharge = (line) => calculateBillSubmissionAllowedAmount(line, procedures) ?? (Number.isFinite(line.charge) ? Number(line.charge) : void 0);
|
|
1641
|
+
const total = submittedLines(bill.serviceLines).reduce((sum, line) => sum + (lineCharge(line) ?? 0), 0);
|
|
1506
1642
|
async function submit() {
|
|
1507
|
-
const clean = { ...cloneBill(bill), serviceLines: submittedLines(bill.serviceLines)
|
|
1643
|
+
const clean = { ...cloneBill(bill), serviceLines: submittedLines(bill.serviceLines).map((line) => {
|
|
1644
|
+
const charge = lineCharge(line);
|
|
1645
|
+
return charge == null ? line : { ...line, charge };
|
|
1646
|
+
}) };
|
|
1508
1647
|
const validation = validateBillSubmission(clean);
|
|
1509
1648
|
setErrors(validation.fieldErrors);
|
|
1510
1649
|
setFormError(null);
|
|
@@ -1562,15 +1701,23 @@ function BillSubmissionForm({
|
|
|
1562
1701
|
/* @__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
1702
|
/* @__PURE__ */ jsx3(Field2, { label: "Injury description (optional)", span: true, children: text(bill.claim.description, (description2) => setBill((c) => ({ ...c, claim: { ...c.claim, description: description2 } }))) }),
|
|
1564
1703
|
/* @__PURE__ */ jsxs3(Field2, { label: "Diagnosis codes (ICD-10)", span: true, children: [
|
|
1704
|
+
/* @__PURE__ */ jsx3("div", { className: "mbsf-quick-picks", "aria-label": "Common diagnosis codes", children: BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS.map((option) => {
|
|
1705
|
+
const selected = (bill.diagnoses ?? []).includes(option.code);
|
|
1706
|
+
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: [
|
|
1707
|
+
selected ? "\u2713" : "+",
|
|
1708
|
+
" ",
|
|
1709
|
+
option.label
|
|
1710
|
+
] }, option.code);
|
|
1711
|
+
}) }),
|
|
1565
1712
|
/* @__PURE__ */ jsx3("div", { className: "mbsf-chips", children: (bill.diagnoses ?? []).map((code) => {
|
|
1566
|
-
const option = [...diagnosisOptions, ...diagnosisResults].find((item) => item.code === code);
|
|
1713
|
+
const option = [...BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS, ...diagnosisOptions, ...diagnosisResults].find((item) => item.code === code);
|
|
1567
1714
|
return /* @__PURE__ */ jsxs3("span", { className: "mbsf-chip", children: [
|
|
1568
1715
|
/* @__PURE__ */ jsx3("strong", { children: code }),
|
|
1569
1716
|
option?.description ? ` ${option.description}` : "",
|
|
1570
1717
|
/* @__PURE__ */ jsx3("button", { type: "button", "aria-label": `Remove ${code}`, onClick: () => setBill((c) => ({ ...c, diagnoses: (c.diagnoses ?? []).filter((item) => item !== code) })), children: "\xD7" })
|
|
1571
1718
|
] }, code);
|
|
1572
1719
|
}) }),
|
|
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])] })) })
|
|
1720
|
+
/* @__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
1721
|
] })
|
|
1575
1722
|
] })
|
|
1576
1723
|
] }),
|
|
@@ -1605,16 +1752,15 @@ function BillSubmissionForm({
|
|
|
1605
1752
|
" "
|
|
1606
1753
|
] }),
|
|
1607
1754
|
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);
|
|
1755
|
+
/* @__PURE__ */ jsxs3("div", { "data-label": "Procedure code", children: [
|
|
1756
|
+
/* @__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
1757
|
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 } : {}
|
|
1758
|
+
setLine(index, { code: option.id, ...auto ? { modifiers: [auto, ...(line.modifiers ?? []).filter((item) => !["94", "95", "96"].includes(item.replace(/^-/, "")))] } : line.modifiers ? { modifiers: line.modifiers } : {} });
|
|
1613
1759
|
} }),
|
|
1614
|
-
line.code ? /* @__PURE__ */ jsx3("small", { className: "mbsf-help", children: procedures.find((item) => item.code === line.code)?.description }) : null,
|
|
1760
|
+
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
1761
|
errors[`serviceLines.${index}.code`] ? /* @__PURE__ */ jsx3("small", { className: "mbsf-error", children: errors[`serviceLines.${index}.code`] }) : null
|
|
1616
1762
|
] }),
|
|
1617
|
-
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1763
|
+
/* @__PURE__ */ jsxs3("div", { "data-label": "Modifiers", children: [
|
|
1618
1764
|
/* @__PURE__ */ jsx3("div", { className: "mbsf-chips", children: (line.modifiers ?? []).map((modifier) => /* @__PURE__ */ jsxs3("span", { className: "mbsf-chip", children: [
|
|
1619
1765
|
"\u2212",
|
|
1620
1766
|
modifier.replace(/^-/, ""),
|
|
@@ -1622,15 +1768,11 @@ function BillSubmissionForm({
|
|
|
1622
1768
|
] }, modifier)) }),
|
|
1623
1769
|
/* @__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
1770
|
] }),
|
|
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
|
-
} }),
|
|
1771
|
+
/* @__PURE__ */ jsxs3("div", { "data-label": "Units", children: [
|
|
1772
|
+
/* @__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
1773
|
errors[`serviceLines.${index}.units`] ? /* @__PURE__ */ jsx3("small", { className: "mbsf-error", children: errors[`serviceLines.${index}.units`] }) : null
|
|
1632
1774
|
] }),
|
|
1633
|
-
/* @__PURE__ */ jsx3("div", { className: "mbsf-money", children: line
|
|
1775
|
+
/* @__PURE__ */ jsx3("div", { className: "mbsf-money", "data-label": "Allowed", children: lineCharge(line) == null ? "\u2014" : lineCharge(line).toLocaleString(void 0, { style: "currency", currency: "USD" }) }),
|
|
1634
1776
|
/* @__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
1777
|
] }, index)),
|
|
1636
1778
|
/* @__PURE__ */ jsxs3("div", { className: "mbsf-total", children: [
|
|
@@ -1643,31 +1785,39 @@ function BillSubmissionForm({
|
|
|
1643
1785
|
/* @__PURE__ */ jsxs3("fieldset", { className: "mbsf-card", disabled: locked, children: [
|
|
1644
1786
|
/* @__PURE__ */ jsx3("legend", { className: "mbsf-legend", children: "Attachments" }),
|
|
1645
1787
|
/* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-list", children: [
|
|
1646
|
-
attachments.map((attachment) => {
|
|
1647
|
-
const auto = attachment.autoAttached
|
|
1648
|
-
const
|
|
1788
|
+
attachments.filter((attachment) => !removedSourceIds.includes(attachment.id)).map((attachment) => {
|
|
1789
|
+
const auto = attachment.autoAttached || attachment.documentType === "w9";
|
|
1790
|
+
const removable = !auto && attachment.removable !== false;
|
|
1649
1791
|
return /* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-row", "data-auto": auto, children: [
|
|
1650
|
-
/* @__PURE__ */ jsxs3("
|
|
1651
|
-
/* @__PURE__ */ jsx3("
|
|
1792
|
+
/* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-main", children: [
|
|
1793
|
+
auto ? /* @__PURE__ */ jsx3("span", { "aria-label": "Always attached", role: "img", children: "\u2713" }) : null,
|
|
1652
1794
|
/* @__PURE__ */ jsxs3("span", { className: "mbsf-file", children: [
|
|
1653
1795
|
/* @__PURE__ */ jsx3("strong", { children: attachment.fileName }),
|
|
1654
1796
|
/* @__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
|
|
1797
|
+
/* @__PURE__ */ jsx3("span", { className: "mbsf-help", style: { display: "block" }, children: attachment.description || (auto ? "Included automatically with every bill." : documentLabels[attachment.documentType]) })
|
|
1656
1798
|
] })
|
|
1657
1799
|
] }),
|
|
1658
|
-
|
|
1800
|
+
/* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-actions", children: [
|
|
1801
|
+
attachment.previewUrl ? /* @__PURE__ */ jsx3("a", { className: "mbsf-secondary", href: attachment.previewUrl, target: "_blank", rel: "noopener noreferrer", children: "Preview" }) : null,
|
|
1802
|
+
removable ? /* @__PURE__ */ jsx3("button", { className: "mbsf-icon-btn", type: "button", "aria-label": `Remove ${attachment.fileName}`, disabled: locked, onClick: () => {
|
|
1803
|
+
setSelectedIds((current) => current.filter((id) => id !== attachment.id));
|
|
1804
|
+
setRemovedSourceIds((current) => [.../* @__PURE__ */ new Set([...current, attachment.id])]);
|
|
1805
|
+
}, children: "\xD7" }) : null
|
|
1806
|
+
] })
|
|
1659
1807
|
] }, attachment.id);
|
|
1660
1808
|
}),
|
|
1661
1809
|
uploads.map((upload, index) => /* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-row", children: [
|
|
1662
|
-
/* @__PURE__ */ jsxs3("span", { className: "mbsf-file", children: [
|
|
1810
|
+
/* @__PURE__ */ jsx3("div", { className: "mbsf-attach-main", children: /* @__PURE__ */ jsxs3("span", { className: "mbsf-file", children: [
|
|
1663
1811
|
/* @__PURE__ */ jsx3("strong", { children: upload.file.name }),
|
|
1664
1812
|
/* @__PURE__ */ jsxs3("span", { className: "mbsf-help", style: { display: "block" }, children: [
|
|
1665
1813
|
(upload.file.size / 1024 / 1024).toFixed(1),
|
|
1666
1814
|
" MB"
|
|
1667
1815
|
] })
|
|
1668
|
-
] }),
|
|
1669
|
-
/* @__PURE__ */
|
|
1670
|
-
|
|
1816
|
+
] }) }),
|
|
1817
|
+
/* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-actions", children: [
|
|
1818
|
+
/* @__PURE__ */ jsx3("button", { className: "mbsf-secondary", type: "button", onClick: () => previewUploadedPdf(upload.file), children: "Preview" }),
|
|
1819
|
+
/* @__PURE__ */ jsx3("button", { className: "mbsf-icon-btn", type: "button", "aria-label": `Remove ${upload.file.name}`, onClick: () => setUploads((current) => current.filter((_, itemIndex) => itemIndex !== index)), children: "\xD7" })
|
|
1820
|
+
] })
|
|
1671
1821
|
] }, `${upload.file.name}-${index}`))
|
|
1672
1822
|
] }),
|
|
1673
1823
|
/* @__PURE__ */ jsx3("input", { ref: fileInput, hidden: true, type: "file", accept: "application/pdf,.pdf", multiple: true, onChange: (event) => {
|
|
@@ -2581,6 +2731,7 @@ function MindBillBillReview(props) {
|
|
|
2581
2731
|
return widget("mindbill-bill-review", props);
|
|
2582
2732
|
}
|
|
2583
2733
|
export {
|
|
2734
|
+
BILL_SUBMISSION_DIAGNOSIS_QUICK_PICKS,
|
|
2584
2735
|
BILL_SUBMISSION_DOCUMENT_TYPES,
|
|
2585
2736
|
BILL_SUBMISSION_REQUIRED_FIELDS,
|
|
2586
2737
|
BillActivityTimeline,
|
|
@@ -2596,12 +2747,15 @@ export {
|
|
|
2596
2747
|
BillSubmissionForm,
|
|
2597
2748
|
ConnectedBillLifecycle,
|
|
2598
2749
|
ConnectedBillStatus,
|
|
2750
|
+
DEFAULT_BILL_SUBMISSION_MODIFIERS,
|
|
2751
|
+
DEFAULT_BILL_SUBMISSION_PROCEDURES,
|
|
2599
2752
|
MindBillBillReview,
|
|
2600
2753
|
MindBillBillTimeline,
|
|
2601
2754
|
applyBillSubmissionEvaluationModifiers,
|
|
2602
2755
|
billActivityEventLabel,
|
|
2603
2756
|
billLifecycleStage,
|
|
2604
2757
|
buildBillReviewSaveInput,
|
|
2758
|
+
calculateBillSubmissionAllowedAmount,
|
|
2605
2759
|
createBillLifecycleClient2 as createBillLifecycleClient,
|
|
2606
2760
|
createBillStatusClient,
|
|
2607
2761
|
ensureTrailingBillSubmissionLine,
|