@mindbill/react 0.9.2 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  // src/index.tsx
4
4
  import "@mindbill/embed";
5
- import { createElement, useEffect as useEffect4, useRef as useRef3 } from "react";
5
+ import { createElement, useEffect as useEffect4, useRef as useRef4 } from "react";
6
6
 
7
7
  // src/native-bill-review.tsx
8
- import { useEffect, useId, useMemo, useState } from "react";
8
+ import { useEffect, useId, useMemo, useRef, useState } from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  var EMPTY_BILLING_PROVIDER = {
11
11
  name: "",
@@ -37,6 +37,35 @@ var DOCUMENT_LABELS = {
37
37
  appeal: "Appeal or review support",
38
38
  other: "Other supporting document"
39
39
  };
40
+ var US_STATES = ["AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY", "DC"];
41
+ var PROCEDURES = [
42
+ ["ML200", "Missed med-legal appointment"],
43
+ ["ML201", "Comprehensive med-legal evaluation"],
44
+ ["ML202", "Follow-up med-legal evaluation"],
45
+ ["ML203", "Supplemental med-legal evaluation"],
46
+ ["ML204", "Medical-legal testimony"],
47
+ ["ML205", "Sub rosa recording review"],
48
+ ["MLPRR", "Medical record review"]
49
+ ];
50
+ var MODIFIERS = [
51
+ ["92", "Primary treating physician"],
52
+ ["93", "Interpreter required"],
53
+ ["94", "Agreed medical evaluator (AME)"],
54
+ ["95", "Qualified medical evaluator (QME)"],
55
+ ["96", "Psychiatric or psychological evaluation"],
56
+ ["97", "Toxicology evaluation"],
57
+ ["98", "Oncology evaluation"]
58
+ ];
59
+ var MANAGED_EVALUATOR_MODIFIERS = /* @__PURE__ */ new Set(["94", "95", "96"]);
60
+ var MODIFIER_CODES = {
61
+ "92": ["ML201", "ML202", "ML203"],
62
+ "93": ["ML201", "ML202"],
63
+ "94": ["ML201", "ML202", "ML203"],
64
+ "95": ["ML200", "ML201", "ML202", "ML203", "MLPRR"],
65
+ "96": ["ML201", "ML202", "ML203"],
66
+ "97": ["ML201", "ML202", "ML203"],
67
+ "98": ["ML201", "ML202", "ML203"]
68
+ };
40
69
  function withoutId(value) {
41
70
  const result = { ...value };
42
71
  delete result.id;
@@ -44,9 +73,20 @@ function withoutId(value) {
44
73
  }
45
74
  function toDraft(data) {
46
75
  const snapshot = data.bill.billingSnapshot;
76
+ const nameParts = data.patient.name.trim().split(/\s+/);
47
77
  return {
48
78
  claimsAdminId: data.injury.claimsAdminId || "",
49
79
  claimsAdminName: data.injury.claimsAdminName || "",
80
+ patientFirstName: data.patient.firstName || nameParts[0] || "",
81
+ patientMiddleName: data.patient.middleName || (nameParts.length > 2 ? nameParts.slice(1, -1).join(" ") : ""),
82
+ patientLastName: data.patient.lastName || (nameParts.length > 1 ? nameParts.at(-1) || "" : ""),
83
+ patientDob: data.patient.dob || "",
84
+ claimNumber: data.injury.claimNumber || "",
85
+ employer: data.injury.employer || "",
86
+ doi: data.injury.doi || "",
87
+ injuryEndDate: data.injury.injuryEndDate || "",
88
+ cumulativeTrauma: Boolean(data.injury.cumulativeTrauma),
89
+ adjNumber: data.injury.adjNumber || "",
50
90
  dos: data.bill.dos || "",
51
91
  dosEnd: data.bill.dosEnd || "",
52
92
  authorizationNumber: data.bill.authorizationNumber || "",
@@ -62,6 +102,20 @@ function toDraft(data) {
62
102
  function buildBillReviewSaveInput(draft) {
63
103
  return {
64
104
  claimsAdminId: draft.claimsAdminId,
105
+ patientOverrides: {
106
+ firstName: draft.patientFirstName.trim(),
107
+ ...draft.patientMiddleName.trim() ? { middleName: draft.patientMiddleName.trim() } : {},
108
+ lastName: draft.patientLastName.trim(),
109
+ ...draft.patientDob ? { dob: draft.patientDob } : {}
110
+ },
111
+ injuryOverrides: {
112
+ ...draft.claimNumber.trim() ? { claimNumber: draft.claimNumber.trim() } : {},
113
+ ...draft.employer.trim() ? { employer: draft.employer.trim() } : {},
114
+ ...draft.doi ? { doi: draft.doi } : {},
115
+ ...draft.injuryEndDate ? { injuryEndDate: draft.injuryEndDate } : {},
116
+ cumulativeTrauma: draft.cumulativeTrauma,
117
+ ...draft.adjNumber.trim() ? { adjNumber: draft.adjNumber.trim().toUpperCase().replace(/\s+/g, "") } : {}
118
+ },
65
119
  dos: draft.dos,
66
120
  dosEnd: draft.dosEnd || null,
67
121
  authorizationNumber: draft.authorizationNumber.trim() || null,
@@ -71,7 +125,7 @@ function buildBillReviewSaveInput(draft) {
71
125
  renderingProvider: withoutId(draft.clinician),
72
126
  ...draft.location.id ? { placeOfServiceId: draft.location.id } : {},
73
127
  placeOfService: withoutId(draft.location),
74
- lineItems: draft.lineItems.map(({ id, code, modifiers, units }) => ({
128
+ lineItems: draft.lineItems.filter((line) => line.code.trim()).map(({ id, code, modifiers, units }) => ({
75
129
  ...id ? { id } : {},
76
130
  code: code.trim().toUpperCase(),
77
131
  modifiers,
@@ -103,7 +157,9 @@ function Field({
103
157
  onChange,
104
158
  type = "text",
105
159
  optional,
106
- required
160
+ required,
161
+ disabled,
162
+ hint
107
163
  }) {
108
164
  return /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
109
165
  /* @__PURE__ */ jsxs("span", { children: [
@@ -117,11 +173,128 @@ function Field({
117
173
  type,
118
174
  value,
119
175
  required,
176
+ disabled,
177
+ autoComplete: "off",
120
178
  onChange: (event) => onChange(event.target.value)
121
179
  }
122
- )
180
+ ),
181
+ hint ? /* @__PURE__ */ jsx("small", { className: "mb-native-hint", children: hint }) : null
182
+ ] });
183
+ }
184
+ function Combobox({ label, value, options, onChange, placeholder, required, disabled, name }) {
185
+ const listId = useId();
186
+ const root = useRef(null);
187
+ const [open, setOpen] = useState(false);
188
+ const [active, setActive] = useState(0);
189
+ const filtered = useMemo(() => {
190
+ const query = value.trim().toLowerCase();
191
+ return options.filter((option) => !query || option.label.toLowerCase().includes(query) || option.value.toLowerCase().includes(query)).slice(0, 40);
192
+ }, [options, value]);
193
+ useEffect(() => {
194
+ const close = (event) => {
195
+ if (!root.current?.contains(event.target)) setOpen(false);
196
+ };
197
+ document.addEventListener("mousedown", close);
198
+ return () => document.removeEventListener("mousedown", close);
199
+ }, []);
200
+ const select = (option) => {
201
+ onChange(option.value, option);
202
+ setOpen(false);
203
+ setActive(0);
204
+ };
205
+ const keyDown = (event) => {
206
+ if (event.key === "ArrowDown") {
207
+ event.preventDefault();
208
+ setOpen(true);
209
+ setActive((value2) => Math.min(value2 + 1, filtered.length - 1));
210
+ }
211
+ if (event.key === "ArrowUp") {
212
+ event.preventDefault();
213
+ setActive((value2) => Math.max(value2 - 1, 0));
214
+ }
215
+ if (event.key === "Enter" && open && filtered[active]) {
216
+ event.preventDefault();
217
+ select(filtered[active]);
218
+ }
219
+ if (event.key === "Escape") setOpen(false);
220
+ };
221
+ return /* @__PURE__ */ jsxs("div", { className: "mb-native-combo", ref: root, children: [
222
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
223
+ /* @__PURE__ */ jsx("span", { children: label }),
224
+ /* @__PURE__ */ jsx(
225
+ "input",
226
+ {
227
+ role: "combobox",
228
+ "aria-autocomplete": "list",
229
+ "aria-controls": listId,
230
+ "aria-expanded": open && filtered.length > 0,
231
+ "aria-activedescendant": open && filtered[active] ? `${listId}-${active}` : void 0,
232
+ name: name || "mindbill-search-value",
233
+ autoComplete: "new-password",
234
+ "data-1p-ignore": "true",
235
+ "data-lpignore": "true",
236
+ value,
237
+ placeholder,
238
+ required,
239
+ disabled,
240
+ onFocus: () => setOpen(true),
241
+ onKeyDown: keyDown,
242
+ onChange: (event) => {
243
+ onChange(event.target.value);
244
+ setOpen(true);
245
+ setActive(0);
246
+ }
247
+ }
248
+ )
249
+ ] }),
250
+ open && filtered.length ? /* @__PURE__ */ jsx("ul", { id: listId, role: "listbox", className: "mb-native-combo-list", children: filtered.map((option, index) => /* @__PURE__ */ jsx("li", { id: `${listId}-${index}`, role: "option", "aria-selected": index === active, children: /* @__PURE__ */ jsxs("button", { type: "button", className: index === active ? "active" : "", onMouseDown: (event) => event.preventDefault(), onClick: () => select(option), children: [
251
+ /* @__PURE__ */ jsx("strong", { children: option.label }),
252
+ option.detail ? /* @__PURE__ */ jsx("span", { children: option.detail }) : null
253
+ ] }) }, `${option.value}-${index}`)) }) : null
123
254
  ] });
124
255
  }
256
+ function StateCombobox({ label, value, onChange, required, disabled }) {
257
+ return /* @__PURE__ */ jsx(
258
+ Combobox,
259
+ {
260
+ label,
261
+ value,
262
+ onChange: (next) => onChange(next.toUpperCase().slice(0, 2)),
263
+ options: US_STATES.map((state) => ({ value: state, label: state })),
264
+ ...required === void 0 ? {} : { required },
265
+ ...disabled === void 0 ? {} : { disabled },
266
+ name: "mindbill-state-value"
267
+ }
268
+ );
269
+ }
270
+ function inferPreset(lines) {
271
+ const modifiers = new Set(lines.flatMap((line) => line.modifiers));
272
+ return modifiers.has("94") ? "ame" : modifiers.has("96") ? "psych_qme" : "qme";
273
+ }
274
+ function presetModifiersForCode(preset, code) {
275
+ if (code === "MLPRR") return ["95"];
276
+ if (preset === "qme" && ["ML200", "ML201", "ML202", "ML203"].includes(code)) return ["95"];
277
+ if (preset === "ame" && ["ML201", "ML202", "ML203"].includes(code)) return ["94"];
278
+ if (preset === "psych_qme") {
279
+ if (code === "ML200") return ["95"];
280
+ if (["ML201", "ML202", "ML203"].includes(code)) return ["96"];
281
+ }
282
+ return [];
283
+ }
284
+ function modifierAppliesToCode(modifier, code) {
285
+ return !code || (MODIFIER_CODES[modifier]?.includes(code) ?? true);
286
+ }
287
+ function applyPreset(lines, preset) {
288
+ return lines.map((line) => {
289
+ const preserved = line.modifiers.filter(
290
+ (value) => !MANAGED_EVALUATOR_MODIFIERS.has(value) && modifierAppliesToCode(value, line.code)
291
+ );
292
+ return {
293
+ ...line,
294
+ modifiers: [.../* @__PURE__ */ new Set([...presetModifiersForCode(preset, line.code), ...preserved])]
295
+ };
296
+ });
297
+ }
125
298
  function BillReviewForm({
126
299
  data,
127
300
  onSave,
@@ -149,7 +322,6 @@ function BillReviewForm({
149
322
  const [error, setError] = useState("");
150
323
  const [notice, setNotice] = useState("");
151
324
  const routeName = useId();
152
- const payerListId = useId();
153
325
  const editable = data.bill.status === "incomplete" && !disabled;
154
326
  useEffect(() => {
155
327
  setDraft(toDraft(data));
@@ -182,12 +354,25 @@ function BillReviewForm({
182
354
  window.clearTimeout(timer);
183
355
  };
184
356
  }, [onSearchClaimsAdministrators, payerQuery]);
185
- const canSubmit = useMemo(
186
- () => Boolean(
187
- draft.dos && draft.claimsAdminId && draft.billingProvider.name.trim() && draft.billingProvider.taxId.trim() && draft.billingProvider.npi.trim() && draft.clinician.name.trim() && draft.clinician.npi.trim() && draft.location.name.trim() && draft.location.street.trim() && draft.location.city.trim() && draft.location.state.trim() && draft.location.zip.trim() && draft.lineItems.length && draft.lineItems.every((line) => line.code.trim() && line.units > 0)
188
- ),
189
- [draft]
190
- );
357
+ const adjFormatValid = !draft.adjNumber || /^ADJ\d{7,}$/i.test(draft.adjNumber.replace(/[\s-]/g, ""));
358
+ const blockers = useMemo(() => {
359
+ const result = [];
360
+ if (!draft.patientFirstName.trim() || !draft.patientLastName.trim()) result.push("Patient name");
361
+ if (!draft.claimsAdminId) result.push("Claims administrator");
362
+ if (!draft.claimNumber.trim()) result.push("Claim number");
363
+ if (!draft.doi) result.push("Date of injury");
364
+ if (!adjFormatValid) result.push("Valid WCAB / ADJ number");
365
+ if (!draft.dos) result.push("Date of service");
366
+ if (!draft.billingProvider.name.trim()) result.push("Practice name");
367
+ if (!draft.billingProvider.taxId.trim()) result.push("Tax ID");
368
+ if (!draft.billingProvider.npi.trim()) result.push("Billing NPI");
369
+ if (!draft.clinician.name.trim() || !draft.clinician.npi.trim()) result.push("Clinician and NPI");
370
+ if (![draft.location.name, draft.location.street, draft.location.city, draft.location.state, draft.location.zip].every((value) => value.trim())) result.push("Service location");
371
+ const completedLines = draft.lineItems.filter((line) => line.code.trim());
372
+ if (!completedLines.length || completedLines.some((line) => line.units <= 0)) result.push("Valid procedure line");
373
+ return result;
374
+ }, [adjFormatValid, draft]);
375
+ const canSubmit = blockers.length === 0;
191
376
  const updateBillingProvider = (key, value) => setDraft((current) => ({
192
377
  ...current,
193
378
  billingProvider: { ...current.billingProvider, [key]: value }
@@ -264,19 +449,19 @@ function BillReviewForm({
264
449
  /* @__PURE__ */ jsxs("dl", { className: "mb-native-summary", children: [
265
450
  /* @__PURE__ */ jsxs("div", { children: [
266
451
  /* @__PURE__ */ jsx("dt", { children: "Patient" }),
267
- /* @__PURE__ */ jsx("dd", { children: data.patient.name || "\u2014" })
452
+ /* @__PURE__ */ jsx("dd", { children: [draft.patientFirstName, draft.patientMiddleName, draft.patientLastName].filter(Boolean).join(" ") || "\u2014" })
268
453
  ] }),
269
454
  /* @__PURE__ */ jsxs("div", { children: [
270
455
  /* @__PURE__ */ jsx("dt", { children: "Claim" }),
271
- /* @__PURE__ */ jsx("dd", { children: data.injury.claimNumber || "\u2014" })
456
+ /* @__PURE__ */ jsx("dd", { children: draft.claimNumber || "\u2014" })
272
457
  ] }),
273
458
  /* @__PURE__ */ jsxs("div", { children: [
274
459
  /* @__PURE__ */ jsx("dt", { children: "Employer" }),
275
- /* @__PURE__ */ jsx("dd", { children: data.injury.employer || "\u2014" })
460
+ /* @__PURE__ */ jsx("dd", { children: draft.employer || "\u2014" })
276
461
  ] }),
277
462
  /* @__PURE__ */ jsxs("div", { children: [
278
463
  /* @__PURE__ */ jsx("dt", { children: "Date of injury" }),
279
- /* @__PURE__ */ jsx("dd", { children: data.injury.doi || "\u2014" })
464
+ /* @__PURE__ */ jsx("dd", { children: draft.doi || "\u2014" })
280
465
  ] })
281
466
  ] }),
282
467
  /* @__PURE__ */ jsxs("section", { className: sectionClass, children: [
@@ -288,61 +473,66 @@ function BillReviewForm({
288
473
  draft.claimsAdminId ? /* @__PURE__ */ jsx("span", { children: "Selected" }) : /* @__PURE__ */ jsx("span", { children: "Required" })
289
474
  ] }),
290
475
  /* @__PURE__ */ jsxs("div", { className: "mb-native-payer-picker", children: [
291
- /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
292
- /* @__PURE__ */ jsx("span", { children: "Insurance company or claims administrator" }),
293
- /* @__PURE__ */ jsx(
294
- "input",
295
- {
296
- role: "combobox",
297
- "aria-autocomplete": "list",
298
- "aria-controls": payerListId,
299
- "aria-expanded": payerResults.length > 0,
300
- value: payerQuery,
301
- disabled: !editable,
302
- placeholder: "Search by payer or administrator name",
303
- onChange: (event) => {
304
- const value = event.target.value;
476
+ /* @__PURE__ */ jsx(
477
+ Combobox,
478
+ {
479
+ label: "Insurance company or claims administrator",
480
+ value: payerQuery,
481
+ disabled: !editable,
482
+ placeholder: "Search by payer or administrator name",
483
+ name: "mindbill-payer-query",
484
+ options: payerResults.map((payer) => ({ value: payer.id, label: payer.name, detail: payer.hasElectronic ? "Electronic billing available" : "Billing route confirmed after review" })),
485
+ onChange: (value, option) => {
486
+ if (option) {
487
+ setDraft((current) => ({ ...current, claimsAdminId: option.value, claimsAdminName: option.label }));
488
+ setPayerQuery(option.label);
489
+ setPayerResults([]);
490
+ setNotice("Claims administrator selected. Save changes to keep it on this bill.");
491
+ } else {
305
492
  setPayerQuery(value);
306
- setDraft((current) => ({
307
- ...current,
308
- ...value === current.claimsAdminName ? {} : { claimsAdminId: "", claimsAdminName: "" }
309
- }));
493
+ setDraft((current) => value === current.claimsAdminName ? current : { ...current, claimsAdminId: "", claimsAdminName: "" });
310
494
  }
311
495
  }
312
- )
313
- ] }),
314
- payerBusy ? /* @__PURE__ */ jsx("span", { className: "mb-native-payer-help", children: "Searching\u2026" }) : null,
315
- !payerBusy && payerQuery.trim().length > 1 && payerResults.length === 0 && !draft.claimsAdminId ? /* @__PURE__ */ jsx("span", { className: "mb-native-payer-help", children: "No matching administrator selected yet." }) : null,
316
- payerResults.length > 0 ? /* @__PURE__ */ jsx("ul", { id: payerListId, className: "mb-native-payer-results", role: "listbox", children: payerResults.map((payer) => /* @__PURE__ */ jsx("li", { role: "option", "aria-selected": payer.id === draft.claimsAdminId, children: /* @__PURE__ */ jsxs(
317
- "button",
318
- {
319
- type: "button",
320
- onClick: () => {
321
- setDraft((current) => ({
322
- ...current,
323
- claimsAdminId: payer.id,
324
- claimsAdminName: payer.name
325
- }));
326
- setPayerQuery(payer.name);
327
- setPayerResults([]);
328
- },
329
- children: [
330
- /* @__PURE__ */ jsx("strong", { children: payer.name }),
331
- /* @__PURE__ */ jsx("span", { children: payer.hasElectronic ? "Electronic billing available" : "Billing route confirmed after review" })
332
- ]
333
496
  }
334
- ) }, payer.id)) }) : null
497
+ ),
498
+ payerBusy ? /* @__PURE__ */ jsx("span", { className: "mb-native-payer-help", children: "Searching\u2026" }) : null,
499
+ !payerBusy && payerQuery.trim().length > 1 && payerResults.length === 0 && !draft.claimsAdminId ? /* @__PURE__ */ jsx("span", { className: "mb-native-payer-help", children: "No matching administrator selected yet." }) : null
500
+ ] })
501
+ ] }),
502
+ /* @__PURE__ */ jsxs("section", { className: sectionClass, children: [
503
+ /* @__PURE__ */ jsxs("div", { className: "mb-native-section-head", children: [
504
+ /* @__PURE__ */ jsxs("div", { children: [
505
+ /* @__PURE__ */ jsx("h3", { children: "Patient and claim" }),
506
+ /* @__PURE__ */ jsx("p", { children: "Prefilled from the case. Correct anything that should print differently on this bill." })
507
+ ] }),
508
+ /* @__PURE__ */ jsx("span", { children: "Editable" })
509
+ ] }),
510
+ /* @__PURE__ */ jsxs("div", { className: "mb-native-grid three", children: [
511
+ /* @__PURE__ */ jsx(Field, { label: "Patient first name", required: true, disabled: !editable, value: draft.patientFirstName, onChange: (patientFirstName) => setDraft((current) => ({ ...current, patientFirstName })) }),
512
+ /* @__PURE__ */ jsx(Field, { label: "Middle name", optional: true, disabled: !editable, value: draft.patientMiddleName, onChange: (patientMiddleName) => setDraft((current) => ({ ...current, patientMiddleName })) }),
513
+ /* @__PURE__ */ jsx(Field, { label: "Patient last name", required: true, disabled: !editable, value: draft.patientLastName, onChange: (patientLastName) => setDraft((current) => ({ ...current, patientLastName })) }),
514
+ /* @__PURE__ */ jsx(Field, { label: "Date of birth", type: "date", required: true, disabled: !editable, value: draft.patientDob, onChange: (patientDob) => setDraft((current) => ({ ...current, patientDob })) }),
515
+ /* @__PURE__ */ jsx(Field, { label: "Claim number", required: true, disabled: !editable, value: draft.claimNumber, onChange: (claimNumber) => setDraft((current) => ({ ...current, claimNumber })), ...data.injury.claimPatternStatus?.detail || data.injury.claimPatternStatus?.label ? { hint: data.injury.claimPatternStatus?.detail || data.injury.claimPatternStatus?.label || "" } : {} }),
516
+ /* @__PURE__ */ jsx(Field, { label: "Employer", disabled: !editable, value: draft.employer, onChange: (employer) => setDraft((current) => ({ ...current, employer })) }),
517
+ /* @__PURE__ */ jsx(Field, { label: "Date of injury", type: "date", required: true, disabled: !editable, value: draft.doi, onChange: (doi) => setDraft((current) => ({ ...current, doi })) }),
518
+ draft.cumulativeTrauma ? /* @__PURE__ */ jsx(Field, { label: "Cumulative trauma end date", type: "date", required: true, disabled: !editable, value: draft.injuryEndDate, onChange: (injuryEndDate) => setDraft((current) => ({ ...current, injuryEndDate })) }) : null,
519
+ features?.wcabNumber === false ? null : /* @__PURE__ */ jsx(Field, { label: "WCAB / ADJ number", optional: true, disabled: !editable, value: draft.adjNumber, onChange: (adjNumber) => setDraft((current) => ({ ...current, adjNumber })), hint: adjFormatValid ? "Use the EAMS case number shown as ADJ followed by digits." : "Expected format: ADJ followed by at least 7 digits." })
520
+ ] }),
521
+ features?.wcabNumber === false ? null : /* @__PURE__ */ jsxs("p", { className: "mb-native-eams", children: [
522
+ "EAMS lookup requires California DWC verification. ",
523
+ /* @__PURE__ */ jsx("a", { href: "https://eams.dwc.ca.gov/WebEnhancement/", target: "_blank", rel: "noreferrer", children: "Verify in EAMS" }),
524
+ "."
335
525
  ] })
336
526
  ] }),
337
527
  /* @__PURE__ */ jsxs("section", { className: sectionClass, children: [
338
528
  /* @__PURE__ */ jsx("div", { className: "mb-native-section-head", children: /* @__PURE__ */ jsxs("div", { children: [
339
- /* @__PURE__ */ jsx("h3", { children: "Claim and service" }),
340
- /* @__PURE__ */ jsx("p", { children: "These values print on the bill." })
529
+ /* @__PURE__ */ jsx("h3", { children: "Service" }),
530
+ /* @__PURE__ */ jsx("p", { children: "The service date and optional payer authorization printed on this bill." })
341
531
  ] }) }),
342
- /* @__PURE__ */ jsxs("div", { className: `mb-native-grid ${features?.authorizationNumber === false ? "two" : "three"}`, children: [
343
- /* @__PURE__ */ jsx(Field, { label: "Date of service", type: "date", required: true, value: draft.dos, onChange: (dos) => setDraft((current) => ({ ...current, dos })) }),
344
- /* @__PURE__ */ jsx(Field, { label: "End date", type: "date", optional: true, value: draft.dosEnd, onChange: (dosEnd) => setDraft((current) => ({ ...current, dosEnd })) }),
345
- features?.authorizationNumber === false ? null : /* @__PURE__ */ jsx(Field, { label: "Authorization number", optional: true, value: draft.authorizationNumber, onChange: (authorizationNumber) => setDraft((current) => ({ ...current, authorizationNumber })) })
532
+ /* @__PURE__ */ jsxs("div", { className: `mb-native-grid ${features?.serviceDateRange || features?.authorizationNumber !== false ? "three" : "one"}`, children: [
533
+ /* @__PURE__ */ jsx(Field, { label: "Date of service", type: "date", required: true, disabled: !editable, value: draft.dos, onChange: (dos) => setDraft((current) => ({ ...current, dos })) }),
534
+ features?.serviceDateRange ? /* @__PURE__ */ jsx(Field, { label: "Service end date", type: "date", optional: true, disabled: !editable, value: draft.dosEnd, onChange: (dosEnd) => setDraft((current) => ({ ...current, dosEnd })) }) : null,
535
+ features?.authorizationNumber === false ? null : /* @__PURE__ */ jsx(Field, { label: "Authorization number", optional: true, disabled: !editable, value: draft.authorizationNumber, onChange: (authorizationNumber) => setDraft((current) => ({ ...current, authorizationNumber })) })
346
536
  ] })
347
537
  ] }),
348
538
  /* @__PURE__ */ jsxs("section", { className: sectionClass, children: [
@@ -360,7 +550,7 @@ function BillReviewForm({
360
550
  /* @__PURE__ */ jsx(Field, { label: "Phone", optional: true, value: draft.billingProvider.phone || "", onChange: (value) => updateBillingProvider("phone", value) }),
361
551
  /* @__PURE__ */ jsx(Field, { label: "Billing street", required: true, value: draft.billingProvider.billingStreet || "", onChange: (value) => updateBillingProvider("billingStreet", value) }),
362
552
  /* @__PURE__ */ jsx(Field, { label: "City", required: true, value: draft.billingProvider.billingCity || "", onChange: (value) => updateBillingProvider("billingCity", value) }),
363
- /* @__PURE__ */ jsx(Field, { label: "State", required: true, value: draft.billingProvider.billingState || "", onChange: (value) => updateBillingProvider("billingState", value) }),
553
+ /* @__PURE__ */ jsx(StateCombobox, { label: "State", required: true, disabled: !editable, value: draft.billingProvider.billingState || "", onChange: (value) => updateBillingProvider("billingState", value) }),
364
554
  /* @__PURE__ */ jsx(Field, { label: "ZIP", required: true, value: draft.billingProvider.billingZip || "", onChange: (value) => updateBillingProvider("billingZip", value) })
365
555
  ] })
366
556
  ] }),
@@ -378,7 +568,7 @@ function BillReviewForm({
378
568
  /* @__PURE__ */ jsx(Field, { label: "NPI", required: true, value: draft.clinician.npi, onChange: (value) => updateClinician("npi", value) }),
379
569
  /* @__PURE__ */ jsx(Field, { label: "Taxonomy", optional: true, value: draft.clinician.taxonomy || "", onChange: (value) => updateClinician("taxonomy", value) }),
380
570
  /* @__PURE__ */ jsx(Field, { label: "License number", optional: true, value: draft.clinician.licenseNumber || "", onChange: (value) => updateClinician("licenseNumber", value) }),
381
- /* @__PURE__ */ jsx(Field, { label: "License state", optional: true, value: draft.clinician.licenseState || "", onChange: (value) => updateClinician("licenseState", value) })
571
+ /* @__PURE__ */ jsx(StateCombobox, { label: "License state (optional)", disabled: !editable, value: draft.clinician.licenseState || "", onChange: (value) => updateClinician("licenseState", value) })
382
572
  ] })
383
573
  ] }),
384
574
  /* @__PURE__ */ jsxs("section", { className: sectionClass, children: [
@@ -393,7 +583,7 @@ function BillReviewForm({
393
583
  /* @__PURE__ */ jsx(Field, { label: "Location name", required: true, value: draft.location.name, onChange: (value) => updateLocation("name", value) }),
394
584
  /* @__PURE__ */ jsx(Field, { label: "Street", required: true, value: draft.location.street, onChange: (value) => updateLocation("street", value) }),
395
585
  /* @__PURE__ */ jsx(Field, { label: "City", required: true, value: draft.location.city, onChange: (value) => updateLocation("city", value) }),
396
- /* @__PURE__ */ jsx(Field, { label: "State", required: true, value: draft.location.state, onChange: (value) => updateLocation("state", value) }),
586
+ /* @__PURE__ */ jsx(StateCombobox, { label: "State", required: true, disabled: !editable, value: draft.location.state, onChange: (value) => updateLocation("state", value) }),
397
587
  /* @__PURE__ */ jsx(Field, { label: "ZIP", required: true, value: draft.location.zip, onChange: (value) => updateLocation("zip", value) }),
398
588
  /* @__PURE__ */ jsx(Field, { label: "Place of service code", required: true, value: draft.location.posCode || "11", onChange: (value) => updateLocation("posCode", value) })
399
589
  ] })
@@ -402,16 +592,75 @@ function BillReviewForm({
402
592
  /* @__PURE__ */ jsxs("div", { className: "mb-native-section-head", children: [
403
593
  /* @__PURE__ */ jsxs("div", { children: [
404
594
  /* @__PURE__ */ jsx("h3", { children: "Procedure lines" }),
405
- /* @__PURE__ */ jsx("p", { children: "The allowed amount is recalculated when changes are saved." })
595
+ /* @__PURE__ */ jsx("p", { children: "Choose a billing profile, then review the codes and modifiers. Allowed amounts recalculate on save." })
406
596
  ] }),
407
- /* @__PURE__ */ jsx("button", { type: "button", className: "mb-native-button quiet", disabled: !editable, onClick: () => setDraft((current) => ({ ...current, lineItems: [...current.lineItems, { code: "", modifiers: [], units: 1, charge: 0 }] })), children: "+ Add line" })
597
+ /* @__PURE__ */ jsx("button", { type: "button", className: "mb-native-button quiet", disabled: !editable || draft.lineItems.length >= 50, onClick: () => setDraft((current) => ({ ...current, lineItems: [...current.lineItems, { code: "", modifiers: [], units: 1, charge: 0 }] })), children: "+ Add line" })
598
+ ] }),
599
+ features?.codingPresets === false ? null : /* @__PURE__ */ jsxs("div", { className: "mb-native-presets", role: "group", "aria-label": "Evaluation billing profile", children: [
600
+ [["qme", "QME"], ["ame", "AME"], ["psych_qme", "Psych QME"]].map(([value, label]) => /* @__PURE__ */ jsx("button", { type: "button", className: inferPreset(draft.lineItems) === value ? "active" : "", disabled: !editable, onClick: () => setDraft((current) => ({ ...current, lineItems: applyPreset(current.lineItems, value) })), children: label }, value)),
601
+ /* @__PURE__ */ jsx("span", { children: "Sets evaluator modifiers across med-legal lines. You can still edit each line." })
408
602
  ] }),
409
603
  /* @__PURE__ */ jsx("div", { className: "mb-native-lines", children: draft.lineItems.map((line, index) => /* @__PURE__ */ jsxs("div", { className: "mb-native-line", children: [
410
- /* @__PURE__ */ jsx(Field, { label: "Procedure", required: true, value: line.code, onChange: (value) => setDraft((current) => ({ ...current, lineItems: current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, code: value } : item) })) }),
411
- /* @__PURE__ */ jsx(Field, { label: "Modifiers", value: line.modifiers.join(", "), onChange: (value) => setDraft((current) => ({ ...current, lineItems: current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, modifiers: value.split(",").map((part) => part.trim()).filter(Boolean) } : item) })) }),
604
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
605
+ /* @__PURE__ */ jsx("span", { children: "Procedure" }),
606
+ /* @__PURE__ */ jsxs("select", { disabled: !editable, value: line.code, onChange: (event) => {
607
+ const code = event.target.value;
608
+ setDraft((current) => {
609
+ const lineItems = current.lineItems.map((item, itemIndex) => {
610
+ if (itemIndex !== index) return item;
611
+ const presetLine = applyPreset(
612
+ [{ ...item, code }],
613
+ inferPreset(current.lineItems)
614
+ )[0];
615
+ return { ...item, code, modifiers: presetLine?.modifiers || [] };
616
+ });
617
+ if (code && index === lineItems.length - 1 && lineItems.length < 50) {
618
+ lineItems.push({
619
+ code: "",
620
+ modifiers: [],
621
+ units: 1,
622
+ charge: 0
623
+ });
624
+ }
625
+ return { ...current, lineItems };
626
+ });
627
+ }, children: [
628
+ line.code && !PROCEDURES.some(([code]) => code === line.code) ? /* @__PURE__ */ jsx("option", { value: line.code, children: line.code }) : null,
629
+ /* @__PURE__ */ jsx("option", { value: "", children: "Select code\u2026" }),
630
+ PROCEDURES.map(([code, label]) => /* @__PURE__ */ jsxs("option", { value: code, children: [
631
+ code,
632
+ " \u2014 ",
633
+ label
634
+ ] }, code))
635
+ ] }),
636
+ line.code ? /* @__PURE__ */ jsx("small", { children: PROCEDURES.find(([code]) => code === line.code)?.[1] }) : null
637
+ ] }),
638
+ /* @__PURE__ */ jsxs("div", { className: "mb-native-modifiers", children: [
639
+ /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
640
+ /* @__PURE__ */ jsx("span", { children: "Modifiers" }),
641
+ /* @__PURE__ */ jsxs("select", { disabled: !editable, value: "", onChange: (event) => {
642
+ const modifier = event.target.value;
643
+ if (!modifier) return;
644
+ setDraft((current) => ({ ...current, lineItems: current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, modifiers: [.../* @__PURE__ */ new Set([...item.modifiers, modifier])] } : item) }));
645
+ }, children: [
646
+ /* @__PURE__ */ jsx("option", { value: "", children: "Add modifier\u2026" }),
647
+ MODIFIERS.filter(([value]) => !line.modifiers.includes(value) && modifierAppliesToCode(value, line.code)).map(([value, label]) => /* @__PURE__ */ jsxs("option", { value, children: [
648
+ "-",
649
+ value,
650
+ " \u2014 ",
651
+ label
652
+ ] }, value))
653
+ ] })
654
+ ] }),
655
+ /* @__PURE__ */ jsx("div", { className: "mb-native-chips", children: line.modifiers.map((modifier) => /* @__PURE__ */ jsxs("button", { type: "button", disabled: !editable, onClick: () => setDraft((current) => ({ ...current, lineItems: current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, modifiers: item.modifiers.filter((value) => value !== modifier) } : item) })), children: [
656
+ "-",
657
+ modifier,
658
+ " \xD7"
659
+ ] }, modifier)) })
660
+ ] }),
412
661
  /* @__PURE__ */ jsxs("label", { className: "mb-native-field", children: [
413
662
  /* @__PURE__ */ jsx("span", { children: "Units" }),
414
- /* @__PURE__ */ jsx("input", { type: "number", min: "1", required: true, value: line.units, onChange: (event) => setDraft((current) => ({ ...current, lineItems: current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, units: Number(event.target.value) } : item) })) })
663
+ /* @__PURE__ */ jsx("input", { type: "number", min: "1", required: true, disabled: !editable, value: line.units, onChange: (event) => setDraft((current) => ({ ...current, lineItems: current.lineItems.map((item, itemIndex) => itemIndex === index ? { ...item, units: Number(event.target.value) } : item) })) })
415
664
  ] }),
416
665
  /* @__PURE__ */ jsxs("div", { className: "mb-native-allowed", children: [
417
666
  /* @__PURE__ */ jsx("span", { children: "Allowed" }),
@@ -469,6 +718,10 @@ function BillReviewForm({
469
718
  ] }),
470
719
  error ? /* @__PURE__ */ jsx("div", { className: "mb-native-message error", role: "alert", children: error }) : null,
471
720
  notice ? /* @__PURE__ */ jsx("div", { className: "mb-native-message success", role: "status", children: notice }) : null,
721
+ !canSubmit ? /* @__PURE__ */ jsxs("div", { className: "mb-native-blockers", role: "status", children: [
722
+ /* @__PURE__ */ jsx("strong", { children: "Before you can submit:" }),
723
+ /* @__PURE__ */ jsx("span", { children: blockers.join(" \xB7 ") })
724
+ ] }) : null,
472
725
  /* @__PURE__ */ jsxs("div", { className: "mb-native-actions", children: [
473
726
  /* @__PURE__ */ jsx("button", { className: "mb-native-button secondary", type: "submit", disabled: !editable || busy !== "", children: busy === "save" ? "Saving\u2026" : "Save changes" }),
474
727
  /* @__PURE__ */ jsx("button", { className: "mb-native-button primary", type: "button", disabled: !editable || !canSubmit || busy !== "", onClick: () => void handleSubmit(), children: busy === "submit" ? "Submitting\u2026" : "Submit bill" })
@@ -520,6 +773,18 @@ var NATIVE_BILL_REVIEW_STYLES = `
520
773
  .mb-native-payer-results button{display:grid;width:100%;gap:2px;padding:11px 12px;border:0;border-radius:7px;background:transparent;color:var(--mb-text);font:inherit;text-align:left;cursor:pointer}
521
774
  .mb-native-payer-results button:hover,.mb-native-payer-results button:focus{background:var(--mb-soft);outline:0}
522
775
  .mb-native-payer-results span{color:var(--mb-muted);font-size:12px}
776
+ .mb-native-grid.one{grid-template-columns:minmax(0,1fr)}
777
+ .mb-native-field select{width:100%;min-height:43px;border:1px solid var(--mb-border);border-radius:8px;background:#fff;color:var(--mb-text);font:inherit;padding:10px 36px 10px 12px}
778
+ .mb-native-field select:focus{border-color:var(--mb-accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--mb-accent) 14%,transparent);outline:0}
779
+ .mb-native-field input:disabled,.mb-native-field select:disabled{cursor:not-allowed;background:#f6f8f9;color:#667982}
780
+ .mb-native-hint{color:var(--mb-muted);font-size:12px;font-weight:500}
781
+ .mb-native-combo{position:relative;min-width:0}
782
+ .mb-native-combo-list{position:absolute;z-index:20;top:calc(100% + 6px);right:0;left:0;max-height:300px;overflow:auto;list-style:none;margin:0;padding:6px;border:1px solid var(--mb-border);border-radius:10px;background:var(--mb-surface);box-shadow:0 18px 42px rgba(28,58,72,.18)}
783
+ .mb-native-combo-list li{margin:0;padding:0}.mb-native-combo-list button{display:grid;width:100%;gap:2px;padding:11px 12px;border:0;border-radius:7px;background:transparent;color:var(--mb-text);font:inherit;text-align:left;cursor:pointer}.mb-native-combo-list button:hover,.mb-native-combo-list button.active{background:var(--mb-soft);outline:0}.mb-native-combo-list span{color:var(--mb-muted);font-size:12px;font-weight:500}
784
+ .mb-native-presets{display:flex;align-items:center;flex-wrap:wrap;gap:7px;margin:-2px 0 14px}.mb-native-presets button{min-height:36px;border:1px solid var(--mb-border);border-radius:8px;background:#fff;color:var(--mb-text);cursor:pointer;font:inherit;font-weight:750;padding:7px 13px}.mb-native-presets button.active{border-color:var(--mb-accent);background:var(--mb-accent);color:#fff}.mb-native-presets span{margin-left:5px;color:var(--mb-muted);font-size:12px}
785
+ .mb-native-modifiers{display:grid;gap:7px}.mb-native-chips{display:flex;flex-wrap:wrap;gap:5px}.mb-native-chips button{border:1px solid #c9dce3;border-radius:999px;background:#fff;color:var(--mb-text);cursor:pointer;font:inherit;font-size:11px;font-weight:750;padding:4px 8px}
786
+ .mb-native-blockers{grid-column:1/-1;display:grid;gap:2px;padding:11px 13px;border:1px solid #e8cf9a;border-radius:8px;background:#fff9ea;color:#74531b}.mb-native-blockers span{font-size:12px}
787
+ .mb-native-eams{margin-top:13px!important;font-size:12px}.mb-native-eams a{color:var(--mb-accent);font-weight:750}
523
788
  @media(max-width:620px){.mb-native-review{padding:12px}.mb-native-grid.two{grid-template-columns:1fr}}
524
789
  `;
525
790
 
@@ -528,7 +793,7 @@ import {
528
793
  useCallback,
529
794
  useEffect as useEffect2,
530
795
  useMemo as useMemo2,
531
- useRef,
796
+ useRef as useRef2,
532
797
  useState as useState2
533
798
  } from "react";
534
799
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -677,11 +942,11 @@ function useBillStatus({
677
942
  const [error, setError] = useState2(null);
678
943
  const [isLoading, setIsLoading] = useState2(enabled && !initialData);
679
944
  const [isRefreshing, setIsRefreshing] = useState2(false);
680
- const dataRef = useRef(initialData);
681
- const initialDataRef = useRef(initialData);
945
+ const dataRef = useRef2(initialData);
946
+ const initialDataRef = useRef2(initialData);
682
947
  initialDataRef.current = initialData;
683
- const activeControllerRef = useRef(null);
684
- const requestSequence = useRef(0);
948
+ const activeControllerRef = useRef2(null);
949
+ const requestSequence = useRef2(0);
685
950
  useEffect2(() => {
686
951
  const seed = initialDataRef.current;
687
952
  dataRef.current = seed;
@@ -787,7 +1052,7 @@ import {
787
1052
  useCallback as useCallback2,
788
1053
  useEffect as useEffect3,
789
1054
  useMemo as useMemo3,
790
- useRef as useRef2,
1055
+ useRef as useRef3,
791
1056
  useState as useState3
792
1057
  } from "react";
793
1058
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -1086,7 +1351,7 @@ function useBillLifecycle({
1086
1351
  const [isLoading, setIsLoading] = useState3(enabled && !initialData);
1087
1352
  const [isRefreshing, setIsRefreshing] = useState3(false);
1088
1353
  const [isMutating, setIsMutating] = useState3(false);
1089
- const mounted = useRef2(true);
1354
+ const mounted = useRef3(true);
1090
1355
  useEffect3(() => {
1091
1356
  setBillId(providedBillId);
1092
1357
  setData(initialData);
@@ -1298,7 +1563,7 @@ function ConnectedBillLifecycle({
1298
1563
  attachmentIds: [],
1299
1564
  route: "ebill"
1300
1565
  });
1301
- const lastData = useRef2(null);
1566
+ const lastData = useRef3(null);
1302
1567
  useEffect3(() => {
1303
1568
  if (!data || data === lastData.current) return;
1304
1569
  lastData.current = data;
@@ -1553,7 +1818,7 @@ var CONNECTED_LIFECYCLE_STYLES = `
1553
1818
 
1554
1819
  // src/index.tsx
1555
1820
  function widget(tagName, props) {
1556
- const ref = useRef3(null);
1821
+ const ref = useRef4(null);
1557
1822
  const { onMindBill, onMindBillError } = props;
1558
1823
  useEffect4(() => {
1559
1824
  const element = ref.current;