@mindbill/react 0.77.61 → 0.77.63

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.d.ts CHANGED
@@ -227,6 +227,8 @@ type BillSubmissionProcedureOption = {
227
227
  code: string;
228
228
  description: string;
229
229
  allowedAmount?: number;
230
+ /** Units a line starts with when this code is chosen, for services with a customary or minimum quantity. */
231
+ defaultUnits?: number;
230
232
  };
231
233
  type BillSubmissionModifierOption = {
232
234
  code: string;
package/dist/index.js CHANGED
@@ -2423,7 +2423,14 @@ var messages = {
2423
2423
  telehealth_modifier_requires_ground_rule_review: "This telehealth modifier needs fee review for the service date.",
2424
2424
  conflicting_telehealth_modifiers: "Review the telehealth modifiers; the selected modes conflict.",
2425
2425
  telehealth_modifier_93_not_adopted_for_date: "Audio-only modifier 93 is not adopted for this service date. Review the dated telehealth rules.",
2426
- telehealth_modifier_required: "Select the telehealth modifier that matches the service and its date."
2426
+ telehealth_modifier_required: "Select the telehealth modifier that matches the service and its date.",
2427
+ timed_testing_add_on_requires_primary_service: "Add the first-hour or first-30-minute testing code for the same date; this code is billed only with it.",
2428
+ timed_testing_units_exceed_adopted_mue: "The units are above the daily limit for this code. Lower the units, or submit with documentation for review.",
2429
+ timed_testing_unit_limit_unverified: "The daily unit limit for this code could not be confirmed for this service date.",
2430
+ timed_testing_indicators_or_modifiers_require_review: "Remove the modifiers from this testing code to get an automatic fee, or submit it for review.",
2431
+ modifier_requires_ground_rule_review: "This modifier changes how the fee is calculated and needs review.",
2432
+ physician_service_context_required_or_adjustment_not_supported: "This service is billed with other same-day services and needs fee review.",
2433
+ separate_schedule_or_payment_formula_required: "This code is paid under a separate schedule and needs fee review."
2427
2434
  };
2428
2435
  function feeReviewMessage(reason) {
2429
2436
  if (!reason) return "Checking the fee schedule\u2026";
@@ -8640,15 +8647,15 @@ function TextDateInput({ value, onChange, disabled, required: required2, ariaLab
8640
8647
  invalid ? /* @__PURE__ */ jsx20("small", { className: "mbsf-error", children: "Use MM/DD/YYYY" }) : null
8641
8648
  ] });
8642
8649
  }
8643
- function ComboBox({ value, placeholder, options, disabled, loading, loadingMore, invalid, preserveValueOnOpen = false, filterOptions = true, onOpen, onQuery, onEndReached, onSelect, createOption, ariaLabel }) {
8650
+ function ComboBox({ value, placeholder, options, disabled, loading, loadingMore, invalid, preserveValueOnOpen = false, filterOptions = true, matchCodeIgnoringSeparators = false, onOpen, onQuery, onEndReached, onSelect, createOption, ariaLabel }) {
8644
8651
  const [open, setOpen] = useState12(false);
8645
8652
  const [query, setQuery] = useState12("");
8646
8653
  const visible = useMemo6(() => {
8647
8654
  const q = query.trim().toLowerCase();
8648
- const matches = q && filterOptions ? options.filter((option) => `${option.id} ${option.label} ${option.detail ?? ""} ${(option.badges ?? []).join(" ")} ${(option.affiliatedEntities ?? []).join(" ")} ${option.trailing ?? ""}`.toLowerCase().includes(q)) : options;
8655
+ const matches = q && filterOptions ? options.filter((option) => `${option.id} ${option.label} ${option.detail ?? ""} ${(option.badges ?? []).join(" ")} ${(option.affiliatedEntities ?? []).join(" ")} ${option.trailing ?? ""}`.toLowerCase().includes(q) || matchCodeIgnoringSeparators && /[\s-]/.test(q) && option.id.toLowerCase().includes(q.replace(/[\s-]+/g, ""))) : options;
8649
8656
  const custom = createOption?.(query) ?? null;
8650
8657
  return custom && !matches.some((option) => option.id.toUpperCase() === custom.id.toUpperCase()) ? [...matches, custom] : matches;
8651
- }, [createOption, filterOptions, options, query]);
8658
+ }, [createOption, filterOptions, matchCodeIgnoringSeparators, options, query]);
8652
8659
  const showMenu = open;
8653
8660
  return /* @__PURE__ */ jsxs19("div", { className: "mbsf-combo", children: [
8654
8661
  /* @__PURE__ */ jsx20("input", { className: "mbsf-input", role: "combobox", "aria-label": ariaLabel, "aria-invalid": invalid, "aria-expanded": showMenu, autoComplete: "off", disabled, placeholder, value: open ? query : value, onFocus: () => {
@@ -8707,7 +8714,7 @@ function focusFirstInvalid(form) {
8707
8714
  }
8708
8715
  }
8709
8716
  function customProcedureOption(query) {
8710
- const code = query.trim().toUpperCase().replace(/\s+/g, "");
8717
+ const code = query.trim().toUpperCase().replace(/[\s-]+/g, "");
8711
8718
  if (!/^(?:\d{5}|[A-Z]\d{4}|WC\d{3}|ML(?:20[0-5]|PRR))$/.test(code)) return null;
8712
8719
  return { id: code, label: code, detail: "Use this CPT, HCPCS, or medical-legal code" };
8713
8720
  }
@@ -8898,7 +8905,7 @@ function BillSubmissionForm({
8898
8905
  const diagnosisAppendPending = useRef8(false);
8899
8906
  const payerRequest = useRef8(0);
8900
8907
  const payerAppendPending = useRef8(false);
8901
- const procedures = useMemo6(() => mergeOptions(DEFAULT_BILL_SUBMISSION_PROCEDURES, [...procedureOptions ?? [], ...procedureResults, ...treatmentBilling ? [{ code: "WC002", description: "Progress report" }, { code: "WC003", description: "Permanent and stationary report (PR-3)" }, { code: "WC004", description: "Permanent and stationary report (PR-4)" }] : []]), [procedureOptions, procedureResults, treatmentBilling]);
8908
+ const procedures = useMemo6(() => mergeOptions(DEFAULT_BILL_SUBMISSION_PROCEDURES, [...procedureResults.filter((result) => !DEFAULT_BILL_SUBMISSION_PROCEDURES.some((item) => item.code.toUpperCase() === result.code.toUpperCase())), ...procedureOptions ?? [], ...treatmentBilling ? [{ code: "WC002", description: "Progress report" }, { code: "WC003", description: "Permanent and stationary report (PR-3)" }, { code: "WC004", description: "Permanent and stationary report (PR-4)" }] : []]), [procedureOptions, procedureResults, treatmentBilling]);
8902
8909
  const orderedClaimsAdministratorSources = useMemo6(() => [...claimsAdministratorSources ?? []].filter((source) => source.name.trim()).sort((left, right) => Number(right.source.toLowerCase() === "eams") - Number(left.source.toLowerCase() === "eams")), [claimsAdministratorSources]);
8903
8910
  const sourceClaimsAdministratorName = orderedClaimsAdministratorSources[0]?.name.trim() ?? "";
8904
8911
  const initializationKey = useMemo6(
@@ -9037,6 +9044,10 @@ function BillSubmissionForm({
9037
9044
  delete next.feeContext;
9038
9045
  delete next.drug;
9039
9046
  }
9047
+ if (patch.code != null && patch.code !== line.code && (patch.units === void 0 || patch.units === line.units)) {
9048
+ const startingUnits = (code) => procedures.find((item) => item.code.toUpperCase() === code.trim().toUpperCase())?.defaultUnits ?? 1;
9049
+ if ((line.units ?? 1) === startingUnits(line.code)) next.units = startingUnits(patch.code);
9050
+ }
9040
9051
  if (treatmentBilling && next.code && !isMedicalLegalCode(next.code)) {
9041
9052
  if (!editableTreatmentCharges || patch.code != null && patch.code !== line.code) delete next.charge;
9042
9053
  return next;
@@ -9829,7 +9840,7 @@ function BillSubmissionForm({
9829
9840
  ] }),
9830
9841
  bill.serviceLines.map((line, index) => /* @__PURE__ */ jsxs19("div", { className: "mbsf-line", children: [
9831
9842
  /* @__PURE__ */ jsxs19("div", { "data-label": "Procedure code", "data-field-path": `serviceLines.${index}.code`, "data-invalid": Boolean(errors[`serviceLines.${index}.code`]), children: [
9832
- /* @__PURE__ */ jsx20(ComboBox, { ariaLabel: `Procedure code ${index + 1}`, invalid: Boolean(errors[`serviceLines.${index}.code`]), disabled: locked, value: line.code, placeholder: "Search or enter code\u2026", loading: procedureLoading, onOpen: () => loadProcedures(""), onQuery: loadProcedures, options: procedures.map((item) => ({ id: item.code, label: item.code, detail: item.description })), createOption: customProcedureOption, onSelect: (option) => {
9843
+ /* @__PURE__ */ jsx20(ComboBox, { ariaLabel: `Procedure code ${index + 1}`, invalid: Boolean(errors[`serviceLines.${index}.code`]), disabled: locked, value: line.code, placeholder: "Search or enter code\u2026", matchCodeIgnoringSeparators: true, loading: procedureLoading, onOpen: () => loadProcedures(""), onQuery: loadProcedures, options: procedures.map((item) => ({ id: item.code, label: item.code, detail: item.description })), createOption: customProcedureOption, onSelect: (option) => {
9833
9844
  const switched = isMedicalLegalCode(line.code) && !isMedicalLegalCode(option.id);
9834
9845
  const [updated] = applyBillSubmissionEvaluationModifiers([{ ...line, code: option.id, ...switched ? { modifiers: (line.modifiers ?? []).filter((value) => !["94", "95", "96"].includes(value.replace(/^-/, ""))) } : {} }], evaluationType);
9835
9846
  setLine(index, updated);
@@ -9853,7 +9864,7 @@ function BillSubmissionForm({
9853
9864
  /* @__PURE__ */ jsx20("input", { className: "mbsf-input", "aria-label": `Units ${index + 1}`, "aria-invalid": Boolean(errors[`serviceLines.${index}.units`]), type: "number", min: 1, max: treatmentBilling && isAnesthesiaCandidate(line.code) ? 1 : void 0, value: line.units ?? 1, onChange: (event) => setLine(index, { units: Number(event.target.value) }) }),
9854
9865
  errors[`serviceLines.${index}.units`] ? /* @__PURE__ */ jsx20("small", { className: "mbsf-error", role: "alert", children: errors[`serviceLines.${index}.units`] }) : null
9855
9866
  ] }),
9856
- /* @__PURE__ */ jsx20("div", { className: "mbsf-money", "data-label": editableTreatmentCharges && treatmentBilling ? "Billed charge" : "Allowed", "data-field-path": `serviceLines.${index}.charge`, "data-invalid": Boolean(errors[`serviceLines.${index}.charge`]), children: lineCharge(line, index) == null ? quoteKeys[index] ? !supportedFeeJurisdiction || !quoteFee || !quoteInputs[index]?.dateOfService || isTherapyEditorCode(line.code) && !quoteInputs[index]?.therapyContext || feeQuotes[quoteKeys[index]] ? "Needs review" : "Checking\u2026" : "\u2014" : lineCharge(line, index).toLocaleString(void 0, { style: "currency", currency: "USD" }) }),
9867
+ /* @__PURE__ */ jsx20("div", { className: "mbsf-money", "data-label": editableTreatmentCharges && treatmentBilling ? "Billed charge" : "Allowed", "data-field-path": `serviceLines.${index}.charge`, "data-invalid": Boolean(errors[`serviceLines.${index}.charge`]), children: lineCharge(line, index) == null ? quoteKeys[index] ? !supportedFeeJurisdiction || !quoteFee || !quoteInputs[index]?.dateOfService || isTherapyEditorCode(line.code) && !quoteInputs[index]?.therapyContext ? "Needs review" : feeQuotes[quoteKeys[index]]?.status === "error" ? "Fee unavailable" : feeQuotes[quoteKeys[index]] ? "Needs review" : "Checking\u2026" : "\u2014" : lineCharge(line, index).toLocaleString(void 0, { style: "currency", currency: "USD" }) }),
9857
9868
  /* @__PURE__ */ jsx20("button", { className: "mbsf-icon-btn", type: "button", "aria-label": `Remove service line ${index + 1}`, disabled: locked || !lineHasContent(line) && index === bill.serviceLines.length - 1, onClick: () => {
9858
9869
  setFeeDetails({});
9859
9870
  if (individualDiagnoses.current) individualDiagnoses.current.splice(index, 1);
@@ -11419,7 +11430,7 @@ function rfaDecisionSummary(rfa) {
11419
11430
  if (decided.every((item) => item.outcome === "modified")) return { label: "Modified", tone: "warn" };
11420
11431
  return { label: "Partially approved", tone: "warn" };
11421
11432
  }
11422
- var FAX_FAILURES = { busy: "The line was busy", no_answer: "No answer", not_a_fax_machine: "The number did not answer as a fax machine", invalid_number: "The number is not in service", rejected: "The call was rejected", carrier_error: "The fax carrier could not complete the call", email_rejected: "The e-mail address was refused" };
11433
+ var FAX_FAILURES = { busy: "The line was busy", no_answer: "No answer", not_a_fax_machine: "The number did not answer as a fax machine", invalid_number: "The number is not in service", rejected: "The call was rejected", carrier_error: "The fax carrier could not complete the call", email_rejected: "The e-mail address was refused", email_bounced_bad_address: "The e-mail bounced: that address does not exist", email_bounced_mailbox_full: "The e-mail bounced: the recipient's mailbox is full", email_bounced: "The e-mail bounced and was not delivered" };
11423
11434
  function rfaFailureReason(transmission) {
11424
11435
  const reason = transmission.metadata?.failureReason;
11425
11436
  return transmission.status === "failed" && typeof reason === "string" ? FAX_FAILURES[reason] ?? "" : "";