@mindbill/angular 0.1.1 → 0.2.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 +2 -0
- package/dist/README.md +56 -0
- package/{fesm2022 → dist/fesm2022}/mindbill-angular.mjs +185 -20
- package/dist/fesm2022/mindbill-angular.mjs.map +1 -0
- package/{types → dist/types}/mindbill-angular.d.ts +37 -10
- package/ng-package.json +6 -0
- package/package.json +10 -25
- package/src/lib/bill-lifecycle.component.ts +378 -0
- package/src/lib/lifecycle-store.ts +109 -0
- package/src/lib/procedure-lines.ts +41 -0
- package/src/public-api.ts +20 -0
- package/tsconfig.lib.json +17 -0
- package/fesm2022/mindbill-angular.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -32,6 +32,8 @@ export class CaseBillingComponent {
|
|
|
32
32
|
|
|
33
33
|
The component loads and refreshes status, searches the payer directory, saves bill edits, manages the explicit payer packet, submits the bill, shows EORs, and exposes the correct payment, review, correction, resubmission, and close actions for the current state.
|
|
34
34
|
|
|
35
|
+
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
|
+
|
|
35
37
|
Add one authenticated server endpoint. It verifies that the signed-in user may access the bill, then mints a short-lived token bound to that bill and browser origin.
|
|
36
38
|
|
|
37
39
|
```ts
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# @mindbill/angular
|
|
2
|
+
|
|
3
|
+
Native Angular billing UI with built-in session renewal and lifecycle API calls.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @mindbill/angular @mindbill/node
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Import the standalone component and give it the one value your application keeps: the bill ID.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { Component } from "@angular/core";
|
|
13
|
+
import { MindBillBillLifecycleComponent } from "@mindbill/angular";
|
|
14
|
+
|
|
15
|
+
@Component({
|
|
16
|
+
selector: "app-case-billing",
|
|
17
|
+
standalone: true,
|
|
18
|
+
imports: [MindBillBillLifecycleComponent],
|
|
19
|
+
template: `
|
|
20
|
+
<mindbill-bill-lifecycle
|
|
21
|
+
[billId]="billId"
|
|
22
|
+
sessionEndpoint="/api/mindbill/bill-session"
|
|
23
|
+
[appearance]="{ preset: 'clinical-blue' }"
|
|
24
|
+
(billIdChange)="billId = $event"
|
|
25
|
+
/>
|
|
26
|
+
`,
|
|
27
|
+
})
|
|
28
|
+
export class CaseBillingComponent {
|
|
29
|
+
billId = "bill_123";
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The component loads and refreshes status, searches the payer directory, saves bill edits, manages the explicit payer packet, submits the bill, shows EORs, and exposes the correct payment, review, correction, resubmission, and close actions for the current state.
|
|
34
|
+
|
|
35
|
+
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
|
+
Add one authenticated server endpoint. It verifies that the signed-in user may access the bill, then mints a short-lived token bound to that bill and browser origin.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { MindBillClient } from "@mindbill/node";
|
|
41
|
+
|
|
42
|
+
const mindbill = new MindBillClient({ apiKey: process.env["MINDBILL_API_KEY"]! });
|
|
43
|
+
|
|
44
|
+
app.post("/api/mindbill/bill-session", requireUser, async (req, res) => {
|
|
45
|
+
await requireBillAccess(req.user, req.body.billId);
|
|
46
|
+
const session = await mindbill.createBrowserSession({
|
|
47
|
+
component: "bill-review",
|
|
48
|
+
billId: req.body.billId,
|
|
49
|
+
allowedOrigin: `${req.protocol}://${req.get("host")}`,
|
|
50
|
+
expiresIn: 900,
|
|
51
|
+
});
|
|
52
|
+
res.json(session);
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Your permanent API key never reaches Angular. Available presets are `mindbill`, `qme-companion`, `orange-bright`, and `clinical-blue`; every visual token can also be overridden.
|
|
@@ -52,8 +52,9 @@ class MindBillLifecycleStore {
|
|
|
52
52
|
searchClaimsAdministrators(query, claimNumber) {
|
|
53
53
|
return this.requireClient().searchClaimsAdministrators(query, claimNumber);
|
|
54
54
|
}
|
|
55
|
+
getDeliveryOptions() { return this.requireClient().getDeliveryOptions(); }
|
|
55
56
|
saveReview(input) { return this.mutate(() => this.requireClient().saveReview(input)); }
|
|
56
|
-
submitBill(input,
|
|
57
|
+
submitBill(input, submission) { return this.mutate(() => this.requireClient().submitBill(input, submission)); }
|
|
57
58
|
addAttachment(file, type, description) { return this.mutate(() => this.requireClient().addAttachment(file, type, description)); }
|
|
58
59
|
removeAttachment(id) { return this.mutate(() => this.requireClient().removeAttachment(id)); }
|
|
59
60
|
getAttachment(id) { return this.requireClient().getAttachment(id); }
|
|
@@ -103,6 +104,31 @@ class MindBillLifecycleStore {
|
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
const EMPTY_PROCEDURE_LINE = {
|
|
108
|
+
code: "",
|
|
109
|
+
modifiers: [],
|
|
110
|
+
units: 1,
|
|
111
|
+
charge: 0,
|
|
112
|
+
};
|
|
113
|
+
function isEmptyProcedureLine(line) {
|
|
114
|
+
return !line.code.trim()
|
|
115
|
+
&& line.modifiers.length === 0
|
|
116
|
+
&& line.units === 1
|
|
117
|
+
&& !line.serviceDate
|
|
118
|
+
&& !line.serviceDateEnd
|
|
119
|
+
&& !(line.diagnosisPointers?.length)
|
|
120
|
+
&& !line.charge;
|
|
121
|
+
}
|
|
122
|
+
/** Keeps completed/partial lines plus one keyboard-ready empty row. */
|
|
123
|
+
function ensureTrailingProcedureLine(lines) {
|
|
124
|
+
const entered = lines
|
|
125
|
+
.filter((line) => !isEmptyProcedureLine(line))
|
|
126
|
+
.map((line) => ({ ...line, modifiers: [...line.modifiers] }));
|
|
127
|
+
return entered.length < 50
|
|
128
|
+
? [...entered, { ...EMPTY_PROCEDURE_LINE, modifiers: [] }]
|
|
129
|
+
: entered;
|
|
130
|
+
}
|
|
131
|
+
|
|
106
132
|
const THEMES = {
|
|
107
133
|
mindbill: { preset: "mindbill", accentColor: "#238dbd", accentTextColor: "#fff", backgroundColor: "#f3f8fa", surfaceColor: "#fff", textColor: "#203743", mutedColor: "#657982", borderColor: "#dbe6ea", borderRadius: "14px", controlRadius: "8px", fontFamily: "Inter,system-ui,sans-serif" },
|
|
108
134
|
"qme-companion": { preset: "qme-companion", accentColor: "#53b5dc", accentTextColor: "#173542", backgroundColor: "#f2f8fb", surfaceColor: "#fff", textColor: "#1d3440", mutedColor: "#617783", borderColor: "#d7e5eb", borderRadius: "12px", controlRadius: "8px", fontFamily: "Inter,system-ui,sans-serif" },
|
|
@@ -114,6 +140,7 @@ const DOCUMENT_TYPES = [
|
|
|
114
140
|
{ value: "proof_of_service", label: "Proof of service" },
|
|
115
141
|
{ value: "letter_of_attestation", label: "Letter of attestation" },
|
|
116
142
|
{ value: "form_122", label: "Required form" },
|
|
143
|
+
{ value: "return_to_work_voucher", label: "Return-to-work voucher" },
|
|
117
144
|
{ value: "w9", label: "W-9" },
|
|
118
145
|
{ value: "appeal", label: "Appeal support" },
|
|
119
146
|
{ value: "medical_records", label: "Medical records (intentional)" },
|
|
@@ -131,14 +158,17 @@ class MindBillBillLifecycleComponent {
|
|
|
131
158
|
billingError = new EventEmitter();
|
|
132
159
|
store = new MindBillLifecycleStore();
|
|
133
160
|
documentTypes = DOCUMENT_TYPES;
|
|
134
|
-
|
|
161
|
+
medLegalCodes = ["ML200", "ML201", "ML202", "ML203", "ML204", "ML205", "ML206", "MLPRR"];
|
|
135
162
|
draft = null;
|
|
136
163
|
dirty = false;
|
|
137
164
|
payerQuery = "";
|
|
138
165
|
payerResults = [];
|
|
139
166
|
documentType = "other";
|
|
140
167
|
pendingFile = null;
|
|
141
|
-
|
|
168
|
+
deliveryOptions = null;
|
|
169
|
+
submission = { route: "ebill" };
|
|
170
|
+
showSubmit = false;
|
|
171
|
+
deliveryBusy = false;
|
|
142
172
|
panel = "";
|
|
143
173
|
notice = "";
|
|
144
174
|
closeReason = "";
|
|
@@ -191,20 +221,71 @@ class MindBillBillLifecycleComponent {
|
|
|
191
221
|
return; this.draft.injury.claimsAdminId = payer.id; this.draft.injury.claimsAdminName = payer.name; this.payerQuery = ""; this.payerResults = []; this.dirty = true; }
|
|
192
222
|
clearPayer() { if (!this.draft)
|
|
193
223
|
return; this.draft.injury.claimsAdminId = ""; this.draft.injury.claimsAdminName = ""; this.dirty = true; }
|
|
194
|
-
|
|
195
|
-
removeLine(index) { this.draft?.bill.lineItems.splice(index, 1); this.dirty = true; }
|
|
196
|
-
setModifiers(line, value) { line.modifiers = value.split(",").map((item) => item.trim().replace(/^-/, "")).filter(Boolean); this.dirty = true; }
|
|
224
|
+
lineChanged() { this.normalizeLineItems(); this.dirty = true; }
|
|
225
|
+
removeLine(index) { this.draft?.bill.lineItems.splice(index, 1); this.normalizeLineItems(); this.dirty = true; }
|
|
226
|
+
setModifiers(line, value) { line.modifiers = value.split(",").map((item) => item.trim().replace(/^-/, "")).filter(Boolean); this.normalizeLineItems(); this.dirty = true; }
|
|
227
|
+
setDiagnosisPointers(line, value) { line.diagnosisPointers = value.split(",").map((item) => Number(item.trim())).filter((item) => Number.isInteger(item) && item >= 1 && item <= 12); this.normalizeLineItems(); this.dirty = true; }
|
|
228
|
+
applyPreset(kind) {
|
|
229
|
+
if (!this.draft)
|
|
230
|
+
return;
|
|
231
|
+
const modifier = kind === "ame" ? "94" : kind === "psych" ? "96" : "95";
|
|
232
|
+
const entered = this.draft.bill.lineItems.filter((line) => line.code.trim());
|
|
233
|
+
if (entered.length === 0)
|
|
234
|
+
entered.push({ code: "ML201", modifiers: [modifier], units: 1, charge: 0 });
|
|
235
|
+
else
|
|
236
|
+
entered.forEach((line) => { if (!line.modifiers.length)
|
|
237
|
+
line.modifiers = [modifier]; });
|
|
238
|
+
this.draft.bill.lineItems = ensureTrailingProcedureLine(entered);
|
|
239
|
+
this.dirty = true;
|
|
240
|
+
}
|
|
197
241
|
fileSelected(event) { this.pendingFile = event.target.files?.[0] ?? null; }
|
|
198
242
|
async attach() { if (!this.pendingFile)
|
|
199
243
|
return; await this.store.addAttachment(this.pendingFile, this.documentType); this.pendingFile = null; this.notice = "Document attached."; }
|
|
200
244
|
async removeAttachment(id) { await this.store.removeAttachment(id); this.notice = "Document removed."; }
|
|
201
245
|
async openAttachment(id, filename) { this.openBlob(await this.store.getAttachment(id), filename); }
|
|
202
246
|
async openEor(id, filename) { this.openBlob(await this.store.getEor(id), filename); }
|
|
203
|
-
canSubmit() {
|
|
247
|
+
canSubmit() {
|
|
248
|
+
const input = this.buildInput();
|
|
249
|
+
if (!input || !input.claimsAdminId || !input.billingProvider?.name || !input.billingProvider.taxId || !input.billingProvider.npi || !input.renderingProvider?.name || !input.renderingProvider.npi || !input.lineItems.length)
|
|
250
|
+
return false;
|
|
251
|
+
return input.lineItems.every((line) => line.code && line.units > 0 && (this.draft?.bill.billingMode !== "professional" || Boolean(line.serviceDate && line.charge && line.charge > 0)));
|
|
252
|
+
}
|
|
204
253
|
async save() { const input = this.buildInput(); if (!input)
|
|
205
254
|
return; const data = await this.store.saveReview(input); this.dirty = false; this.draft = this.makeDraft(data); this.notice = "Bill saved."; }
|
|
206
|
-
async
|
|
207
|
-
|
|
255
|
+
async openSubmit() {
|
|
256
|
+
if (!this.canSubmit())
|
|
257
|
+
return;
|
|
258
|
+
this.deliveryBusy = true;
|
|
259
|
+
try {
|
|
260
|
+
this.deliveryOptions = await this.store.getDeliveryOptions();
|
|
261
|
+
this.chooseDelivery(this.deliveryOptions.recommended);
|
|
262
|
+
this.showSubmit = true;
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
this.deliveryBusy = false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
closeSubmit() { this.showSubmit = false; }
|
|
269
|
+
selectedDelivery() { return this.deliveryOptions?.options.find((option) => option.route === this.submission.route); }
|
|
270
|
+
chooseDelivery(option) {
|
|
271
|
+
const destination = option.route === "fax" ? { faxNumber: option.target ?? this.deliveryOptions?.contacts.faxNumber ?? "" }
|
|
272
|
+
: option.route === "email" ? { email: option.target ?? this.deliveryOptions?.contacts.claimsEmail ?? "" }
|
|
273
|
+
: option.route === "mail" ? { mailingAddress: option.target ?? this.deliveryOptions?.contacts.mailingAddress ?? "" }
|
|
274
|
+
: undefined;
|
|
275
|
+
this.submission = { route: option.route, ...(destination ? { destination } : {}) };
|
|
276
|
+
}
|
|
277
|
+
setDestination(key, value) { this.submission = { ...this.submission, destination: { ...this.submission.destination, [key]: value } }; }
|
|
278
|
+
deliveryReady() {
|
|
279
|
+
if (this.submission.route === "fax")
|
|
280
|
+
return Boolean(this.submission.destination?.faxNumber?.trim());
|
|
281
|
+
if (this.submission.route === "email")
|
|
282
|
+
return Boolean(this.submission.destination?.email?.trim());
|
|
283
|
+
if (this.submission.route === "mail")
|
|
284
|
+
return Boolean(this.submission.destination?.mailingAddress?.trim());
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
async submit() { const input = this.buildInput(); if (!input || !this.canSubmit() || !this.deliveryReady())
|
|
288
|
+
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); }
|
|
208
289
|
beginAction(action) { if (action === "post_payment")
|
|
209
290
|
this.panel = "payment";
|
|
210
291
|
else if (action === "second_review" || action === "independent_bill_review")
|
|
@@ -246,19 +327,25 @@ class MindBillBillLifecycleComponent {
|
|
|
246
327
|
billingProvider: this.draft.billingProvider,
|
|
247
328
|
renderingProvider: this.draft.clinician,
|
|
248
329
|
placeOfService: this.draft.location,
|
|
249
|
-
lineItems: this.draft.bill.lineItems.map((line) => ({
|
|
330
|
+
lineItems: this.draft.bill.lineItems.filter((line) => line.code.trim()).map((line) => ({
|
|
250
331
|
...(line.id ? { id: line.id } : {}),
|
|
251
332
|
code: line.code,
|
|
252
333
|
modifiers: line.modifiers,
|
|
253
334
|
units: line.units,
|
|
335
|
+
...(line.charge > 0 ? { charge: line.charge } : {}),
|
|
336
|
+
...(line.serviceDate ? { serviceDate: line.serviceDate } : {}),
|
|
337
|
+
...(line.serviceDateEnd ? { serviceDateEnd: line.serviceDateEnd } : {}),
|
|
338
|
+
...(line.diagnosisPointers?.length ? { diagnosisPointers: line.diagnosisPointers } : {}),
|
|
254
339
|
})),
|
|
255
340
|
};
|
|
256
341
|
}
|
|
257
342
|
makeDraft(data) {
|
|
258
343
|
const snapshot = data.bill.billingSnapshot ?? {};
|
|
259
344
|
const names = data.patient.name.trim().split(/\s+/);
|
|
260
|
-
return { patient: { ...data.patient, firstName: data.patient.firstName ?? names[0] ?? "", lastName: data.patient.lastName ?? names.slice(1).join(" ") }, injury: { ...data.injury }, bill: { ...data.bill, lineItems: data.bill.lineItems
|
|
345
|
+
return { patient: { ...data.patient, firstName: data.patient.firstName ?? names[0] ?? "", lastName: data.patient.lastName ?? names.slice(1).join(" ") }, injury: { ...data.injury }, bill: { ...data.bill, lineItems: ensureTrailingProcedureLine(data.bill.lineItems) }, billingProvider: snapshot.billingProvider ?? { name: "", taxId: "", npi: "", billType: "Professional" }, clinician: snapshot.renderingProvider ?? { name: "", specialty: "", npi: "" }, location: snapshot.placeOfService ?? { name: "", street: "", city: "", state: "", zip: "", posCode: "11" } };
|
|
261
346
|
}
|
|
347
|
+
normalizeLineItems() { if (this.draft)
|
|
348
|
+
this.draft.bill.lineItems = ensureTrailingProcedureLine(this.draft.bill.lineItems); }
|
|
262
349
|
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); }
|
|
263
350
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillBillLifecycleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
264
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: `
|
|
@@ -324,8 +411,29 @@ class MindBillBillLifecycleComponent {
|
|
|
324
411
|
</section>
|
|
325
412
|
|
|
326
413
|
<section class="card">
|
|
327
|
-
<div class="card-title"><div><h3>Charges</h3><p>
|
|
328
|
-
|
|
414
|
+
<div class="card-title"><div><h3>Charges</h3><p>{{ draft.bill.billingMode === 'professional' ? 'Enter each treatment or professional service.' : 'Choose medical-legal codes, modifiers, units, and allowed amounts.' }} A keyboard-ready row appears automatically.</p></div></div>
|
|
415
|
+
@if (draft.bill.billingMode === 'med_legal') {
|
|
416
|
+
<div class="presets"><button type="button" (click)="applyPreset('qme')">QME</button><button type="button" (click)="applyPreset('ame')">AME</button><button type="button" (click)="applyPreset('psych')">Psych QME</button></div>
|
|
417
|
+
}
|
|
418
|
+
<div class="lines">@for (line of draft.bill.lineItems; track $index; let i=$index) {
|
|
419
|
+
<div class="line" [class.professional]="draft.bill.billingMode === 'professional'">
|
|
420
|
+
<label><span>Procedure</span>
|
|
421
|
+
@if (draft.bill.billingMode === 'med_legal') {
|
|
422
|
+
<select [(ngModel)]="line.code" [name]="'code'+i" (ngModelChange)="lineChanged()"><option value="">Choose code…</option>@for (code of medLegalCodes; track code) { <option [value]="code">{{ code }}</option> }</select>
|
|
423
|
+
} @else { <input [(ngModel)]="line.code" [name]="'code'+i" (ngModelChange)="lineChanged()" placeholder="e.g. 99204"> }
|
|
424
|
+
</label>
|
|
425
|
+
<label><span>Modifiers</span><input [ngModel]="line.modifiers.join(', ')" (ngModelChange)="setModifiers(line,$any($event))" [name]="'modifiers'+i" placeholder="e.g. 25, 95"></label>
|
|
426
|
+
@if (draft.bill.billingMode === 'professional') {
|
|
427
|
+
<label><span>Service date</span><input type="date" [(ngModel)]="line.serviceDate" [name]="'serviceDate'+i" (ngModelChange)="lineChanged()"></label>
|
|
428
|
+
<label><span>End date</span><input type="date" [(ngModel)]="line.serviceDateEnd" [name]="'serviceDateEnd'+i" (ngModelChange)="lineChanged()"></label>
|
|
429
|
+
<label><span>Charge</span><input type="number" min="0" step="0.01" [(ngModel)]="line.charge" [name]="'charge'+i" (ngModelChange)="lineChanged()"></label>
|
|
430
|
+
<label><span>Diagnosis pointers</span><input [ngModel]="(line.diagnosisPointers || []).join(', ')" (ngModelChange)="setDiagnosisPointers(line,$any($event))" [name]="'pointers'+i" placeholder="1, 2"></label>
|
|
431
|
+
}
|
|
432
|
+
<label><span>Units</span><input type="number" min="1" [(ngModel)]="line.units" [name]="'units'+i" (ngModelChange)="lineChanged()"></label>
|
|
433
|
+
<div class="allowed"><span>{{ draft.bill.billingMode === 'professional' ? 'Charge' : 'Allowed' }}</span><strong>{{ line.charge | currency }}</strong></div>
|
|
434
|
+
<button type="button" class="remove" (click)="removeLine(i)" aria-label="Remove line">×</button>
|
|
435
|
+
</div>
|
|
436
|
+
}</div>
|
|
329
437
|
</section>
|
|
330
438
|
|
|
331
439
|
<section class="card">
|
|
@@ -334,7 +442,25 @@ class MindBillBillLifecycleComponent {
|
|
|
334
442
|
<div class="upload"><select [(ngModel)]="documentType" name="documentType">@for (type of documentTypes; track type.value) { <option [value]="type.value">{{ type.label }}</option> }</select><input #fileInput type="file" accept="application/pdf" (change)="fileSelected($event)"><button type="button" [disabled]="!pendingFile || store.mutating()" (click)="attach()">Attach document</button></div>
|
|
335
443
|
</section>
|
|
336
444
|
|
|
337
|
-
<section class="delivery"><div><span class="eyebrow">Delivery</span><h3>Submit this bill</h3><p>
|
|
445
|
+
<section class="delivery"><div><span class="eyebrow">Delivery</span><h3>Submit this bill</h3><p>Review the exact electronic, fax, email, or mail destination before anything is sent.</p></div><div class="actions"><button type="button" (click)="save()" [disabled]="store.mutating()">Save changes</button><button class="primary" type="button" (click)="openSubmit()" [disabled]="store.mutating() || deliveryBusy || !canSubmit()">{{ deliveryBusy ? 'Loading routes…' : 'Review delivery' }}</button></div></section>
|
|
446
|
+
|
|
447
|
+
@if (showSubmit && deliveryOptions) {
|
|
448
|
+
<div class="modal-backdrop" (click)="closeSubmit()">
|
|
449
|
+
<section class="submit-modal" role="dialog" aria-modal="true" aria-labelledby="mb-submit-title" (click)="$event.stopPropagation()">
|
|
450
|
+
<header><div><span class="eyebrow">Send bill</span><h3 id="mb-submit-title">Choose a delivery route</h3><p>{{ deliveryOptions.payerName }}</p></div><button type="button" class="close" (click)="closeSubmit()" aria-label="Close">×</button></header>
|
|
451
|
+
<div class="route-list">@for (option of deliveryOptions.options; track option.route) {
|
|
452
|
+
<button type="button" class="route-option" [class.selected]="submission.route === option.route" (click)="chooseDelivery(option)"><span class="radio"></span><span><strong>{{ option.label }}</strong><small>{{ option.detail }}</small></span>@if (option.route === deliveryOptions.recommended.route) { <b>Recommended</b> }</button>
|
|
453
|
+
}</div>
|
|
454
|
+
@if (selectedDelivery(); as option) {
|
|
455
|
+
@if (option.route === 'fax') { <label><span>Fax number</span><input [ngModel]="submission.destination?.faxNumber || ''" (ngModelChange)="setDestination('faxNumber',$any($event))" name="submitFax"></label> }
|
|
456
|
+
@if (option.route === 'email') { <label><span>Email address</span><input type="email" [ngModel]="submission.destination?.email || ''" (ngModelChange)="setDestination('email',$any($event))" name="submitEmail"></label><label><span>Subject</span><input [(ngModel)]="submission.subject" name="submitSubject"></label> }
|
|
457
|
+
@if (option.route === 'mail') { <label><span>Mailing address</span><textarea [ngModel]="submission.destination?.mailingAddress || ''" (ngModelChange)="setDestination('mailingAddress',$any($event))" name="submitMail"></textarea></label> }
|
|
458
|
+
@if (option.route !== 'ebill') { <label><span>Attention (optional)</span><input [(ngModel)]="submission.attention" name="submitAttention"></label> }
|
|
459
|
+
}
|
|
460
|
+
<footer><button type="button" (click)="closeSubmit()">Cancel</button><button type="button" class="primary" (click)="submit()" [disabled]="store.mutating() || !deliveryReady()">{{ store.mutating() ? 'Submitting…' : 'Submit bill' }}</button></footer>
|
|
461
|
+
</section>
|
|
462
|
+
</div>
|
|
463
|
+
}
|
|
338
464
|
</form>
|
|
339
465
|
} @else {
|
|
340
466
|
<section class="card lifecycle">
|
|
@@ -352,7 +478,7 @@ class MindBillBillLifecycleComponent {
|
|
|
352
478
|
}
|
|
353
479
|
<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>
|
|
354
480
|
</section>
|
|
355
|
-
`, 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}.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}.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)}.
|
|
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" }] });
|
|
356
482
|
}
|
|
357
483
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillBillLifecycleComponent, decorators: [{
|
|
358
484
|
type: Component,
|
|
@@ -419,8 +545,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
|
|
|
419
545
|
</section>
|
|
420
546
|
|
|
421
547
|
<section class="card">
|
|
422
|
-
<div class="card-title"><div><h3>Charges</h3><p>
|
|
423
|
-
|
|
548
|
+
<div class="card-title"><div><h3>Charges</h3><p>{{ draft.bill.billingMode === 'professional' ? 'Enter each treatment or professional service.' : 'Choose medical-legal codes, modifiers, units, and allowed amounts.' }} A keyboard-ready row appears automatically.</p></div></div>
|
|
549
|
+
@if (draft.bill.billingMode === 'med_legal') {
|
|
550
|
+
<div class="presets"><button type="button" (click)="applyPreset('qme')">QME</button><button type="button" (click)="applyPreset('ame')">AME</button><button type="button" (click)="applyPreset('psych')">Psych QME</button></div>
|
|
551
|
+
}
|
|
552
|
+
<div class="lines">@for (line of draft.bill.lineItems; track $index; let i=$index) {
|
|
553
|
+
<div class="line" [class.professional]="draft.bill.billingMode === 'professional'">
|
|
554
|
+
<label><span>Procedure</span>
|
|
555
|
+
@if (draft.bill.billingMode === 'med_legal') {
|
|
556
|
+
<select [(ngModel)]="line.code" [name]="'code'+i" (ngModelChange)="lineChanged()"><option value="">Choose code…</option>@for (code of medLegalCodes; track code) { <option [value]="code">{{ code }}</option> }</select>
|
|
557
|
+
} @else { <input [(ngModel)]="line.code" [name]="'code'+i" (ngModelChange)="lineChanged()" placeholder="e.g. 99204"> }
|
|
558
|
+
</label>
|
|
559
|
+
<label><span>Modifiers</span><input [ngModel]="line.modifiers.join(', ')" (ngModelChange)="setModifiers(line,$any($event))" [name]="'modifiers'+i" placeholder="e.g. 25, 95"></label>
|
|
560
|
+
@if (draft.bill.billingMode === 'professional') {
|
|
561
|
+
<label><span>Service date</span><input type="date" [(ngModel)]="line.serviceDate" [name]="'serviceDate'+i" (ngModelChange)="lineChanged()"></label>
|
|
562
|
+
<label><span>End date</span><input type="date" [(ngModel)]="line.serviceDateEnd" [name]="'serviceDateEnd'+i" (ngModelChange)="lineChanged()"></label>
|
|
563
|
+
<label><span>Charge</span><input type="number" min="0" step="0.01" [(ngModel)]="line.charge" [name]="'charge'+i" (ngModelChange)="lineChanged()"></label>
|
|
564
|
+
<label><span>Diagnosis pointers</span><input [ngModel]="(line.diagnosisPointers || []).join(', ')" (ngModelChange)="setDiagnosisPointers(line,$any($event))" [name]="'pointers'+i" placeholder="1, 2"></label>
|
|
565
|
+
}
|
|
566
|
+
<label><span>Units</span><input type="number" min="1" [(ngModel)]="line.units" [name]="'units'+i" (ngModelChange)="lineChanged()"></label>
|
|
567
|
+
<div class="allowed"><span>{{ draft.bill.billingMode === 'professional' ? 'Charge' : 'Allowed' }}</span><strong>{{ line.charge | currency }}</strong></div>
|
|
568
|
+
<button type="button" class="remove" (click)="removeLine(i)" aria-label="Remove line">×</button>
|
|
569
|
+
</div>
|
|
570
|
+
}</div>
|
|
424
571
|
</section>
|
|
425
572
|
|
|
426
573
|
<section class="card">
|
|
@@ -429,7 +576,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
|
|
|
429
576
|
<div class="upload"><select [(ngModel)]="documentType" name="documentType">@for (type of documentTypes; track type.value) { <option [value]="type.value">{{ type.label }}</option> }</select><input #fileInput type="file" accept="application/pdf" (change)="fileSelected($event)"><button type="button" [disabled]="!pendingFile || store.mutating()" (click)="attach()">Attach document</button></div>
|
|
430
577
|
</section>
|
|
431
578
|
|
|
432
|
-
<section class="delivery"><div><span class="eyebrow">Delivery</span><h3>Submit this bill</h3><p>
|
|
579
|
+
<section class="delivery"><div><span class="eyebrow">Delivery</span><h3>Submit this bill</h3><p>Review the exact electronic, fax, email, or mail destination before anything is sent.</p></div><div class="actions"><button type="button" (click)="save()" [disabled]="store.mutating()">Save changes</button><button class="primary" type="button" (click)="openSubmit()" [disabled]="store.mutating() || deliveryBusy || !canSubmit()">{{ deliveryBusy ? 'Loading routes…' : 'Review delivery' }}</button></div></section>
|
|
580
|
+
|
|
581
|
+
@if (showSubmit && deliveryOptions) {
|
|
582
|
+
<div class="modal-backdrop" (click)="closeSubmit()">
|
|
583
|
+
<section class="submit-modal" role="dialog" aria-modal="true" aria-labelledby="mb-submit-title" (click)="$event.stopPropagation()">
|
|
584
|
+
<header><div><span class="eyebrow">Send bill</span><h3 id="mb-submit-title">Choose a delivery route</h3><p>{{ deliveryOptions.payerName }}</p></div><button type="button" class="close" (click)="closeSubmit()" aria-label="Close">×</button></header>
|
|
585
|
+
<div class="route-list">@for (option of deliveryOptions.options; track option.route) {
|
|
586
|
+
<button type="button" class="route-option" [class.selected]="submission.route === option.route" (click)="chooseDelivery(option)"><span class="radio"></span><span><strong>{{ option.label }}</strong><small>{{ option.detail }}</small></span>@if (option.route === deliveryOptions.recommended.route) { <b>Recommended</b> }</button>
|
|
587
|
+
}</div>
|
|
588
|
+
@if (selectedDelivery(); as option) {
|
|
589
|
+
@if (option.route === 'fax') { <label><span>Fax number</span><input [ngModel]="submission.destination?.faxNumber || ''" (ngModelChange)="setDestination('faxNumber',$any($event))" name="submitFax"></label> }
|
|
590
|
+
@if (option.route === 'email') { <label><span>Email address</span><input type="email" [ngModel]="submission.destination?.email || ''" (ngModelChange)="setDestination('email',$any($event))" name="submitEmail"></label><label><span>Subject</span><input [(ngModel)]="submission.subject" name="submitSubject"></label> }
|
|
591
|
+
@if (option.route === 'mail') { <label><span>Mailing address</span><textarea [ngModel]="submission.destination?.mailingAddress || ''" (ngModelChange)="setDestination('mailingAddress',$any($event))" name="submitMail"></textarea></label> }
|
|
592
|
+
@if (option.route !== 'ebill') { <label><span>Attention (optional)</span><input [(ngModel)]="submission.attention" name="submitAttention"></label> }
|
|
593
|
+
}
|
|
594
|
+
<footer><button type="button" (click)="closeSubmit()">Cancel</button><button type="button" class="primary" (click)="submit()" [disabled]="store.mutating() || !deliveryReady()">{{ store.mutating() ? 'Submitting…' : 'Submit bill' }}</button></footer>
|
|
595
|
+
</section>
|
|
596
|
+
</div>
|
|
597
|
+
}
|
|
433
598
|
</form>
|
|
434
599
|
} @else {
|
|
435
600
|
<section class="card lifecycle">
|
|
@@ -447,7 +612,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
|
|
|
447
612
|
}
|
|
448
613
|
<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>
|
|
449
614
|
</section>
|
|
450
|
-
`, 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}.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}.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)}.
|
|
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: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"] }]
|
|
451
616
|
}], ctorParameters: () => [], propDecorators: { billId: [{
|
|
452
617
|
type: Input,
|
|
453
618
|
args: [{ required: true }]
|
|
@@ -473,5 +638,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
|
|
|
473
638
|
* Generated bundle index. Do not edit.
|
|
474
639
|
*/
|
|
475
640
|
|
|
476
|
-
export { MindBillBillLifecycleComponent, MindBillLifecycleStore };
|
|
641
|
+
export { MindBillBillLifecycleComponent, MindBillLifecycleStore, ensureTrailingProcedureLine, isEmptyProcedureLine };
|
|
477
642
|
//# sourceMappingURL=mindbill-angular.mjs.map
|