@mindbill/angular 0.2.1 → 0.4.0
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 +8 -8
- package/{dist/fesm2022 → fesm2022}/mindbill-angular.mjs +178 -35
- package/fesm2022/mindbill-angular.mjs.map +1 -0
- package/package.json +14 -6
- package/{dist/types → types}/mindbill-angular.d.ts +31 -13
- package/dist/README.md +0 -56
- package/dist/fesm2022/mindbill-angular.mjs.map +0 -1
- package/ng-package.json +0 -6
- package/src/lib/bill-lifecycle.component.ts +0 -378
- package/src/lib/lifecycle-store.ts +0 -109
- package/src/lib/procedure-lines.ts +0 -41
- package/src/public-api.ts +0 -20
- package/tsconfig.lib.json +0 -17
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Native Angular billing UI with built-in session renewal and lifecycle API calls.
|
|
|
6
6
|
npm install @mindbill/angular @mindbill/node
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Import the standalone component
|
|
9
|
+
Import the standalone component. Pass either an existing bill ID or the known values for a new bill.
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
12
|
import { Component } from "@angular/core";
|
|
@@ -18,9 +18,10 @@ import { MindBillBillLifecycleComponent } from "@mindbill/angular";
|
|
|
18
18
|
imports: [MindBillBillLifecycleComponent],
|
|
19
19
|
template: `
|
|
20
20
|
<mindbill-bill-lifecycle
|
|
21
|
-
[
|
|
22
|
-
sessionEndpoint="/api/mindbill/
|
|
21
|
+
[create]="knownBillValues"
|
|
22
|
+
sessionEndpoint="/api/mindbill/session"
|
|
23
23
|
[appearance]="{ preset: 'clinical-blue' }"
|
|
24
|
+
(billCreated)="rememberBill($event)"
|
|
24
25
|
(billIdChange)="billId = $event"
|
|
25
26
|
/>
|
|
26
27
|
`,
|
|
@@ -34,19 +35,18 @@ The component loads and refreshes status, searches the payer directory, saves bi
|
|
|
34
35
|
|
|
35
36
|
Procedure entry always keeps one empty row after the entered lines. Starting a code, modifier, or non-default unit count opens the next row automatically; the empty row is never included in save or submit payloads.
|
|
36
37
|
|
|
37
|
-
Add one authenticated server endpoint. It
|
|
38
|
+
Add one authenticated server endpoint. It maps the signed-in user's role to permissions and mints a short-lived token bound to your organization, that user, and the browser origin.
|
|
38
39
|
|
|
39
40
|
```ts
|
|
40
41
|
import { MindBillClient } from "@mindbill/node";
|
|
41
42
|
|
|
42
43
|
const mindbill = new MindBillClient({ apiKey: process.env["MINDBILL_API_KEY"]! });
|
|
43
44
|
|
|
44
|
-
app.post("/api/mindbill/
|
|
45
|
-
await requireBillAccess(req.user, req.body.billId);
|
|
45
|
+
app.post("/api/mindbill/session", requireUser, async (req, res) => {
|
|
46
46
|
const session = await mindbill.createBrowserSession({
|
|
47
|
-
|
|
48
|
-
billId: req.body.billId,
|
|
47
|
+
subject: req.user.id,
|
|
49
48
|
allowedOrigin: `${req.protocol}://${req.get("host")}`,
|
|
49
|
+
permissions: billingPermissionsFor(req.user.role),
|
|
50
50
|
expiresIn: 900,
|
|
51
51
|
});
|
|
52
52
|
res.json(session);
|
|
@@ -14,10 +14,14 @@ class MindBillLifecycleStore {
|
|
|
14
14
|
mutating = signal(false, ...(ngDevMode ? [{ debugName: "mutating" }] : /* istanbul ignore next */ []));
|
|
15
15
|
ready = computed(() => this.data() !== null && !this.loading(), ...(ngDevMode ? [{ debugName: "ready" }] : /* istanbul ignore next */ []));
|
|
16
16
|
client = null;
|
|
17
|
+
createInput;
|
|
18
|
+
onBillCreated;
|
|
17
19
|
refreshTimer = null;
|
|
18
|
-
connect(options, refreshInterval = 60_000) {
|
|
20
|
+
connect(options, refreshInterval = 60_000, createInput, onBillCreated) {
|
|
19
21
|
this.disconnect();
|
|
20
|
-
this.billId.set(options.billId);
|
|
22
|
+
this.billId.set(options.billId ?? "");
|
|
23
|
+
this.createInput = createInput;
|
|
24
|
+
this.onBillCreated = onBillCreated;
|
|
21
25
|
this.client = createBillLifecycleClient(options);
|
|
22
26
|
void this.refresh();
|
|
23
27
|
if (refreshInterval > 0) {
|
|
@@ -30,13 +34,29 @@ class MindBillLifecycleStore {
|
|
|
30
34
|
this.refreshTimer = null;
|
|
31
35
|
this.client?.clearSession();
|
|
32
36
|
this.client = null;
|
|
37
|
+
this.createInput = undefined;
|
|
38
|
+
this.onBillCreated = undefined;
|
|
33
39
|
}
|
|
34
40
|
async refresh() {
|
|
35
41
|
if (!this.client)
|
|
36
42
|
return null;
|
|
37
43
|
this.loading.set(this.data() === null);
|
|
38
44
|
try {
|
|
39
|
-
|
|
45
|
+
let data;
|
|
46
|
+
if (!this.client.getBillId()) {
|
|
47
|
+
if (!this.createInput) {
|
|
48
|
+
throw new Error("Pass billId to open a bill or create to start a new one.");
|
|
49
|
+
}
|
|
50
|
+
const created = await this.client.createBill(this.createInput);
|
|
51
|
+
const isNew = !this.billId();
|
|
52
|
+
this.billId.set(created.billId);
|
|
53
|
+
if (isNew)
|
|
54
|
+
this.onBillCreated?.(created.billId, created.data);
|
|
55
|
+
data = created.data;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
data = await this.client.getLifecycle();
|
|
59
|
+
}
|
|
40
60
|
this.data.set(data);
|
|
41
61
|
this.error.set(null);
|
|
42
62
|
return data;
|
|
@@ -148,17 +168,27 @@ const DOCUMENT_TYPES = [
|
|
|
148
168
|
];
|
|
149
169
|
class MindBillBillLifecycleComponent {
|
|
150
170
|
billId = "";
|
|
151
|
-
|
|
171
|
+
create;
|
|
172
|
+
sessionEndpoint = "/api/mindbill/session";
|
|
152
173
|
apiBaseUrl = "https://app.mindbill.org";
|
|
153
174
|
getSession;
|
|
154
175
|
refreshInterval = 60_000;
|
|
155
176
|
appearance = { preset: "mindbill" };
|
|
156
177
|
billIdChange = new EventEmitter();
|
|
178
|
+
billCreated = new EventEmitter();
|
|
157
179
|
submitted = new EventEmitter();
|
|
158
180
|
billingError = new EventEmitter();
|
|
159
181
|
store = new MindBillLifecycleStore();
|
|
160
182
|
documentTypes = DOCUMENT_TYPES;
|
|
161
183
|
medLegalCodes = ["ML200", "ML201", "ML202", "ML203", "ML204", "ML205", "ML206", "MLPRR"];
|
|
184
|
+
lifecycleStages = [
|
|
185
|
+
{ id: "created", label: "Created" },
|
|
186
|
+
{ id: "submitted", label: "Submitted" },
|
|
187
|
+
{ id: "accepted", label: "Accepted" },
|
|
188
|
+
{ id: "response", label: "Payer response" },
|
|
189
|
+
{ id: "follow_up", label: "Follow-up" },
|
|
190
|
+
{ id: "closed", label: "Closed" },
|
|
191
|
+
];
|
|
162
192
|
draft = null;
|
|
163
193
|
dirty = false;
|
|
164
194
|
payerQuery = "";
|
|
@@ -172,8 +202,9 @@ class MindBillBillLifecycleComponent {
|
|
|
172
202
|
panel = "";
|
|
173
203
|
notice = "";
|
|
174
204
|
closeReason = "";
|
|
175
|
-
payment = { amount: 0, method: "check", depositDate: new Date().toISOString().slice(0, 10) };
|
|
205
|
+
payment = { amount: 0, method: "check", checkNumber: "", depositDate: new Date().toISOString().slice(0, 10), note: "" };
|
|
176
206
|
review = { reason: "", payerClaimControlNumber: "", disputedAmount: 0 };
|
|
207
|
+
reviewAttachmentIds = [];
|
|
177
208
|
payerTimer = null;
|
|
178
209
|
constructor() {
|
|
179
210
|
effect(() => {
|
|
@@ -186,8 +217,20 @@ class MindBillBillLifecycleComponent {
|
|
|
186
217
|
});
|
|
187
218
|
}
|
|
188
219
|
ngOnChanges(changes) {
|
|
189
|
-
if (
|
|
190
|
-
|
|
220
|
+
if (changes["billId"] || changes["create"] || changes["sessionEndpoint"] || changes["apiBaseUrl"] || changes["getSession"]) {
|
|
221
|
+
if (!this.billId && !this.create) {
|
|
222
|
+
this.store.disconnect();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
this.store.connect({
|
|
226
|
+
...(this.billId ? { billId: this.billId } : {}),
|
|
227
|
+
sessionEndpoint: this.sessionEndpoint,
|
|
228
|
+
apiBaseUrl: this.apiBaseUrl,
|
|
229
|
+
...(this.getSession ? { getSession: this.getSession } : {}),
|
|
230
|
+
}, this.refreshInterval, this.create, (billId, data) => {
|
|
231
|
+
this.billIdChange.emit(billId);
|
|
232
|
+
this.billCreated.emit({ billId, data });
|
|
233
|
+
});
|
|
191
234
|
}
|
|
192
235
|
}
|
|
193
236
|
ngOnDestroy() { this.store.disconnect(); if (this.payerTimer)
|
|
@@ -209,6 +252,24 @@ class MindBillBillLifecycleComponent {
|
|
|
209
252
|
}
|
|
210
253
|
stateLabel(data) { return data.lifecycle.state.replace(/_/g, " ").replace(/\b\w/g, (value) => value.toUpperCase()); }
|
|
211
254
|
lifecycleDetail(data) { return data.lifecycle.submittedAt ? `Submitted ${new Date(data.lifecycle.submittedAt).toLocaleDateString()}${data.lifecycle.agingDays != null ? ` · ${data.lifecycle.agingDays} days old` : ""}` : "Review the prefilled bill and payer packet before submission."; }
|
|
255
|
+
currentStageIndex(data) {
|
|
256
|
+
const value = data.lifecycle.state.toLowerCase();
|
|
257
|
+
if (value.includes("closed") || value.includes("written_off"))
|
|
258
|
+
return 5;
|
|
259
|
+
if (value.includes("second_review") || value.includes("ibr") || value.includes("lien") || value.includes("appeal"))
|
|
260
|
+
return 4;
|
|
261
|
+
if (value.includes("processed") || value.includes("paid") || value.includes("denied") || value.includes("rejected") || value.includes("response"))
|
|
262
|
+
return 3;
|
|
263
|
+
if (value.includes("accepted"))
|
|
264
|
+
return 2;
|
|
265
|
+
if (value.includes("submitted") || value.includes("queued") || value.includes("sent"))
|
|
266
|
+
return 1;
|
|
267
|
+
return 0;
|
|
268
|
+
}
|
|
269
|
+
activityLabel(type) {
|
|
270
|
+
const labels = { "bill.created": "Bill created", "bill.submitted": "Bill submitted", "bill.accepted": "Bill accepted", "bill.rejected": "Bill rejected", "bill.denied": "Bill denied", "bill.partially_paid": "Partial payment received", "bill.paid": "Bill paid", "bill.second_review": "Second Bill Review submitted", "bill.ibr": "Independent Bill Review submitted", "bill.lien": "Bill moved to lien", "bill.closed": "Bill closed", "payment.posted": "Payment posted", "eor.received": "EOR received" };
|
|
271
|
+
return labels[type] ?? type.replace(/[._-]+/g, " ").replace(/\b\w/g, (value) => value.toUpperCase());
|
|
272
|
+
}
|
|
212
273
|
isEditable(data) { return data.lifecycle.actions.some((action) => action.id === "edit_and_submit" && action.enabled) || ["incomplete", "draft", "not_submitted"].includes(data.lifecycle.state.toLowerCase()); }
|
|
213
274
|
payerExplanation(payer) { return payer.signals?.map((signal) => signal.label).join(" · ") || (payer.hasElectronic ? "Electronic billing available" : "Available in payer directory"); }
|
|
214
275
|
queuePayerSearch() { if (this.payerTimer)
|
|
@@ -286,22 +347,51 @@ class MindBillBillLifecycleComponent {
|
|
|
286
347
|
}
|
|
287
348
|
async submit() { const input = this.buildInput(); if (!input || !this.canSubmit() || !this.deliveryReady())
|
|
288
349
|
return; const data = await this.store.submitBill(input, this.submission); this.showSubmit = false; this.dirty = false; this.draft = this.makeDraft(data); this.notice = "Bill submitted."; this.submitted.emit(data); }
|
|
289
|
-
beginAction(action) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
350
|
+
beginAction(action) {
|
|
351
|
+
const data = this.store.data();
|
|
352
|
+
if (action === "post_payment")
|
|
353
|
+
this.panel = "payment";
|
|
354
|
+
else if (action === "second_review" || action === "independent_bill_review") {
|
|
355
|
+
this.reviewAttachmentIds = data?.bill.attachments.map((doc) => doc.id) ?? [];
|
|
356
|
+
this.panel = "review";
|
|
357
|
+
}
|
|
358
|
+
else if (action === "close")
|
|
359
|
+
this.panel = "close";
|
|
360
|
+
else if (action === "view_eor" && data?.eors[0]) {
|
|
361
|
+
const eor = data.eors[0];
|
|
362
|
+
void this.openEor(eor.id, eor.filename);
|
|
363
|
+
}
|
|
364
|
+
else if (action === "correct_and_resubmit")
|
|
365
|
+
this.panel = "correction";
|
|
366
|
+
}
|
|
367
|
+
actionTitle() { return this.panel === "payment" ? "Post payment" : this.panel === "review" ? "Submit Second Review" : this.panel === "correction" ? "Correct and resubmit" : "Close bill"; }
|
|
368
|
+
toggleReviewAttachment(id) { this.reviewAttachmentIds = this.reviewAttachmentIds.includes(id) ? this.reviewAttachmentIds.filter((item) => item !== id) : [...this.reviewAttachmentIds, id]; }
|
|
369
|
+
async attachForReview() { if (!this.pendingFile)
|
|
370
|
+
return; const filename = this.pendingFile.name; await this.attach(); const attachment = this.store.data()?.bill.attachments.find((doc) => doc.filename === filename); if (attachment && !this.reviewAttachmentIds.includes(attachment.id))
|
|
371
|
+
this.reviewAttachmentIds = [...this.reviewAttachmentIds, attachment.id]; }
|
|
372
|
+
async correct() { const data = await this.store.startCorrection(); this.billIdChange.emit(this.store.billId()); this.dirty = false; this.draft = this.makeDraft(data); this.panel = ""; this.notice = "Correction ready for review."; }
|
|
373
|
+
async postPayment() {
|
|
374
|
+
await this.store.postPayment({
|
|
375
|
+
amount: this.payment.amount,
|
|
376
|
+
method: this.payment.method,
|
|
377
|
+
depositDate: this.payment.depositDate,
|
|
378
|
+
...(this.payment.checkNumber ? { checkNumber: this.payment.checkNumber } : {}),
|
|
379
|
+
...(this.payment.note ? { note: this.payment.note } : {}),
|
|
380
|
+
});
|
|
381
|
+
this.panel = "";
|
|
382
|
+
this.notice = "Payment posted.";
|
|
383
|
+
}
|
|
384
|
+
async submitReview() {
|
|
385
|
+
await this.store.submitSecondReview({
|
|
386
|
+
reason: this.review.reason,
|
|
387
|
+
payerClaimControlNumber: this.review.payerClaimControlNumber,
|
|
388
|
+
disputedAmount: this.review.disputedAmount > 0 ? this.review.disputedAmount : undefined,
|
|
389
|
+
route: "ebill",
|
|
390
|
+
attachmentIds: this.reviewAttachmentIds,
|
|
391
|
+
});
|
|
392
|
+
this.panel = "";
|
|
393
|
+
this.notice = "Second Review submitted.";
|
|
298
394
|
}
|
|
299
|
-
else if (action === "correct_and_resubmit")
|
|
300
|
-
void this.correct(); }
|
|
301
|
-
async correct() { const data = await this.store.startCorrection(); this.billIdChange.emit(this.store.billId()); this.dirty = false; this.draft = this.makeDraft(data); this.notice = "Correction draft created."; }
|
|
302
|
-
async postPayment() { await this.store.postPayment({ ...this.payment }); this.panel = ""; this.notice = "Payment posted."; }
|
|
303
|
-
async submitReview() { const data = this.store.data(); if (!data)
|
|
304
|
-
return; await this.store.submitSecondReview({ ...this.review, disputedAmount: this.review.disputedAmount || undefined, route: "ebill", attachmentIds: data.bill.attachments.map((doc) => doc.id) }); this.panel = ""; this.notice = "Second Review submitted."; }
|
|
305
395
|
async closeBill() { if (!this.closeReason.trim())
|
|
306
396
|
return; await this.store.closeBill({ reason: this.closeReason }); this.panel = ""; this.notice = "Bill closed."; }
|
|
307
397
|
buildInput() {
|
|
@@ -348,7 +438,7 @@ class MindBillBillLifecycleComponent {
|
|
|
348
438
|
this.draft.bill.lineItems = ensureTrailingProcedureLine(this.draft.bill.lineItems); }
|
|
349
439
|
openBlob(blob, filename) { const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.target = "_blank"; link.rel = "noopener"; link.download = filename; link.click(); setTimeout(() => URL.revokeObjectURL(url), 60_000); }
|
|
350
440
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillBillLifecycleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
351
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: MindBillBillLifecycleComponent, isStandalone: true, selector: "mindbill-bill-lifecycle", inputs: { billId: "billId", sessionEndpoint: "sessionEndpoint", apiBaseUrl: "apiBaseUrl", getSession: "getSession", refreshInterval: "refreshInterval", appearance: "appearance" }, outputs: { billIdChange: "billIdChange", submitted: "submitted", billingError: "billingError" }, usesOnChanges: true, ngImport: i0, template: `
|
|
441
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: MindBillBillLifecycleComponent, isStandalone: true, selector: "mindbill-bill-lifecycle", inputs: { billId: "billId", create: "create", sessionEndpoint: "sessionEndpoint", apiBaseUrl: "apiBaseUrl", getSession: "getSession", refreshInterval: "refreshInterval", appearance: "appearance" }, outputs: { billIdChange: "billIdChange", billCreated: "billCreated", submitted: "submitted", billingError: "billingError" }, usesOnChanges: true, ngImport: i0, template: `
|
|
352
442
|
<section class="mb" [ngStyle]="themeStyle">
|
|
353
443
|
@if (store.loading() && !store.data()) {
|
|
354
444
|
<div class="state">Loading billing…</div>
|
|
@@ -360,6 +450,16 @@ class MindBillBillLifecycleComponent {
|
|
|
360
450
|
<div class="money"><span>{{ data.bill.balanceDue | currency }}</span><small>balance</small></div>
|
|
361
451
|
</header>
|
|
362
452
|
|
|
453
|
+
<section class="card progress" aria-label="Bill lifecycle">
|
|
454
|
+
<div class="card-title"><div><h3>Bill status</h3><p>{{ lifecycleDetail(data) }}</p></div><span>{{ stateLabel(data) }}</span></div>
|
|
455
|
+
<ol>@for (stage of lifecycleStages; track stage.id; let i=$index) { <li [class.complete]="i < currentStageIndex(data)" [class.current]="i === currentStageIndex(data)" [attr.aria-current]="i === currentStageIndex(data) ? 'step' : null"><b>{{ i < currentStageIndex(data) ? '✓' : i + 1 }}</b><span>{{ stage.label }}</span></li> }</ol>
|
|
456
|
+
</section>
|
|
457
|
+
|
|
458
|
+
<section class="card snapshot" aria-label="Bill snapshot">
|
|
459
|
+
<div class="card-title"><div><h3>Bill snapshot</h3><p>The claim and financial values currently recorded on this bill.</p></div></div>
|
|
460
|
+
<dl><div><dt>Patient</dt><dd>{{ data.patient.name }}</dd></div><div><dt>Claim</dt><dd>{{ data.injury.claimNumber || '—' }}</dd></div><div><dt>Payer</dt><dd>{{ data.delivery.payerName || data.injury.claimsAdminName || '—' }}</dd></div><div><dt>Date of service</dt><dd>{{ data.bill.dos || '—' }}</dd></div><div><dt>Charged</dt><dd>{{ data.bill.totalCharge | currency }}</dd></div><div><dt>Balance</dt><dd>{{ data.bill.balanceDue | currency }}</dd></div></dl>
|
|
461
|
+
</section>
|
|
462
|
+
|
|
363
463
|
@if (isEditable(data) && draft) {
|
|
364
464
|
<form class="review" (submit)="$event.preventDefault(); submit()">
|
|
365
465
|
<section class="card">
|
|
@@ -465,12 +565,27 @@ class MindBillBillLifecycleComponent {
|
|
|
465
565
|
} @else {
|
|
466
566
|
<section class="card lifecycle">
|
|
467
567
|
<div class="card-title"><div><h3>Billing activity</h3><p>Available actions change automatically with bill status.</p></div><button (click)="store.refresh()">Refresh</button></div>
|
|
468
|
-
|
|
568
|
+
<div class="lifecycle-grid">
|
|
569
|
+
<section><h4>Remittance</h4><dl class="facts"><div><dt>Payer reported</dt><dd>{{ data.remittance.payerReportedPaid == null ? '—' : (data.remittance.payerReportedPaid | currency) }}</dd></div><div><dt>Posted</dt><dd>{{ data.remittance.totalPaid | currency }}</dd></div><div><dt>Balance</dt><dd>{{ data.remittance.balanceDue | currency }}</dd></div></dl>@if (data.remittance.denialReason) { <div class="denial"><strong>Denial reason</strong><p>{{ data.remittance.denialReason }}</p></div> }</section>
|
|
570
|
+
<section><h4>{{ data.delivery.payerName || 'Claims administrator' }}</h4><dl class="contacts">@if (data.delivery.contacts.adjusterName) { <div><dt>Adjuster</dt><dd>{{ data.delivery.contacts.adjusterName }}</dd></div> }@if (data.delivery.contacts.adjusterPhone) { <div><dt>Phone</dt><dd><a [href]="'tel:'+data.delivery.contacts.adjusterPhone">{{ data.delivery.contacts.adjusterPhone }}</a></dd></div> }@if (data.delivery.contacts.adjusterEmail) { <div><dt>Adjuster email</dt><dd><a [href]="'mailto:'+data.delivery.contacts.adjusterEmail">{{ data.delivery.contacts.adjusterEmail }}</a></dd></div> }@if (data.delivery.contacts.faxNumber) { <div><dt>Fax</dt><dd><a [href]="'tel:'+data.delivery.contacts.faxNumber">{{ data.delivery.contacts.faxNumber }}</a></dd></div> }@if (data.delivery.contacts.claimsEmail) { <div><dt>Claims email</dt><dd><a [href]="'mailto:'+data.delivery.contacts.claimsEmail">{{ data.delivery.contacts.claimsEmail }}</a></dd></div> }@if (data.delivery.contacts.mailingAddress) { <div><dt>Mail</dt><dd>{{ data.delivery.contacts.mailingAddress }}</dd></div> }@if (data.delivery.contacts.portalUrl) { <div><dt>Portal</dt><dd><a [href]="data.delivery.contacts.portalUrl" target="_blank" rel="noopener">Open payer portal</a></dd></div> }</dl></section>
|
|
571
|
+
</div>
|
|
572
|
+
@if (data.eors.length) { <div class="eors"><h4>Explanation of Review</h4><p>Payer response details and the original returned document.</p>@for (eor of data.eors; track eor.id) { <button (click)="openEor(eor.id,eor.filename)"><span><strong>{{ eor.filename }}</strong><small>{{ eor.description || 'Payer response' }}</small></span><b>View original PDF</b></button> }</div> }
|
|
573
|
+
<section class="payments"><h4>Payments</h4>@if (!data.payments.length) { <p>No payments posted.</p> } @else { @for (paymentItem of data.payments; track paymentItem.id) { <article><div><strong>{{ paymentItem.amount | currency }}</strong><span>{{ paymentItem.method | uppercase }} · {{ paymentItem.status }}</span></div><div><span>{{ paymentItem.checkNumber ? '#'+paymentItem.checkNumber : paymentItem.source }}</span><span>{{ paymentItem.depositDate || (paymentItem.postedAt | date:'mediumDate') }}</span></div>@if (paymentItem.note) { <p>{{ paymentItem.note }}</p> }</article> } }</section>
|
|
574
|
+
<section class="history"><h4>Bill history</h4>@if (!data.activity.length) { <p>No bill activity yet.</p> } @else { <ol>@for (event of data.activity; track event.id) { <li><span></span><div><strong>{{ activityLabel(event.type) }}</strong><small>{{ event.createdAt | date:'medium' }}{{ event.actor ? ' · '+event.actor : '' }}</small>@if (event.description) { <p>{{ event.description }}</p> }</div></li> }</ol> }</section>
|
|
469
575
|
<div class="actionbar">@for (action of data.lifecycle.actions; track action.id) { @if (action.enabled) { <button [class.primary]="action.primary" (click)="beginAction(action.id)">{{ action.label }}</button> } }</div>
|
|
470
|
-
@if (panel === 'payment') { <div class="panel"><h4>Post payment</h4><div class="grid three"><label><span>Amount</span><input type="number" min="0.01" [(ngModel)]="payment.amount"></label><label><span>Method</span><select [(ngModel)]="payment.method"><option value="check">Check</option><option value="eft">EFT</option></select></label><label><span>Deposit date</span><input type="date" [(ngModel)]="payment.depositDate"></label></div><div class="actions"><button (click)="panel=''">Cancel</button><button class="primary" (click)="postPayment()">Post payment</button></div></div> }
|
|
471
|
-
@if (panel === 'review') { <div class="panel"><h4>Submit Second Review</h4><label><span>Reason</span><textarea [(ngModel)]="review.reason"></textarea></label><div class="grid two"><label><span>Payer control number</span><input [(ngModel)]="review.payerClaimControlNumber"></label><label><span>Disputed amount</span><input type="number" [(ngModel)]="review.disputedAmount"></label></div><div class="actions"><button (click)="panel=''">Cancel</button><button class="primary" (click)="submitReview()">Submit review</button></div></div> }
|
|
472
|
-
@if (panel === 'close') { <div class="panel"><h4>Close bill</h4><label><span>Reason</span><textarea [(ngModel)]="closeReason"></textarea></label><div class="actions"><button (click)="panel=''">Cancel</button><button class="danger" (click)="closeBill()">Close bill</button></div></div> }
|
|
473
576
|
</section>
|
|
577
|
+
@if (panel) {
|
|
578
|
+
<div class="modal-backdrop" (click)="panel=''">
|
|
579
|
+
<section class="submit-modal action-modal" role="dialog" aria-modal="true" (click)="$event.stopPropagation()">
|
|
580
|
+
<header><div><span class="eyebrow">Bill {{ data.bill.billNumber }}</span><h3>{{ actionTitle() }}</h3></div><button class="close" type="button" (click)="panel=''" aria-label="Close">×</button></header>
|
|
581
|
+
@if (panel === 'payment') { <p>Record funds received for this bill. This updates the payment ledger and remaining balance.</p><div class="grid two"><label><span>Amount</span><input type="number" min="0.01" [(ngModel)]="payment.amount"></label><label><span>Method</span><select [(ngModel)]="payment.method"><option value="check">Check</option><option value="eft">EFT</option></select></label><label><span>Check / EFT number</span><input [(ngModel)]="payment.checkNumber"></label><label><span>Deposit date</span><input type="date" [(ngModel)]="payment.depositDate"></label></div><label><span>Note (optional)</span><input [(ngModel)]="payment.note"></label> }
|
|
582
|
+
@if (panel === 'review') { <p>Explain the dispute and choose the exact payer documents to include with the Second Review.</p><label><span>Reason for Second Review</span><textarea [(ngModel)]="review.reason"></textarea></label><div class="grid two"><label><span>Payer control number</span><input [(ngModel)]="review.payerClaimControlNumber"></label><label><span>Disputed amount</span><input type="number" [(ngModel)]="review.disputedAmount"></label></div><fieldset class="review-docs"><legend>Supporting documents</legend>@for (doc of data.bill.attachments; track doc.id) { <label><input type="checkbox" [checked]="reviewAttachmentIds.includes(doc.id)" (change)="toggleReviewAttachment(doc.id)"><span><strong>{{ doc.filename }}</strong><small>{{ doc.description || doc.documentType }}</small></span></label> }</fieldset><div class="upload"><select [(ngModel)]="documentType">@for (type of documentTypes; track type.value) { <option [value]="type.value">{{ type.label }}</option> }</select><input type="file" accept="application/pdf" (change)="fileSelected($event)"><button type="button" [disabled]="!pendingFile || store.mutating()" (click)="attachForReview()">Add document</button></div> }
|
|
583
|
+
@if (panel === 'correction') { <p>Create a replacement bill prefilled from this rejected submission. You can correct the payer, claim, provider, service lines, and packet before resubmitting.</p> }
|
|
584
|
+
@if (panel === 'close') { <p>Closing stops active follow-up. The bill history and documents remain available.</p><label><span>Reason</span><textarea [(ngModel)]="closeReason"></textarea></label> }
|
|
585
|
+
<footer><button type="button" (click)="panel=''">Cancel</button>@if (panel === 'payment') { <button class="primary" type="button" (click)="postPayment()" [disabled]="store.mutating() || payment.amount <= 0">Post payment</button> }@if (panel === 'review') { <button class="primary" type="button" (click)="submitReview()" [disabled]="store.mutating() || !review.reason.trim() || !review.payerClaimControlNumber.trim()">Submit Second Review</button> }@if (panel === 'correction') { <button class="primary" type="button" (click)="correct()" [disabled]="store.mutating()">Create correction</button> }@if (panel === 'close') { <button class="danger" type="button" (click)="closeBill()" [disabled]="store.mutating() || !closeReason.trim()">Close bill</button> }</footer>
|
|
586
|
+
</section>
|
|
587
|
+
</div>
|
|
588
|
+
}
|
|
474
589
|
}
|
|
475
590
|
@if (notice) { <div class="notice">{{ notice }}</div> }
|
|
476
591
|
@if (store.error()) { <div class="notice error">{{ store.error()?.message }}</div> }
|
|
@@ -478,7 +593,7 @@ class MindBillBillLifecycleComponent {
|
|
|
478
593
|
}
|
|
479
594
|
<datalist id="mb-states"><option value="CA"></option><option value="AZ"></option><option value="NV"></option><option value="OR"></option><option value="WA"></option><option value="TX"></option><option value="NY"></option></datalist>
|
|
480
595
|
</section>
|
|
481
|
-
`, isInline: true, styles: [":host{display:block}.mb{--a:#238dbd;--ac:#fff;--bg:#f3f8fa;--s:#fff;--t:#203743;--m:#657982;--b:#dbe6ea;--r:12px;--cr:8px;display:grid;gap:16px;color:var(--t);font:14px/1.45 var(--font,Inter,system-ui,sans-serif)}*{box-sizing:border-box}h2,h3,h4,p{margin:0}.summary,.card,.delivery,.state{border:1px solid var(--b);border-radius:var(--r);background:var(--s)}.summary{display:flex;justify-content:space-between;gap:20px;padding:20px}.summary h2{font-size:24px}.summary p,.card p,.delivery p,small{color:var(--m)}.eyebrow{color:var(--m);font-size:11px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}.money{text-align:right}.money span{display:block;font-size:28px;font-weight:800}.money small{font-size:12px}.review{display:grid;gap:16px}.card{padding:20px}.card-title{display:flex;align-items:start;justify-content:space-between;gap:16px;margin-bottom:18px}.card-title h3,.delivery h3{font-size:18px}.card-title>span{border-radius:999px;background:var(--bg);padding:5px 9px;color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.grid{display:grid;gap:14px}.grid.four{grid-template-columns:repeat(4,minmax(0,1fr))}.grid.three{grid-template-columns:repeat(3,minmax(0,1fr))}.grid.two{grid-template-columns:repeat(2,minmax(0,1fr))}label{display:grid;gap:6px;color:var(--t);font-size:12px;font-weight:700}input,select,textarea,button{font:inherit}input,select,textarea{width:100%;min-height:42px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;color:var(--t);padding:9px 11px}textarea{min-height:90px;resize:vertical}button{min-height:38px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;color:var(--t);padding:8px 13px;cursor:pointer;font-weight:700}button.primary{border-color:var(--a);background:var(--a);color:var(--ac)}button.danger{border-color:#d4380d;background:#d4380d;color:#fff}button:disabled{cursor:not-allowed;opacity:.5}.subhead{margin:18px 0 9px;border-top:1px solid var(--b);padding-top:15px;font-size:12px;font-weight:800}.selected{display:flex;align-items:center;justify-content:space-between;border:1px solid var(--b);border-radius:var(--cr);padding:12px}.selected div{display:grid}.results{position:relative;z-index:3;display:grid;margin-top:5px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;box-shadow:0 12px 30px #1f2d3d1f;overflow:hidden}.results button{display:grid;gap:2px;text-align:left;border:0;border-bottom:1px solid var(--b);border-radius:0;padding:12px}.results span{color:var(--m);font-weight:400}.presets{display:flex;gap:8px;margin:-4px 0 12px}.lines{display:grid;gap:10px}.line{display:grid;grid-template-columns:1.2fr 1.2fr 110px 120px 40px;align-items:end;gap:10px;border-radius:var(--cr);background:var(--bg);padding:12px}.line.professional{grid-template-columns:1.1fr 1fr 1fr 1fr 110px 1fr 90px 110px 40px}.allowed{display:grid;gap:7px;text-align:right}.allowed span{color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.allowed strong{font-size:17px}.remove{border:0;background:transparent;font-size:20px}.docs{list-style:none;margin:0;padding:0}.docs li{display:flex;align-items:center;gap:8px;border-top:1px solid var(--b);padding:11px 0}.docs li>div{display:grid;flex:1}.upload{display:grid;grid-template-columns:240px 1fr auto;gap:10px;margin-top:12px;border-radius:var(--cr);background:var(--bg);padding:12px}.delivery{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:20px;background:color-mix(in srgb,var(--a) 5%,white)}.actions,.actionbar{display:flex;justify-content:flex-end;gap:8px}.lifecycle{display:grid;gap:16px}.actionbar{flex-wrap:wrap}.eors{display:grid;gap:8px}.eors>button{display:flex;align-items:center;justify-content:space-between;text-align:left}.eors span{display:grid}.panel{display:grid;gap:14px;border-top:1px solid var(--b);padding-top:16px}.notice,.state{padding:13px 15px}.notice{border-radius:var(--cr);background:#edf8f2;color:#23734c}.notice.error,.state.error{background:#fff2f0;color:#b42318}.state{display:grid;gap:10px}.state button{justify-self:start}.powered{text-align:right;color:var(--m);font-size:11px}.modal-backdrop{position:fixed;z-index:1000;inset:0;display:grid;place-items:center;background:#0f20288f;padding:20px}.submit-modal{display:grid;gap:18px;width:min(680px,100%);max-height:calc(100vh - 40px);overflow:auto;border:1px solid var(--b);border-radius:var(--r);background:var(--s);padding:22px;box-shadow:0 24px 80px #0f202847}.submit-modal>header,.submit-modal>footer{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}.submit-modal>footer{justify-content:flex-end}.submit-modal .close{border:0;background:transparent;font-size:26px}.route-list{display:grid;gap:8px}.route-option{display:grid;grid-template-columns:20px 1fr auto;align-items:center;gap:12px;text-align:left;padding:13px}.route-option>span:nth-child(2){display:grid}.route-option.selected{border-color:var(--a);box-shadow:0 0 0 2px color-mix(in srgb,var(--a) 18%,transparent)}.route-option .radio{width:16px;height:16px;border:2px solid var(--b);border-radius:50%}.route-option.selected .radio{border:5px solid var(--a)}.route-option b{color:var(--a);font-size:11px;text-transform:uppercase}@media(max-width:1100px){.line.professional{grid-template-columns:repeat(3,minmax(0,1fr))}.line.professional .allowed{grid-column:auto}}@media(max-width:900px){.grid.four,.grid.three{grid-template-columns:repeat(2,minmax(0,1fr))}.line{grid-template-columns:1fr 1fr 90px}.allowed{grid-column:1/-2;text-align:left}.upload{grid-template-columns:1fr}.delivery{align-items:stretch;flex-direction:column}.actions{justify-content:flex-start}}@media(max-width:600px){.summary,.card-title{align-items:stretch;flex-direction:column}.money{text-align:left}.grid.four,.grid.three,.grid.two,.line,.line.professional{grid-template-columns:1fr}.allowed{grid-column:auto}.docs li{align-items:flex-start;flex-wrap:wrap}.modal-backdrop{padding:8px}.submit-modal{max-height:calc(100vh - 16px);padding:16px}.route-option{grid-template-columns:20px 1fr}.route-option b{grid-column:2}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1.CurrencyPipe, name: "currency" }] });
|
|
596
|
+
`, isInline: true, styles: [":host{display:block}.mb{--a:#238dbd;--ac:#fff;--bg:#f3f8fa;--s:#fff;--t:#203743;--m:#657982;--b:#dbe6ea;--r:12px;--cr:8px;display:grid;gap:16px;color:var(--t);font:14px/1.45 var(--font,Inter,system-ui,sans-serif)}*{box-sizing:border-box}h2,h3,h4,p{margin:0}a{color:var(--a)}.summary,.card,.delivery,.state{border:1px solid var(--b);border-radius:var(--r);background:var(--s)}.summary{display:flex;justify-content:space-between;gap:20px;padding:20px}.summary h2{font-size:24px}.summary p,.card p,.delivery p,small{color:var(--m)}.eyebrow{color:var(--m);font-size:11px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}.money{text-align:right}.money span{display:block;font-size:28px;font-weight:800}.money small{font-size:12px}.review{display:grid;gap:16px}.card{padding:20px}.card-title{display:flex;align-items:start;justify-content:space-between;gap:16px;margin-bottom:18px}.card-title h3,.delivery h3{font-size:18px}.card-title>span{border-radius:999px;background:var(--bg);padding:5px 9px;color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.grid{display:grid;gap:14px}.grid.four{grid-template-columns:repeat(4,minmax(0,1fr))}.grid.three{grid-template-columns:repeat(3,minmax(0,1fr))}.grid.two{grid-template-columns:repeat(2,minmax(0,1fr))}label{display:grid;gap:6px;color:var(--t);font-size:12px;font-weight:700}input,select,textarea,button{font:inherit}input,select,textarea{width:100%;min-height:42px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;color:var(--t);padding:9px 11px}textarea{min-height:90px;resize:vertical}button{min-height:38px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;color:var(--t);padding:8px 13px;cursor:pointer;font-weight:700}button.primary{border-color:var(--a);background:var(--a);color:var(--ac)}button.danger{border-color:#d4380d;background:#d4380d;color:#fff}button:disabled{cursor:not-allowed;opacity:.5}.subhead{margin:18px 0 9px;border-top:1px solid var(--b);padding-top:15px;font-size:12px;font-weight:800}.selected{display:flex;align-items:center;justify-content:space-between;border:1px solid var(--b);border-radius:var(--cr);padding:12px}.selected div{display:grid}.results{position:relative;z-index:3;display:grid;margin-top:5px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;box-shadow:0 12px 30px #1f2d3d1f;overflow:hidden}.results button{display:grid;gap:2px;text-align:left;border:0;border-bottom:1px solid var(--b);border-radius:0;padding:12px}.results span{color:var(--m);font-weight:400}.presets{display:flex;gap:8px;margin:-4px 0 12px}.lines{display:grid;gap:10px}.line{display:grid;grid-template-columns:1.2fr 1.2fr 110px 120px 40px;align-items:end;gap:10px;border-radius:var(--cr);background:var(--bg);padding:12px}.line.professional{grid-template-columns:1.1fr 1fr 1fr 1fr 110px 1fr 90px 110px 40px}.allowed{display:grid;gap:7px;text-align:right}.allowed span{color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.allowed strong{font-size:17px}.remove{border:0;background:transparent;font-size:20px}.docs{list-style:none;margin:0;padding:0}.docs li{display:flex;align-items:center;gap:8px;border-top:1px solid var(--b);padding:11px 0}.docs li>div{display:grid;flex:1}.upload{display:grid;grid-template-columns:240px 1fr auto;gap:10px;margin-top:12px;border-radius:var(--cr);background:var(--bg);padding:12px}.delivery{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:20px;background:color-mix(in srgb,var(--a) 5%,white)}.actions,.actionbar{display:flex;justify-content:flex-end;gap:8px}.progress ol{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));list-style:none;margin:0;padding:0}.progress li{position:relative;display:grid;justify-items:center;gap:7px;color:var(--m);font-size:12px;text-align:center}.progress li:before{content:\"\";position:absolute;top:14px;right:50%;left:-50%;height:2px;background:var(--b)}.progress li:first-child:before{display:none}.progress li b{position:relative;z-index:1;display:grid;place-items:center;width:28px;height:28px;border:2px solid var(--b);border-radius:50%;background:var(--s)}.progress li.complete,.progress li.current{color:var(--t)}.progress li.complete:before,.progress li.current:before{background:var(--a)}.progress li.complete b,.progress li.current b{border-color:var(--a);background:var(--a);color:var(--ac)}.snapshot dl,.facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));margin:0}.snapshot dl>div,.facts>div{display:grid;gap:3px;border-right:1px solid var(--b);padding:4px 14px}.snapshot dl>div:nth-child(3n),.facts>div:last-child{border-right:0}.snapshot dt,.facts dt,.contacts dt{color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.snapshot dd,.facts dd,.contacts dd{margin:0;font-weight:700}.lifecycle{display:grid;gap:20px}.actionbar{flex-wrap:wrap;border-top:1px solid var(--b);padding-top:18px}.lifecycle-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}.lifecycle-grid>section,.payments,.history,.eors{display:grid;gap:11px;border:1px solid var(--b);border-radius:var(--cr);padding:15px}.contacts{display:grid;gap:9px;margin:0}.contacts>div{display:grid;grid-template-columns:70px 1fr;gap:10px}.denial{border-radius:var(--cr);background:#fff4ed;padding:11px}.eors>button{display:flex;align-items:center;justify-content:space-between;text-align:left}.eors span{display:grid}.payments article{display:grid;grid-template-columns:1fr auto;gap:4px;border-top:1px solid var(--b);padding-top:10px}.payments article>div{display:grid}.payments article>div:last-of-type{text-align:right}.payments article p{grid-column:1/-1}.history ol{display:grid;gap:0;list-style:none;margin:0;padding:0}.history li{display:grid;grid-template-columns:18px 1fr;gap:9px}.history li>span{position:relative;margin-top:5px;width:10px;height:10px;border-radius:50%;background:var(--a)}.history li>span:after{content:\"\";position:absolute;top:10px;bottom:-30px;left:4px;width:2px;background:var(--b)}.history li:last-child>span:after{display:none}.history li>div{display:grid;gap:2px;padding-bottom:15px}.notice,.state{padding:13px 15px}.notice{border-radius:var(--cr);background:#edf8f2;color:#23734c}.notice.error,.state.error{background:#fff2f0;color:#b42318}.state{display:grid;gap:10px}.state button{justify-self:start}.powered{text-align:right;color:var(--m);font-size:11px}.modal-backdrop{position:fixed;z-index:1000;inset:0;display:grid;place-items:center;background:#0f20288f;padding:20px}.submit-modal{display:grid;gap:18px;width:min(680px,100%);max-height:calc(100vh - 40px);overflow:auto;border:1px solid var(--b);border-radius:var(--r);background:var(--s);padding:22px;box-shadow:0 24px 80px #0f202847}.submit-modal>header,.submit-modal>footer{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}.submit-modal>footer{justify-content:flex-end}.submit-modal .close{border:0;background:transparent;font-size:26px}.route-list{display:grid;gap:8px}.route-option{display:grid;grid-template-columns:20px 1fr auto;align-items:center;gap:12px;text-align:left;padding:13px}.route-option>span:nth-child(2){display:grid}.route-option.selected{border-color:var(--a);box-shadow:0 0 0 2px color-mix(in srgb,var(--a) 18%,transparent)}.route-option .radio{width:16px;height:16px;border:2px solid var(--b);border-radius:50%}.route-option.selected .radio{border:5px solid var(--a)}.route-option b{color:var(--a);font-size:11px;text-transform:uppercase}.action-modal{width:min(720px,100%)}.review-docs{display:grid;gap:8px;border:1px solid var(--b);border-radius:var(--cr);padding:12px}.review-docs label{display:grid;grid-template-columns:20px 1fr;align-items:start}.review-docs input{min-height:auto}.review-docs label>span{display:grid}@media(max-width:1100px){.line.professional{grid-template-columns:repeat(3,minmax(0,1fr))}.line.professional .allowed{grid-column:auto}}@media(max-width:900px){.grid.four,.grid.three{grid-template-columns:repeat(2,minmax(0,1fr))}.line{grid-template-columns:1fr 1fr 90px}.allowed{grid-column:1/-2;text-align:left}.upload{grid-template-columns:1fr}.delivery{align-items:stretch;flex-direction:column}.actions{justify-content:flex-start}.lifecycle-grid{grid-template-columns:1fr}}@media(max-width:600px){.summary,.card-title{align-items:stretch;flex-direction:column}.money{text-align:left}.grid.four,.grid.three,.grid.two,.line,.line.professional{grid-template-columns:1fr}.allowed{grid-column:auto}.docs li{align-items:flex-start;flex-wrap:wrap}.progress{overflow-x:auto}.progress ol{min-width:560px}.snapshot dl,.facts{grid-template-columns:1fr}.snapshot dl>div,.facts>div{border-right:0;border-bottom:1px solid var(--b);padding:10px 0}.snapshot dl>div:last-child,.facts>div:last-child{border-bottom:0}.modal-backdrop{align-items:end;padding:0}.submit-modal{max-height:92vh;border-radius:var(--r) var(--r) 0 0;padding:16px}.route-option{grid-template-columns:20px 1fr}.route-option b{grid-column:2}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i1.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i1.DatePipe, name: "date" }] });
|
|
482
597
|
}
|
|
483
598
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillBillLifecycleComponent, decorators: [{
|
|
484
599
|
type: Component,
|
|
@@ -494,6 +609,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
|
|
|
494
609
|
<div class="money"><span>{{ data.bill.balanceDue | currency }}</span><small>balance</small></div>
|
|
495
610
|
</header>
|
|
496
611
|
|
|
612
|
+
<section class="card progress" aria-label="Bill lifecycle">
|
|
613
|
+
<div class="card-title"><div><h3>Bill status</h3><p>{{ lifecycleDetail(data) }}</p></div><span>{{ stateLabel(data) }}</span></div>
|
|
614
|
+
<ol>@for (stage of lifecycleStages; track stage.id; let i=$index) { <li [class.complete]="i < currentStageIndex(data)" [class.current]="i === currentStageIndex(data)" [attr.aria-current]="i === currentStageIndex(data) ? 'step' : null"><b>{{ i < currentStageIndex(data) ? '✓' : i + 1 }}</b><span>{{ stage.label }}</span></li> }</ol>
|
|
615
|
+
</section>
|
|
616
|
+
|
|
617
|
+
<section class="card snapshot" aria-label="Bill snapshot">
|
|
618
|
+
<div class="card-title"><div><h3>Bill snapshot</h3><p>The claim and financial values currently recorded on this bill.</p></div></div>
|
|
619
|
+
<dl><div><dt>Patient</dt><dd>{{ data.patient.name }}</dd></div><div><dt>Claim</dt><dd>{{ data.injury.claimNumber || '—' }}</dd></div><div><dt>Payer</dt><dd>{{ data.delivery.payerName || data.injury.claimsAdminName || '—' }}</dd></div><div><dt>Date of service</dt><dd>{{ data.bill.dos || '—' }}</dd></div><div><dt>Charged</dt><dd>{{ data.bill.totalCharge | currency }}</dd></div><div><dt>Balance</dt><dd>{{ data.bill.balanceDue | currency }}</dd></div></dl>
|
|
620
|
+
</section>
|
|
621
|
+
|
|
497
622
|
@if (isEditable(data) && draft) {
|
|
498
623
|
<form class="review" (submit)="$event.preventDefault(); submit()">
|
|
499
624
|
<section class="card">
|
|
@@ -599,12 +724,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
|
|
|
599
724
|
} @else {
|
|
600
725
|
<section class="card lifecycle">
|
|
601
726
|
<div class="card-title"><div><h3>Billing activity</h3><p>Available actions change automatically with bill status.</p></div><button (click)="store.refresh()">Refresh</button></div>
|
|
602
|
-
|
|
727
|
+
<div class="lifecycle-grid">
|
|
728
|
+
<section><h4>Remittance</h4><dl class="facts"><div><dt>Payer reported</dt><dd>{{ data.remittance.payerReportedPaid == null ? '—' : (data.remittance.payerReportedPaid | currency) }}</dd></div><div><dt>Posted</dt><dd>{{ data.remittance.totalPaid | currency }}</dd></div><div><dt>Balance</dt><dd>{{ data.remittance.balanceDue | currency }}</dd></div></dl>@if (data.remittance.denialReason) { <div class="denial"><strong>Denial reason</strong><p>{{ data.remittance.denialReason }}</p></div> }</section>
|
|
729
|
+
<section><h4>{{ data.delivery.payerName || 'Claims administrator' }}</h4><dl class="contacts">@if (data.delivery.contacts.adjusterName) { <div><dt>Adjuster</dt><dd>{{ data.delivery.contacts.adjusterName }}</dd></div> }@if (data.delivery.contacts.adjusterPhone) { <div><dt>Phone</dt><dd><a [href]="'tel:'+data.delivery.contacts.adjusterPhone">{{ data.delivery.contacts.adjusterPhone }}</a></dd></div> }@if (data.delivery.contacts.adjusterEmail) { <div><dt>Adjuster email</dt><dd><a [href]="'mailto:'+data.delivery.contacts.adjusterEmail">{{ data.delivery.contacts.adjusterEmail }}</a></dd></div> }@if (data.delivery.contacts.faxNumber) { <div><dt>Fax</dt><dd><a [href]="'tel:'+data.delivery.contacts.faxNumber">{{ data.delivery.contacts.faxNumber }}</a></dd></div> }@if (data.delivery.contacts.claimsEmail) { <div><dt>Claims email</dt><dd><a [href]="'mailto:'+data.delivery.contacts.claimsEmail">{{ data.delivery.contacts.claimsEmail }}</a></dd></div> }@if (data.delivery.contacts.mailingAddress) { <div><dt>Mail</dt><dd>{{ data.delivery.contacts.mailingAddress }}</dd></div> }@if (data.delivery.contacts.portalUrl) { <div><dt>Portal</dt><dd><a [href]="data.delivery.contacts.portalUrl" target="_blank" rel="noopener">Open payer portal</a></dd></div> }</dl></section>
|
|
730
|
+
</div>
|
|
731
|
+
@if (data.eors.length) { <div class="eors"><h4>Explanation of Review</h4><p>Payer response details and the original returned document.</p>@for (eor of data.eors; track eor.id) { <button (click)="openEor(eor.id,eor.filename)"><span><strong>{{ eor.filename }}</strong><small>{{ eor.description || 'Payer response' }}</small></span><b>View original PDF</b></button> }</div> }
|
|
732
|
+
<section class="payments"><h4>Payments</h4>@if (!data.payments.length) { <p>No payments posted.</p> } @else { @for (paymentItem of data.payments; track paymentItem.id) { <article><div><strong>{{ paymentItem.amount | currency }}</strong><span>{{ paymentItem.method | uppercase }} · {{ paymentItem.status }}</span></div><div><span>{{ paymentItem.checkNumber ? '#'+paymentItem.checkNumber : paymentItem.source }}</span><span>{{ paymentItem.depositDate || (paymentItem.postedAt | date:'mediumDate') }}</span></div>@if (paymentItem.note) { <p>{{ paymentItem.note }}</p> }</article> } }</section>
|
|
733
|
+
<section class="history"><h4>Bill history</h4>@if (!data.activity.length) { <p>No bill activity yet.</p> } @else { <ol>@for (event of data.activity; track event.id) { <li><span></span><div><strong>{{ activityLabel(event.type) }}</strong><small>{{ event.createdAt | date:'medium' }}{{ event.actor ? ' · '+event.actor : '' }}</small>@if (event.description) { <p>{{ event.description }}</p> }</div></li> }</ol> }</section>
|
|
603
734
|
<div class="actionbar">@for (action of data.lifecycle.actions; track action.id) { @if (action.enabled) { <button [class.primary]="action.primary" (click)="beginAction(action.id)">{{ action.label }}</button> } }</div>
|
|
604
|
-
@if (panel === 'payment') { <div class="panel"><h4>Post payment</h4><div class="grid three"><label><span>Amount</span><input type="number" min="0.01" [(ngModel)]="payment.amount"></label><label><span>Method</span><select [(ngModel)]="payment.method"><option value="check">Check</option><option value="eft">EFT</option></select></label><label><span>Deposit date</span><input type="date" [(ngModel)]="payment.depositDate"></label></div><div class="actions"><button (click)="panel=''">Cancel</button><button class="primary" (click)="postPayment()">Post payment</button></div></div> }
|
|
605
|
-
@if (panel === 'review') { <div class="panel"><h4>Submit Second Review</h4><label><span>Reason</span><textarea [(ngModel)]="review.reason"></textarea></label><div class="grid two"><label><span>Payer control number</span><input [(ngModel)]="review.payerClaimControlNumber"></label><label><span>Disputed amount</span><input type="number" [(ngModel)]="review.disputedAmount"></label></div><div class="actions"><button (click)="panel=''">Cancel</button><button class="primary" (click)="submitReview()">Submit review</button></div></div> }
|
|
606
|
-
@if (panel === 'close') { <div class="panel"><h4>Close bill</h4><label><span>Reason</span><textarea [(ngModel)]="closeReason"></textarea></label><div class="actions"><button (click)="panel=''">Cancel</button><button class="danger" (click)="closeBill()">Close bill</button></div></div> }
|
|
607
735
|
</section>
|
|
736
|
+
@if (panel) {
|
|
737
|
+
<div class="modal-backdrop" (click)="panel=''">
|
|
738
|
+
<section class="submit-modal action-modal" role="dialog" aria-modal="true" (click)="$event.stopPropagation()">
|
|
739
|
+
<header><div><span class="eyebrow">Bill {{ data.bill.billNumber }}</span><h3>{{ actionTitle() }}</h3></div><button class="close" type="button" (click)="panel=''" aria-label="Close">×</button></header>
|
|
740
|
+
@if (panel === 'payment') { <p>Record funds received for this bill. This updates the payment ledger and remaining balance.</p><div class="grid two"><label><span>Amount</span><input type="number" min="0.01" [(ngModel)]="payment.amount"></label><label><span>Method</span><select [(ngModel)]="payment.method"><option value="check">Check</option><option value="eft">EFT</option></select></label><label><span>Check / EFT number</span><input [(ngModel)]="payment.checkNumber"></label><label><span>Deposit date</span><input type="date" [(ngModel)]="payment.depositDate"></label></div><label><span>Note (optional)</span><input [(ngModel)]="payment.note"></label> }
|
|
741
|
+
@if (panel === 'review') { <p>Explain the dispute and choose the exact payer documents to include with the Second Review.</p><label><span>Reason for Second Review</span><textarea [(ngModel)]="review.reason"></textarea></label><div class="grid two"><label><span>Payer control number</span><input [(ngModel)]="review.payerClaimControlNumber"></label><label><span>Disputed amount</span><input type="number" [(ngModel)]="review.disputedAmount"></label></div><fieldset class="review-docs"><legend>Supporting documents</legend>@for (doc of data.bill.attachments; track doc.id) { <label><input type="checkbox" [checked]="reviewAttachmentIds.includes(doc.id)" (change)="toggleReviewAttachment(doc.id)"><span><strong>{{ doc.filename }}</strong><small>{{ doc.description || doc.documentType }}</small></span></label> }</fieldset><div class="upload"><select [(ngModel)]="documentType">@for (type of documentTypes; track type.value) { <option [value]="type.value">{{ type.label }}</option> }</select><input type="file" accept="application/pdf" (change)="fileSelected($event)"><button type="button" [disabled]="!pendingFile || store.mutating()" (click)="attachForReview()">Add document</button></div> }
|
|
742
|
+
@if (panel === 'correction') { <p>Create a replacement bill prefilled from this rejected submission. You can correct the payer, claim, provider, service lines, and packet before resubmitting.</p> }
|
|
743
|
+
@if (panel === 'close') { <p>Closing stops active follow-up. The bill history and documents remain available.</p><label><span>Reason</span><textarea [(ngModel)]="closeReason"></textarea></label> }
|
|
744
|
+
<footer><button type="button" (click)="panel=''">Cancel</button>@if (panel === 'payment') { <button class="primary" type="button" (click)="postPayment()" [disabled]="store.mutating() || payment.amount <= 0">Post payment</button> }@if (panel === 'review') { <button class="primary" type="button" (click)="submitReview()" [disabled]="store.mutating() || !review.reason.trim() || !review.payerClaimControlNumber.trim()">Submit Second Review</button> }@if (panel === 'correction') { <button class="primary" type="button" (click)="correct()" [disabled]="store.mutating()">Create correction</button> }@if (panel === 'close') { <button class="danger" type="button" (click)="closeBill()" [disabled]="store.mutating() || !closeReason.trim()">Close bill</button> }</footer>
|
|
745
|
+
</section>
|
|
746
|
+
</div>
|
|
747
|
+
}
|
|
608
748
|
}
|
|
609
749
|
@if (notice) { <div class="notice">{{ notice }}</div> }
|
|
610
750
|
@if (store.error()) { <div class="notice error">{{ store.error()?.message }}</div> }
|
|
@@ -612,10 +752,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
|
|
|
612
752
|
}
|
|
613
753
|
<datalist id="mb-states"><option value="CA"></option><option value="AZ"></option><option value="NV"></option><option value="OR"></option><option value="WA"></option><option value="TX"></option><option value="NY"></option></datalist>
|
|
614
754
|
</section>
|
|
615
|
-
`, styles: [":host{display:block}.mb{--a:#238dbd;--ac:#fff;--bg:#f3f8fa;--s:#fff;--t:#203743;--m:#657982;--b:#dbe6ea;--r:12px;--cr:8px;display:grid;gap:16px;color:var(--t);font:14px/1.45 var(--font,Inter,system-ui,sans-serif)}*{box-sizing:border-box}h2,h3,h4,p{margin:0}.summary,.card,.delivery,.state{border:1px solid var(--b);border-radius:var(--r);background:var(--s)}.summary{display:flex;justify-content:space-between;gap:20px;padding:20px}.summary h2{font-size:24px}.summary p,.card p,.delivery p,small{color:var(--m)}.eyebrow{color:var(--m);font-size:11px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}.money{text-align:right}.money span{display:block;font-size:28px;font-weight:800}.money small{font-size:12px}.review{display:grid;gap:16px}.card{padding:20px}.card-title{display:flex;align-items:start;justify-content:space-between;gap:16px;margin-bottom:18px}.card-title h3,.delivery h3{font-size:18px}.card-title>span{border-radius:999px;background:var(--bg);padding:5px 9px;color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.grid{display:grid;gap:14px}.grid.four{grid-template-columns:repeat(4,minmax(0,1fr))}.grid.three{grid-template-columns:repeat(3,minmax(0,1fr))}.grid.two{grid-template-columns:repeat(2,minmax(0,1fr))}label{display:grid;gap:6px;color:var(--t);font-size:12px;font-weight:700}input,select,textarea,button{font:inherit}input,select,textarea{width:100%;min-height:42px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;color:var(--t);padding:9px 11px}textarea{min-height:90px;resize:vertical}button{min-height:38px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;color:var(--t);padding:8px 13px;cursor:pointer;font-weight:700}button.primary{border-color:var(--a);background:var(--a);color:var(--ac)}button.danger{border-color:#d4380d;background:#d4380d;color:#fff}button:disabled{cursor:not-allowed;opacity:.5}.subhead{margin:18px 0 9px;border-top:1px solid var(--b);padding-top:15px;font-size:12px;font-weight:800}.selected{display:flex;align-items:center;justify-content:space-between;border:1px solid var(--b);border-radius:var(--cr);padding:12px}.selected div{display:grid}.results{position:relative;z-index:3;display:grid;margin-top:5px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;box-shadow:0 12px 30px #1f2d3d1f;overflow:hidden}.results button{display:grid;gap:2px;text-align:left;border:0;border-bottom:1px solid var(--b);border-radius:0;padding:12px}.results span{color:var(--m);font-weight:400}.presets{display:flex;gap:8px;margin:-4px 0 12px}.lines{display:grid;gap:10px}.line{display:grid;grid-template-columns:1.2fr 1.2fr 110px 120px 40px;align-items:end;gap:10px;border-radius:var(--cr);background:var(--bg);padding:12px}.line.professional{grid-template-columns:1.1fr 1fr 1fr 1fr 110px 1fr 90px 110px 40px}.allowed{display:grid;gap:7px;text-align:right}.allowed span{color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.allowed strong{font-size:17px}.remove{border:0;background:transparent;font-size:20px}.docs{list-style:none;margin:0;padding:0}.docs li{display:flex;align-items:center;gap:8px;border-top:1px solid var(--b);padding:11px 0}.docs li>div{display:grid;flex:1}.upload{display:grid;grid-template-columns:240px 1fr auto;gap:10px;margin-top:12px;border-radius:var(--cr);background:var(--bg);padding:12px}.delivery{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:20px;background:color-mix(in srgb,var(--a) 5%,white)}.actions,.actionbar{display:flex;justify-content:flex-end;gap:8px}.lifecycle{display:grid;gap:
|
|
755
|
+
`, styles: [":host{display:block}.mb{--a:#238dbd;--ac:#fff;--bg:#f3f8fa;--s:#fff;--t:#203743;--m:#657982;--b:#dbe6ea;--r:12px;--cr:8px;display:grid;gap:16px;color:var(--t);font:14px/1.45 var(--font,Inter,system-ui,sans-serif)}*{box-sizing:border-box}h2,h3,h4,p{margin:0}a{color:var(--a)}.summary,.card,.delivery,.state{border:1px solid var(--b);border-radius:var(--r);background:var(--s)}.summary{display:flex;justify-content:space-between;gap:20px;padding:20px}.summary h2{font-size:24px}.summary p,.card p,.delivery p,small{color:var(--m)}.eyebrow{color:var(--m);font-size:11px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}.money{text-align:right}.money span{display:block;font-size:28px;font-weight:800}.money small{font-size:12px}.review{display:grid;gap:16px}.card{padding:20px}.card-title{display:flex;align-items:start;justify-content:space-between;gap:16px;margin-bottom:18px}.card-title h3,.delivery h3{font-size:18px}.card-title>span{border-radius:999px;background:var(--bg);padding:5px 9px;color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.grid{display:grid;gap:14px}.grid.four{grid-template-columns:repeat(4,minmax(0,1fr))}.grid.three{grid-template-columns:repeat(3,minmax(0,1fr))}.grid.two{grid-template-columns:repeat(2,minmax(0,1fr))}label{display:grid;gap:6px;color:var(--t);font-size:12px;font-weight:700}input,select,textarea,button{font:inherit}input,select,textarea{width:100%;min-height:42px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;color:var(--t);padding:9px 11px}textarea{min-height:90px;resize:vertical}button{min-height:38px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;color:var(--t);padding:8px 13px;cursor:pointer;font-weight:700}button.primary{border-color:var(--a);background:var(--a);color:var(--ac)}button.danger{border-color:#d4380d;background:#d4380d;color:#fff}button:disabled{cursor:not-allowed;opacity:.5}.subhead{margin:18px 0 9px;border-top:1px solid var(--b);padding-top:15px;font-size:12px;font-weight:800}.selected{display:flex;align-items:center;justify-content:space-between;border:1px solid var(--b);border-radius:var(--cr);padding:12px}.selected div{display:grid}.results{position:relative;z-index:3;display:grid;margin-top:5px;border:1px solid var(--b);border-radius:var(--cr);background:#fff;box-shadow:0 12px 30px #1f2d3d1f;overflow:hidden}.results button{display:grid;gap:2px;text-align:left;border:0;border-bottom:1px solid var(--b);border-radius:0;padding:12px}.results span{color:var(--m);font-weight:400}.presets{display:flex;gap:8px;margin:-4px 0 12px}.lines{display:grid;gap:10px}.line{display:grid;grid-template-columns:1.2fr 1.2fr 110px 120px 40px;align-items:end;gap:10px;border-radius:var(--cr);background:var(--bg);padding:12px}.line.professional{grid-template-columns:1.1fr 1fr 1fr 1fr 110px 1fr 90px 110px 40px}.allowed{display:grid;gap:7px;text-align:right}.allowed span{color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.allowed strong{font-size:17px}.remove{border:0;background:transparent;font-size:20px}.docs{list-style:none;margin:0;padding:0}.docs li{display:flex;align-items:center;gap:8px;border-top:1px solid var(--b);padding:11px 0}.docs li>div{display:grid;flex:1}.upload{display:grid;grid-template-columns:240px 1fr auto;gap:10px;margin-top:12px;border-radius:var(--cr);background:var(--bg);padding:12px}.delivery{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:20px;background:color-mix(in srgb,var(--a) 5%,white)}.actions,.actionbar{display:flex;justify-content:flex-end;gap:8px}.progress ol{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));list-style:none;margin:0;padding:0}.progress li{position:relative;display:grid;justify-items:center;gap:7px;color:var(--m);font-size:12px;text-align:center}.progress li:before{content:\"\";position:absolute;top:14px;right:50%;left:-50%;height:2px;background:var(--b)}.progress li:first-child:before{display:none}.progress li b{position:relative;z-index:1;display:grid;place-items:center;width:28px;height:28px;border:2px solid var(--b);border-radius:50%;background:var(--s)}.progress li.complete,.progress li.current{color:var(--t)}.progress li.complete:before,.progress li.current:before{background:var(--a)}.progress li.complete b,.progress li.current b{border-color:var(--a);background:var(--a);color:var(--ac)}.snapshot dl,.facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));margin:0}.snapshot dl>div,.facts>div{display:grid;gap:3px;border-right:1px solid var(--b);padding:4px 14px}.snapshot dl>div:nth-child(3n),.facts>div:last-child{border-right:0}.snapshot dt,.facts dt,.contacts dt{color:var(--m);font-size:11px;font-weight:800;text-transform:uppercase}.snapshot dd,.facts dd,.contacts dd{margin:0;font-weight:700}.lifecycle{display:grid;gap:20px}.actionbar{flex-wrap:wrap;border-top:1px solid var(--b);padding-top:18px}.lifecycle-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}.lifecycle-grid>section,.payments,.history,.eors{display:grid;gap:11px;border:1px solid var(--b);border-radius:var(--cr);padding:15px}.contacts{display:grid;gap:9px;margin:0}.contacts>div{display:grid;grid-template-columns:70px 1fr;gap:10px}.denial{border-radius:var(--cr);background:#fff4ed;padding:11px}.eors>button{display:flex;align-items:center;justify-content:space-between;text-align:left}.eors span{display:grid}.payments article{display:grid;grid-template-columns:1fr auto;gap:4px;border-top:1px solid var(--b);padding-top:10px}.payments article>div{display:grid}.payments article>div:last-of-type{text-align:right}.payments article p{grid-column:1/-1}.history ol{display:grid;gap:0;list-style:none;margin:0;padding:0}.history li{display:grid;grid-template-columns:18px 1fr;gap:9px}.history li>span{position:relative;margin-top:5px;width:10px;height:10px;border-radius:50%;background:var(--a)}.history li>span:after{content:\"\";position:absolute;top:10px;bottom:-30px;left:4px;width:2px;background:var(--b)}.history li:last-child>span:after{display:none}.history li>div{display:grid;gap:2px;padding-bottom:15px}.notice,.state{padding:13px 15px}.notice{border-radius:var(--cr);background:#edf8f2;color:#23734c}.notice.error,.state.error{background:#fff2f0;color:#b42318}.state{display:grid;gap:10px}.state button{justify-self:start}.powered{text-align:right;color:var(--m);font-size:11px}.modal-backdrop{position:fixed;z-index:1000;inset:0;display:grid;place-items:center;background:#0f20288f;padding:20px}.submit-modal{display:grid;gap:18px;width:min(680px,100%);max-height:calc(100vh - 40px);overflow:auto;border:1px solid var(--b);border-radius:var(--r);background:var(--s);padding:22px;box-shadow:0 24px 80px #0f202847}.submit-modal>header,.submit-modal>footer{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}.submit-modal>footer{justify-content:flex-end}.submit-modal .close{border:0;background:transparent;font-size:26px}.route-list{display:grid;gap:8px}.route-option{display:grid;grid-template-columns:20px 1fr auto;align-items:center;gap:12px;text-align:left;padding:13px}.route-option>span:nth-child(2){display:grid}.route-option.selected{border-color:var(--a);box-shadow:0 0 0 2px color-mix(in srgb,var(--a) 18%,transparent)}.route-option .radio{width:16px;height:16px;border:2px solid var(--b);border-radius:50%}.route-option.selected .radio{border:5px solid var(--a)}.route-option b{color:var(--a);font-size:11px;text-transform:uppercase}.action-modal{width:min(720px,100%)}.review-docs{display:grid;gap:8px;border:1px solid var(--b);border-radius:var(--cr);padding:12px}.review-docs label{display:grid;grid-template-columns:20px 1fr;align-items:start}.review-docs input{min-height:auto}.review-docs label>span{display:grid}@media(max-width:1100px){.line.professional{grid-template-columns:repeat(3,minmax(0,1fr))}.line.professional .allowed{grid-column:auto}}@media(max-width:900px){.grid.four,.grid.three{grid-template-columns:repeat(2,minmax(0,1fr))}.line{grid-template-columns:1fr 1fr 90px}.allowed{grid-column:1/-2;text-align:left}.upload{grid-template-columns:1fr}.delivery{align-items:stretch;flex-direction:column}.actions{justify-content:flex-start}.lifecycle-grid{grid-template-columns:1fr}}@media(max-width:600px){.summary,.card-title{align-items:stretch;flex-direction:column}.money{text-align:left}.grid.four,.grid.three,.grid.two,.line,.line.professional{grid-template-columns:1fr}.allowed{grid-column:auto}.docs li{align-items:flex-start;flex-wrap:wrap}.progress{overflow-x:auto}.progress ol{min-width:560px}.snapshot dl,.facts{grid-template-columns:1fr}.snapshot dl>div,.facts>div{border-right:0;border-bottom:1px solid var(--b);padding:10px 0}.snapshot dl>div:last-child,.facts>div:last-child{border-bottom:0}.modal-backdrop{align-items:end;padding:0}.submit-modal{max-height:92vh;border-radius:var(--r) var(--r) 0 0;padding:16px}.route-option{grid-template-columns:20px 1fr}.route-option b{grid-column:2}}\n"] }]
|
|
616
756
|
}], ctorParameters: () => [], propDecorators: { billId: [{
|
|
617
|
-
type: Input
|
|
618
|
-
|
|
757
|
+
type: Input
|
|
758
|
+
}], create: [{
|
|
759
|
+
type: Input
|
|
619
760
|
}], sessionEndpoint: [{
|
|
620
761
|
type: Input
|
|
621
762
|
}], apiBaseUrl: [{
|
|
@@ -628,6 +769,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
|
|
|
628
769
|
type: Input
|
|
629
770
|
}], billIdChange: [{
|
|
630
771
|
type: Output
|
|
772
|
+
}], billCreated: [{
|
|
773
|
+
type: Output
|
|
631
774
|
}], submitted: [{
|
|
632
775
|
type: Output
|
|
633
776
|
}], billingError: [{
|