@mindbill/react 0.21.0 → 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 CHANGED
@@ -157,7 +157,7 @@ The component includes the interaction model, not just the markup:
157
157
  - canonical claims-administrator search through the authenticated MindBill payer directory;
158
158
  - QME, AME, and Psych QME evaluation modes with medical-legal modifier defaults;
159
159
  - searchable workers-comp procedure/modifier controls, medical-legal fee-schedule amounts, totals, valid manual CPT/HCPCS entry, and an automatically maintained empty line;
160
- - removable source documents, a locked auto-attached practice W-9, and click, panel-drop, or whole-page PDF upload.
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.
161
161
 
162
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.
163
163
 
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;
package/dist/index.js CHANGED
@@ -1321,6 +1321,11 @@ var MAX_PDF_BYTES = 25 * 1024 * 1024;
1321
1321
  var MAX_UPLOAD_BYTES = 100 * 1024 * 1024;
1322
1322
  var MAX_DOCUMENTS = 25;
1323
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
+ }
1324
1329
  function blankLine() {
1325
1330
  return { code: "", modifiers: [], units: 1 };
1326
1331
  }
@@ -1419,8 +1424,8 @@ var css = `
1419
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)}
1420
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)}
1421
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}
1422
- .mbsf-icon-btn{width:40px;height:42px;border:0;background:transparent;color:var(--mb-text);font-size:22px;cursor:pointer}.mbsf-secondary{min-height:40px;padding:8px 14px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius);background:var(--mb-surface);color:var(--mb-text);font:inherit;font-weight:680;cursor:pointer}.mbsf-attach-list{display:grid;gap:10px;margin-bottom:18px}.mbsf-attach-row{padding:14px;border:1px solid var(--mb-border);border-radius:var(--mb-control-radius)}.mbsf-attach-row[data-auto=true]{border-color:color-mix(in srgb,#159447 45%,var(--mb-border));background:color-mix(in srgb,#159447 5%,var(--mb-surface))}.mbsf-file{min-width:0}.mbsf-file strong{overflow-wrap:anywhere}.mbsf-badge{display:inline-block;margin-left:8px;padding:2px 7px;border:1px solid var(--mb-border);border-radius:7px;color:var(--mb-muted);font-size:12px;font-weight:600}.mbsf-drop{display:grid;place-items:center;min-height:180px;padding:24px;border:2px dashed color-mix(in srgb,var(--mb-muted) 55%,transparent);border-radius:var(--mb-control-radius);background:color-mix(in srgb,var(--mb-accent) 3%,var(--mb-surface));text-align:center;cursor:pointer}.mbsf-drop[data-active=true]{border-color:var(--mb-accent);background:color-mix(in srgb,var(--mb-accent) 10%,var(--mb-surface))}.mbsf-alert{padding:12px 14px;border-radius:var(--mb-control-radius);background:color-mix(in srgb,var(--mb-danger) 10%,transparent);color:var(--mb-danger)}.mbsf-actions{justify-content:flex-end}.mbsf-submit{min-width:180px;min-height:48px;padding:11px 24px;border:0;border-radius:var(--mb-control-radius);background:var(--mb-accent);color:var(--mb-accent-contrast);font:inherit;font-weight:780;cursor:pointer}
1423
- @media(max-width:820px){.mbsf{gap:16px}.mbsf-grid{grid-template-columns:1fr}.mbsf-span{grid-column:auto}.mbsf-card{padding:18px 16px}.mbsf-line-head{display:none}.mbsf-line{position:relative;display:grid;grid-template-columns:minmax(0,1fr) 86px;gap:14px;padding:18px 16px}.mbsf-line>div:before{display:block;margin-bottom:6px;color:var(--mb-muted);font-size:12px;font-weight:700;content:attr(data-label)}.mbsf-line>div:nth-child(1),.mbsf-line>div:nth-child(2){grid-column:1/-1}.mbsf-money{align-self:end;padding:0 0 12px;text-align:right}.mbsf-line .mbsf-icon-btn{position:absolute;right:8px;bottom:3px}.mbsf-total{padding:16px 18px;gap:24px}.mbsf-head{align-items:flex-start}.mbsf-segments{grid-template-columns:repeat(3,minmax(0,1fr))}.mbsf-segment{min-width:0;padding:8px 4px;border-right:1px solid var(--mb-border);border-bottom:0;font-size:13px}.mbsf-segment:last-child{border-right:0}.mbsf-attach-row{align-items:flex-start;flex-wrap:wrap}.mbsf-actions{position:sticky;bottom:86px;z-index:10}.mbsf-submit{width:100%}}
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%}}
1424
1429
  `;
1425
1430
  function RequiredMark() {
1426
1431
  return /* @__PURE__ */ jsx3("span", { className: "mbsf-star", children: " *" });
@@ -1516,7 +1521,7 @@ function BillSubmissionForm({
1516
1521
  description = "Review the bill details, add attachments, and submit."
1517
1522
  }) {
1518
1523
  const [bill, setBill] = useState2(() => cloneBill(initialBill));
1519
- const [selectedIds, setSelectedIds] = useState2(() => attachments.filter((item) => item.selected !== false || item.autoAttached || item.documentType === "w9").map((item) => item.id));
1524
+ const [selectedIds, setSelectedIds] = useState2(() => attachments.map((item) => item.id));
1520
1525
  const [removedSourceIds, setRemovedSourceIds] = useState2([]);
1521
1526
  const [uploads, setUploads] = useState2([]);
1522
1527
  const [errors, setErrors] = useState2({});
@@ -1536,7 +1541,7 @@ function BillSubmissionForm({
1536
1541
  const locked = disabled || submitting;
1537
1542
  useEffect2(() => {
1538
1543
  setBill(cloneBill(initialBill));
1539
- setSelectedIds(attachments.filter((item) => item.selected !== false || item.autoAttached || item.documentType === "w9").map((item) => item.id));
1544
+ setSelectedIds(attachments.map((item) => item.id));
1540
1545
  setRemovedSourceIds([]);
1541
1546
  setUploads([]);
1542
1547
  setErrors({});
@@ -1606,11 +1611,15 @@ function BillSubmissionForm({
1606
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));
1607
1612
  };
1608
1613
  const searchDiagnoses = (query) => {
1609
- if (query.trim().length < 2) return;
1614
+ const trimmed = query.trim();
1615
+ if (!trimmed) {
1616
+ setDiagnosisResults(diagnosisOptions);
1617
+ return;
1618
+ }
1610
1619
  const search = onSearchDiagnoses ?? referenceClient?.searchDiagnosisCodes;
1611
1620
  if (!search) return;
1612
1621
  setDiagnosisLoading(true);
1613
- void search(query).then(setDiagnosisResults).catch(() => setDiagnosisResults([])).finally(() => setDiagnosisLoading(false));
1622
+ void search(trimmed).then(setDiagnosisResults).catch(() => setDiagnosisResults([])).finally(() => setDiagnosisLoading(false));
1614
1623
  };
1615
1624
  const updatePostalCode = (postalCode) => {
1616
1625
  setAddress({ postalCode });
@@ -1778,34 +1787,37 @@ function BillSubmissionForm({
1778
1787
  /* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-list", children: [
1779
1788
  attachments.filter((attachment) => !removedSourceIds.includes(attachment.id)).map((attachment) => {
1780
1789
  const auto = attachment.autoAttached || attachment.documentType === "w9";
1781
- const selected = selectedIds.includes(attachment.id);
1782
1790
  const removable = !auto && attachment.removable !== false;
1783
1791
  return /* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-row", "data-auto": auto, children: [
1784
- /* @__PURE__ */ jsxs3("label", { className: "mbsf-attach-row", style: { border: 0, padding: 0, flex: 1, justifyContent: "flex-start" }, children: [
1785
- auto ? /* @__PURE__ */ jsx3("span", { "aria-label": "Always attached", role: "img", children: "\u2713" }) : /* @__PURE__ */ jsx3("input", { type: "checkbox", checked: selected, disabled: locked, onChange: (event) => setSelectedIds((current) => event.target.checked ? [.../* @__PURE__ */ new Set([...current, attachment.id])] : current.filter((id) => id !== attachment.id)) }),
1792
+ /* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-main", children: [
1793
+ auto ? /* @__PURE__ */ jsx3("span", { "aria-label": "Always attached", role: "img", children: "\u2713" }) : null,
1786
1794
  /* @__PURE__ */ jsxs3("span", { className: "mbsf-file", children: [
1787
1795
  /* @__PURE__ */ jsx3("strong", { children: attachment.fileName }),
1788
1796
  /* @__PURE__ */ jsx3("span", { className: "mbsf-badge", children: auto ? "Auto-attached" : documentLabels[attachment.documentType] }),
1789
1797
  /* @__PURE__ */ jsx3("span", { className: "mbsf-help", style: { display: "block" }, children: attachment.description || (auto ? "Included automatically with every bill." : documentLabels[attachment.documentType]) })
1790
1798
  ] })
1791
1799
  ] }),
1792
- attachment.previewUrl ? /* @__PURE__ */ jsx3("a", { className: "mbsf-secondary", href: attachment.previewUrl, target: "_blank", rel: "noreferrer", children: "View" }) : null,
1793
- removable ? /* @__PURE__ */ jsx3("button", { className: "mbsf-icon-btn", type: "button", "aria-label": `Remove ${attachment.fileName}`, disabled: locked, onClick: () => {
1794
- setSelectedIds((current) => current.filter((id) => id !== attachment.id));
1795
- setRemovedSourceIds((current) => [.../* @__PURE__ */ new Set([...current, attachment.id])]);
1796
- }, children: "\xD7" }) : null
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
+ ] })
1797
1807
  ] }, attachment.id);
1798
1808
  }),
1799
1809
  uploads.map((upload, index) => /* @__PURE__ */ jsxs3("div", { className: "mbsf-attach-row", children: [
1800
- /* @__PURE__ */ jsxs3("span", { className: "mbsf-file", children: [
1810
+ /* @__PURE__ */ jsx3("div", { className: "mbsf-attach-main", children: /* @__PURE__ */ jsxs3("span", { className: "mbsf-file", children: [
1801
1811
  /* @__PURE__ */ jsx3("strong", { children: upload.file.name }),
1802
1812
  /* @__PURE__ */ jsxs3("span", { className: "mbsf-help", style: { display: "block" }, children: [
1803
1813
  (upload.file.size / 1024 / 1024).toFixed(1),
1804
1814
  " MB"
1805
1815
  ] })
1806
- ] }),
1807
- /* @__PURE__ */ jsx3("select", { className: "mbsf-select", style: { width: 190 }, value: upload.documentType, onChange: (event) => setUploads((current) => current.map((item, itemIndex) => itemIndex === index ? { ...item, documentType: event.target.value } : item)), children: BILL_SUBMISSION_DOCUMENT_TYPES.map((type) => /* @__PURE__ */ jsx3("option", { value: type, children: documentLabels[type] }, type)) }),
1808
- /* @__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" })
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
+ ] })
1809
1821
  ] }, `${upload.file.name}-${index}`))
1810
1822
  ] }),
1811
1823
  /* @__PURE__ */ jsx3("input", { ref: fileInput, hidden: true, type: "file", accept: "application/pdf,.pdf", multiple: true, onChange: (event) => {