Components

Full bill lifecycle demo

See the same public React components your application installs, from a submitted bill through payer acceptance, EOR processing, payment, and closure.

Submission to payment and closure

Use the controls above the preview to move a single synthetic bill through the happy path. The preview is local and deterministic; it makes no network requests and contains no real patient data.

Complete bill journeyMocked sandbox API · click each lifecycle state
import { useMemo, useState } from "react";
import {
  BillActivityTimeline,
  BillExplanationOfReview,
  BillLifecycleProgress,
  BillSnapshotSummary,
} from "@mindbill/react";

const review = {
  bill: {
    id: "bill_demo_1038", billNumber: 1038, status: "Submitted",
    billingMode: "med_legal", dos: "2026-08-26",
    billingSnapshot: {
      billingProvider: { name: "Northstar Evaluations", taxId: "12-3456789", npi: "1023401122", billType: "Professional", phone: "626-555-0194", billingStreet: "236 W Mountain St", billingCity: "Pasadena", billingState: "CA", billingZip: "91103" },
      renderingProvider: { name: "Dr. Morgan Chen", specialty: "Psychiatry", npi: "1023401122", taxonomy: "2084P0800X", licenseNumber: "A140748", licenseState: "CA", isQME: true },
      placeOfService: { name: "West Covina Exam Office", street: "1050 West Lakes Dr, Ste 225", city: "West Covina", state: "CA", zip: "91790", posCode: "11" },
    },
    lineItems: [{ id: "line_1", code: "ML201", modifiers: ["-95"], units: 1, charge: 2015, serviceDate: "2026-08-26" }],
    attachments: [
      { id: "doc_report", filename: "final-report.pdf", documentType: "final_report", description: "Final medical-legal report" },
      { id: "doc_pos", filename: "proof-of-service.pdf", documentType: "proof_of_service", description: "Proof of service" },
    ],
    totalCharge: 2015, totalPaid: 0, balanceDue: 2015,
  },
  patient: { name: "Alex Morgan", firstName: "Alex", lastName: "Morgan", dob: "1988-03-05" },
  injury: { claimNumber: "W8331838-0001", employer: "Northstar Foods", doi: "2025-05-30", adjNumber: "ADJ21439594", claimsAdminId: "payer_republic", claimsAdminName: "Republic Indemnity", claimPatternStatus: { state: "match", label: "Claim pattern matches Republic Indemnity" } },
};

const steps = ["submitted", "accepted", "processed", "paid", "closed"];
const labels = { submitted: "Sent", accepted: "Accepted", processed: "Processed", paid: "Payment posted", closed: "Closed" };

export default function App() {
  const [step, setStep] = useState("submitted");
  const index = steps.indexOf(step);
  const paid = step === "paid" || step === "closed" ? 2015 : 0;
  const state = step === "paid" ? "processed" : step;
  const data = useMemo(() => ({
    ...review,
    environment: "sandbox",
    bill: { ...review.bill, status: labels[step], totalPaid: paid, balanceDue: 2015 - paid },
    lifecycle: {
      state,
      nativeStatus: labels[step],
      submittedAt: "2026-08-31T16:08:00Z",
      agingDays: step === "closed" ? 18 : 4,
      updatedAt: "2026-09-04T14:30:00Z",
      actions: [],
    },
    eors: index >= 2 ? [{ id: "eor_1", filename: "EOR-1038.pdf", description: "Explanation of Review", addedAt: "2026-09-04T14:30:00Z", contentUrl: "#eor" }] : [],
    payments: paid ? [{ id: "payment_1", method: "check", checkNumber: "4811505", status: "deposited", amount: 2015, principalAmount: 2015, feeAmount: 0, feeReason: null, source: "paper", postedAt: "2026-09-06T12:15:00Z" }] : [],
    remittance: {
      billedAmount: 2015, expectedAmount: 2015,
      payerAllowedAmount: index >= 2 ? 2015 : null,
      payerReportedPaid: index >= 2 ? 2015 : null,
      postedPrincipal: paid, postedAdditional: 0,
      totalPostedCash: paid, balanceDue: 2015 - paid,
      denialReason: null,
    },
    delivery: { payerName: "Republic Indemnity", channel: "electronic", clearinghouse: "Jopari", contacts: {} },
    activity: [
      ...(step === "closed" ? [{ id: "evt_close", type: "bill.closed", createdAt: "2026-09-18T17:00:00Z", description: "Bill closed after payment was reconciled" }] : []),
      ...(paid ? [{ id: "evt_pay", type: "payment.posted", createdAt: "2026-09-06T12:15:00Z", description: "$2,015.00 payment posted" }] : []),
      ...(index >= 2 ? [{ id: "evt_eor", type: "eor.received", createdAt: "2026-09-04T14:30:00Z", description: "EOR received with full allowance" }] : []),
      ...(index >= 1 ? [{ id: "evt_accept", type: "bill.accepted", createdAt: "2026-09-01T09:16:00Z", description: "Claims administrator accepted the submission" }] : []),
      { id: "evt_submit", type: "bill.submitted", createdAt: "2026-08-31T16:08:00Z", description: "Electronically sent to Republic Indemnity" },
    ],
  }), [step, index, paid, state]);

  return <main className="journey-demo">
    <header>
      <div><small>Interactive sandbox journey</small><h1>Bill #1038</h1></div>
      <strong>{labels[step]}</strong>
    </header>
    <nav aria-label="Demo lifecycle controls">
      {steps.map((item) => <button key={item} className={item === step ? "active" : ""} onClick={() => setStep(item)}>{labels[item]}</button>)}
    </nav>
    <section className="journey-surfaces">
      <BillLifecycleProgress {...data.lifecycle} appearance={{ preset: "orange-bright" }} />
      <BillSnapshotSummary {...data} appearance={{ preset: "orange-bright" }} />
      {index >= 2 ? <BillExplanationOfReview remittance={data.remittance} eors={data.eors} payments={data.payments} submittedAt={data.lifecycle.submittedAt} onOpenEor={(eor) => alert("Preview " + eor.filename)} appearance={{ preset: "orange-bright" }} /> : null}
      <BillActivityTimeline events={data.activity} appearance={{ preset: "orange-bright" }} />
    </section>
  </main>;
}

Every lifecycle status

These presentational status surfaces cover the happy path and the action states your product needs to handle. “Sent” is the user-facing label for the API's immutable submitted state.

Lifecycle status gallerySeven synthetic states · edit and run
import { BillStatusSummary } from "@mindbill/react";

const states = [
  ["submitted", "Sent", 0, 2015],
  ["accepted", "Accepted", 0, 2015],
  ["processed", "Processed", 503.75, 1511.25],
  ["rejected", "Rejected", 0, 2015],
  ["denied", "Denied", 0, 2015],
  ["second_review", "Second review sent", 0, 2015],
  ["closed", "Closed", 2015, 0],
];

export default function App() {
  return <main className="gallery-demo">
    {states.map(([status, label, paid, balance]) => (
      <section key={status}>
        <span className="state-label">{label}</span>
        <BillStatusSummary
          status={status}
          submittedAt="2026-08-31T16:08:00Z"
          agingDays={status === "closed" ? 18 : 4}
          totalCharge={2015}
          totalPaid={paid}
          balanceDue={balance}
          appearance={{ preset: "orange-bright" }}
        />
      </section>
    ))}
  </main>;
}

Connect the real sandbox

Pass only the submitted billId and a short-lived browser session through getSession or sessionEndpoint. ConnectedBillLifecycle fetches the immutable bill snapshot, EOR, payments, actions, and history directly from MindBill. In the sandbox it also exposes controls for acceptance, processing, rejection, denial, and payment testing.