@mindbill/angular 0.8.0 → 0.10.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.
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, computed, EventEmitter, effect, Output, Input, Component, Directive, inject, ChangeDetectorRef, HostListener } from '@angular/core';
3
- import { createBillLifecycleClient, createBillReferenceClient, createBillSubmissionClient } from '@mindbill/browser';
2
+ import { signal, computed, Input, Component, EventEmitter, effect, Output, Directive, inject, ChangeDetectorRef, HostListener } from '@angular/core';
3
+ import { createBillLifecycleClient, createBillReferenceClient, createBillSubmissionClient, createOrganizationClient } from '@mindbill/browser';
4
4
  import * as i1 from '@angular/common';
5
5
  import { CommonModule } from '@angular/common';
6
6
  import * as i2 from '@angular/forms';
@@ -80,11 +80,114 @@ class MindBillLifecycleStore {
80
80
  }
81
81
 
82
82
  const THEMES = {
83
- 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" },
84
- "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" },
85
- "orange-bright": { preset: "orange-bright", accentColor: "#f4510b", accentTextColor: "#fff", backgroundColor: "#fffaf6", surfaceColor: "#fffefd", textColor: "#090f1f", mutedColor: "#626a73", borderColor: "#e7e1da", borderRadius: "16px", controlRadius: "10px", fontFamily: "Inter,system-ui,sans-serif" },
86
- "clinical-blue": { preset: "clinical-blue", accentColor: "#1677ff", accentTextColor: "#fff", backgroundColor: "#f5f7fa", surfaceColor: "#fff", textColor: "#1f2d3d", mutedColor: "#66788a", borderColor: "#d9e2ec", borderRadius: "8px", controlRadius: "6px", fontFamily: "Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" },
83
+ 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", dangerColor: "#b63d35" },
84
+ "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", dangerColor: "#b83f3a" },
85
+ "orange-bright": { preset: "orange-bright", accentColor: "#f4510b", accentTextColor: "#fff", backgroundColor: "#fffaf6", surfaceColor: "#fffefd", textColor: "#090f1f", mutedColor: "#626a73", borderColor: "#e7e1da", borderRadius: "16px", controlRadius: "10px", fontFamily: "Inter,system-ui,sans-serif", dangerColor: "#c4322b" },
86
+ "clinical-blue": { preset: "clinical-blue", accentColor: "#1677ff", accentTextColor: "#fff", backgroundColor: "#f5f7fa", surfaceColor: "#fff", textColor: "#1f2d3d", mutedColor: "#66788a", borderColor: "#d9e2ec", borderRadius: "8px", controlRadius: "6px", fontFamily: "Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif", dangerColor: "#d4380d" },
87
87
  };
88
+ function mindBillAngularAppearanceStyle(appearance = { preset: "mindbill" }) {
89
+ const base = THEMES[appearance.preset ?? "mindbill"];
90
+ return {
91
+ "--a": appearance.accentColor ?? base.accentColor,
92
+ "--ac": appearance.accentTextColor ?? base.accentTextColor,
93
+ "--bg": appearance.backgroundColor ?? base.backgroundColor,
94
+ "--s": appearance.surfaceColor ?? base.surfaceColor,
95
+ "--t": appearance.textColor ?? base.textColor,
96
+ "--m": appearance.mutedColor ?? base.mutedColor,
97
+ "--b": appearance.borderColor ?? base.borderColor,
98
+ "--r": appearance.borderRadius ?? base.borderRadius,
99
+ "--cr": appearance.controlRadius ?? base.controlRadius,
100
+ "--font": appearance.fontFamily ?? base.fontFamily,
101
+ "--danger": appearance.dangerColor ?? base.dangerColor,
102
+ };
103
+ }
104
+
105
+ function billRejectionIssues(rejection) {
106
+ return rejection.issues?.length
107
+ ? [...rejection.issues]
108
+ : [{ code: rejection.code ?? null, description: rejection.reason }];
109
+ }
110
+ function billRejectionIssueSummary(rejection, count) {
111
+ const noun = count === 1 ? "validation error" : "validation errors";
112
+ const source = rejection.source?.trim().replace(/\.$/, "");
113
+ if (!source)
114
+ return `${count} ${noun}.`;
115
+ if (/acknowledg/i.test(source))
116
+ return `${count} clearinghouse ${noun}.`;
117
+ return `${count} ${noun} returned by ${source}.`;
118
+ }
119
+
120
+ class MindBillBillRejectionNoticeComponent {
121
+ rejection;
122
+ submittedAt = null;
123
+ title = "Rejected — action required";
124
+ appearance = { preset: "mindbill" };
125
+ get issues() { return billRejectionIssues(this.rejection); }
126
+ get hasCodes() { return this.issues.some((issue) => Boolean(issue.code)); }
127
+ get issueSummary() { return billRejectionIssueSummary(this.rejection, this.issues.length); }
128
+ get themeStyle() { return mindBillAngularAppearanceStyle(this.appearance); }
129
+ formatDate(value) { const parsed = new Date(value); return Number.isNaN(parsed.getTime()) ? value : new Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "short" }).format(parsed); }
130
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillBillRejectionNoticeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
131
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: MindBillBillRejectionNoticeComponent, isStandalone: true, selector: "mindbill-bill-rejection-notice", inputs: { rejection: "rejection", submittedAt: "submittedAt", title: "title", appearance: "appearance" }, ngImport: i0, template: `
132
+ <section class="notice" [ngStyle]="themeStyle" role="alert" aria-label="Bill rejection reasons">
133
+ <div class="overview">
134
+ <header>
135
+ <span class="icon" aria-hidden="true">!</span>
136
+ <div><strong>{{ title }}</strong><span>Fix the {{ issues.length === 1 ? 'issue' : 'issues' }} below, then resubmit.</span></div>
137
+ </header>
138
+ <ol class="progress" aria-label="Submission status">
139
+ <li><span aria-hidden="true">✓</span><b>Sent</b>@if (submittedAt) { <small>{{ formatDate(submittedAt) }}</small> }</li>
140
+ <li class="rejected" aria-current="step"><span aria-hidden="true">!</span><b>Rejected</b>@if (rejection.receivedAt) { <small>{{ formatDate(rejection.receivedAt) }}</small> }</li>
141
+ </ol>
142
+ </div>
143
+ <div class="issues" aria-label="Rejection reasons">
144
+ <div class="issues-heading"><strong><span aria-hidden="true">△</span> Rejection reasons</strong><span>{{ issueSummary }}</span></div>
145
+ <ol [attr.aria-label]="issues.length + ' rejection ' + (issues.length === 1 ? 'reason' : 'reasons')">
146
+ @for (issue of issues; track $index) {
147
+ <li><span class="bullet" aria-hidden="true"></span><p>{{ issue.description }}</p>@if (issue.code) { <span class="code">{{ issue.code }}</span> }</li>
148
+ }
149
+ </ol>
150
+ @if (hasCodes) { <p class="code-note"><span aria-hidden="true">i</span> Technical error codes are included for support and auditability.</p> }
151
+ </div>
152
+ </section>
153
+ `, isInline: true, styles: [":host{display:block}.notice,.notice *{box-sizing:border-box}.notice{font-family:var(--font,Inter,system-ui,sans-serif);color:var(--t,#203743);border:1px solid color-mix(in srgb,var(--danger) 30%,var(--b));border-left:4px solid var(--danger);border-radius:var(--r,14px);background:color-mix(in srgb,var(--danger) 5%,var(--s));box-shadow:0 14px 38px color-mix(in srgb,var(--danger) 9%,transparent);padding:26px 28px 18px}.overview{display:grid;grid-template-columns:minmax(230px,.72fr) minmax(360px,1.28fr);align-items:start;gap:38px}header{display:flex;align-items:flex-start;gap:14px}header>div{display:grid;gap:5px}header strong{color:var(--danger);font-size:19px;line-height:1.25}header div>span{color:color-mix(in srgb,var(--danger) 48%,var(--t));font-size:14px;line-height:1.45}.icon{display:grid;place-items:center;flex:0 0 auto;width:42px;height:42px;border-radius:50%;background:var(--danger);box-shadow:0 5px 14px color-mix(in srgb,var(--danger) 25%,transparent);color:#fff;font-size:21px;font-weight:900}.progress{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));list-style:none;margin:5px 0 24px;padding:0}.progress li{display:grid;grid-template-rows:34px auto auto;gap:4px;position:relative;text-align:center;font-size:12px}.progress li:first-child:after{content:\"\";position:absolute;left:calc(50% + 17px);right:calc(-50% + 17px);top:16px;height:2px;background:color-mix(in srgb,var(--danger) 48%,var(--b))}.progress li>span{display:grid;place-items:center;justify-self:center;position:relative;z-index:1;width:34px;height:34px;border:2px solid color-mix(in srgb,var(--danger) 32%,var(--b));border-radius:50%;background:var(--s);color:var(--danger);font-size:16px;font-weight:900}.progress li.rejected>span{border-color:var(--danger);background:var(--danger);color:#fff}.progress b{font-size:13px}.progress small{color:var(--m);font-size:11px;line-height:1.3}.issues{border:1px solid color-mix(in srgb,var(--danger) 19%,var(--b));border-radius:12px;background:color-mix(in srgb,var(--danger) 2%,var(--s));overflow:hidden}.issues-heading{display:flex;align-items:center;justify-content:space-between;gap:18px;padding:12px 16px;border-bottom:1px solid color-mix(in srgb,var(--danger) 14%,var(--b))}.issues-heading strong{display:flex;align-items:center;gap:8px;font-size:13px}.issues-heading strong>span{color:var(--danger);font-size:17px}.issues-heading>span{color:var(--m);font-size:12px;text-align:right}.issues ol{display:grid;gap:7px;list-style:none;margin:0;padding:10px 12px}.issues li{display:grid;grid-template-columns:8px minmax(0,1fr) auto;align-items:center;gap:11px;padding:10px 12px;border:1px solid color-mix(in srgb,var(--danger) 11%,var(--b));border-radius:8px;background:color-mix(in srgb,var(--danger) 1%,var(--s));box-shadow:0 1px 3px #1727300a}.bullet{width:7px;height:7px;border-radius:50%;background:var(--danger)}.issues p{margin:0;font-size:14px;line-height:1.45}.code{justify-self:end;border:1px solid color-mix(in srgb,var(--danger) 20%,var(--b));border-radius:999px;background:color-mix(in srgb,var(--danger) 6%,var(--s));color:var(--danger);font-size:11px;font-weight:850;line-height:1.2;padding:4px 8px}.code-note{display:flex;align-items:center;gap:7px;margin:0;padding:1px 16px 13px;color:var(--m);font-size:11px}.code-note>span{display:grid;place-items:center;width:16px;height:16px;border:1px solid currentColor;border-radius:50%;font-size:10px;font-weight:850}@media(max-width:700px){.notice{padding:18px 14px 14px}.overview{grid-template-columns:1fr;gap:18px}header strong{font-size:17px}.icon{width:36px;height:36px}.progress{margin:0 0 4px}.issues-heading{align-items:flex-start;flex-direction:column;gap:4px}.issues-heading>span{text-align:left}.issues li{grid-template-columns:8px minmax(0,1fr);gap:8px 10px}.code{grid-column:2;justify-self:start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
154
+ }
155
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillBillRejectionNoticeComponent, decorators: [{
156
+ type: Component,
157
+ args: [{ selector: "mindbill-bill-rejection-notice", standalone: true, imports: [CommonModule], template: `
158
+ <section class="notice" [ngStyle]="themeStyle" role="alert" aria-label="Bill rejection reasons">
159
+ <div class="overview">
160
+ <header>
161
+ <span class="icon" aria-hidden="true">!</span>
162
+ <div><strong>{{ title }}</strong><span>Fix the {{ issues.length === 1 ? 'issue' : 'issues' }} below, then resubmit.</span></div>
163
+ </header>
164
+ <ol class="progress" aria-label="Submission status">
165
+ <li><span aria-hidden="true">✓</span><b>Sent</b>@if (submittedAt) { <small>{{ formatDate(submittedAt) }}</small> }</li>
166
+ <li class="rejected" aria-current="step"><span aria-hidden="true">!</span><b>Rejected</b>@if (rejection.receivedAt) { <small>{{ formatDate(rejection.receivedAt) }}</small> }</li>
167
+ </ol>
168
+ </div>
169
+ <div class="issues" aria-label="Rejection reasons">
170
+ <div class="issues-heading"><strong><span aria-hidden="true">△</span> Rejection reasons</strong><span>{{ issueSummary }}</span></div>
171
+ <ol [attr.aria-label]="issues.length + ' rejection ' + (issues.length === 1 ? 'reason' : 'reasons')">
172
+ @for (issue of issues; track $index) {
173
+ <li><span class="bullet" aria-hidden="true"></span><p>{{ issue.description }}</p>@if (issue.code) { <span class="code">{{ issue.code }}</span> }</li>
174
+ }
175
+ </ol>
176
+ @if (hasCodes) { <p class="code-note"><span aria-hidden="true">i</span> Technical error codes are included for support and auditability.</p> }
177
+ </div>
178
+ </section>
179
+ `, styles: [":host{display:block}.notice,.notice *{box-sizing:border-box}.notice{font-family:var(--font,Inter,system-ui,sans-serif);color:var(--t,#203743);border:1px solid color-mix(in srgb,var(--danger) 30%,var(--b));border-left:4px solid var(--danger);border-radius:var(--r,14px);background:color-mix(in srgb,var(--danger) 5%,var(--s));box-shadow:0 14px 38px color-mix(in srgb,var(--danger) 9%,transparent);padding:26px 28px 18px}.overview{display:grid;grid-template-columns:minmax(230px,.72fr) minmax(360px,1.28fr);align-items:start;gap:38px}header{display:flex;align-items:flex-start;gap:14px}header>div{display:grid;gap:5px}header strong{color:var(--danger);font-size:19px;line-height:1.25}header div>span{color:color-mix(in srgb,var(--danger) 48%,var(--t));font-size:14px;line-height:1.45}.icon{display:grid;place-items:center;flex:0 0 auto;width:42px;height:42px;border-radius:50%;background:var(--danger);box-shadow:0 5px 14px color-mix(in srgb,var(--danger) 25%,transparent);color:#fff;font-size:21px;font-weight:900}.progress{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));list-style:none;margin:5px 0 24px;padding:0}.progress li{display:grid;grid-template-rows:34px auto auto;gap:4px;position:relative;text-align:center;font-size:12px}.progress li:first-child:after{content:\"\";position:absolute;left:calc(50% + 17px);right:calc(-50% + 17px);top:16px;height:2px;background:color-mix(in srgb,var(--danger) 48%,var(--b))}.progress li>span{display:grid;place-items:center;justify-self:center;position:relative;z-index:1;width:34px;height:34px;border:2px solid color-mix(in srgb,var(--danger) 32%,var(--b));border-radius:50%;background:var(--s);color:var(--danger);font-size:16px;font-weight:900}.progress li.rejected>span{border-color:var(--danger);background:var(--danger);color:#fff}.progress b{font-size:13px}.progress small{color:var(--m);font-size:11px;line-height:1.3}.issues{border:1px solid color-mix(in srgb,var(--danger) 19%,var(--b));border-radius:12px;background:color-mix(in srgb,var(--danger) 2%,var(--s));overflow:hidden}.issues-heading{display:flex;align-items:center;justify-content:space-between;gap:18px;padding:12px 16px;border-bottom:1px solid color-mix(in srgb,var(--danger) 14%,var(--b))}.issues-heading strong{display:flex;align-items:center;gap:8px;font-size:13px}.issues-heading strong>span{color:var(--danger);font-size:17px}.issues-heading>span{color:var(--m);font-size:12px;text-align:right}.issues ol{display:grid;gap:7px;list-style:none;margin:0;padding:10px 12px}.issues li{display:grid;grid-template-columns:8px minmax(0,1fr) auto;align-items:center;gap:11px;padding:10px 12px;border:1px solid color-mix(in srgb,var(--danger) 11%,var(--b));border-radius:8px;background:color-mix(in srgb,var(--danger) 1%,var(--s));box-shadow:0 1px 3px #1727300a}.bullet{width:7px;height:7px;border-radius:50%;background:var(--danger)}.issues p{margin:0;font-size:14px;line-height:1.45}.code{justify-self:end;border:1px solid color-mix(in srgb,var(--danger) 20%,var(--b));border-radius:999px;background:color-mix(in srgb,var(--danger) 6%,var(--s));color:var(--danger);font-size:11px;font-weight:850;line-height:1.2;padding:4px 8px}.code-note{display:flex;align-items:center;gap:7px;margin:0;padding:1px 16px 13px;color:var(--m);font-size:11px}.code-note>span{display:grid;place-items:center;width:16px;height:16px;border:1px solid currentColor;border-radius:50%;font-size:10px;font-weight:850}@media(max-width:700px){.notice{padding:18px 14px 14px}.overview{grid-template-columns:1fr;gap:18px}header strong{font-size:17px}.icon{width:36px;height:36px}.progress{margin:0 0 4px}.issues-heading{align-items:flex-start;flex-direction:column;gap:4px}.issues-heading>span{text-align:left}.issues li{grid-template-columns:8px minmax(0,1fr);gap:8px 10px}.code{grid-column:2;justify-self:start}}\n"] }]
180
+ }], propDecorators: { rejection: [{
181
+ type: Input,
182
+ args: [{ required: true }]
183
+ }], submittedAt: [{
184
+ type: Input
185
+ }], title: [{
186
+ type: Input
187
+ }], appearance: [{
188
+ type: Input
189
+ }] } });
190
+
88
191
  class MindBillBillLifecycleComponent {
89
192
  billId = "";
90
193
  sessionEndpoint = "/api/mindbill/session";
@@ -117,8 +220,7 @@ class MindBillBillLifecycleComponent {
117
220
  }
118
221
  ngOnDestroy() { this.store.disconnect(); }
119
222
  get themeStyle() {
120
- const base = THEMES[this.appearance.preset ?? "mindbill"];
121
- return { "--a": this.appearance.accentColor ?? base.accentColor, "--ac": this.appearance.accentTextColor ?? base.accentTextColor, "--bg": this.appearance.backgroundColor ?? base.backgroundColor, "--s": this.appearance.surfaceColor ?? base.surfaceColor, "--t": this.appearance.textColor ?? base.textColor, "--m": this.appearance.mutedColor ?? base.mutedColor, "--b": this.appearance.borderColor ?? base.borderColor, "--r": this.appearance.borderRadius ?? base.borderRadius, "--cr": this.appearance.controlRadius ?? base.controlRadius, "--font": this.appearance.fontFamily ?? base.fontFamily };
223
+ return mindBillAngularAppearanceStyle(this.appearance);
122
224
  }
123
225
  stateLabel(data) { return data.lifecycle.state.replace(/_/g, " ").replace(/\b\w/g, (value) => value.toUpperCase()); }
124
226
  lifecycleDetail(data) { return data.lifecycle.submittedAt ? `Submitted ${new Date(data.lifecycle.submittedAt).toLocaleDateString()}${data.lifecycle.agingDays != null ? ` · ${data.lifecycle.agingDays} days old` : ""}` : "Submitted bill"; }
@@ -159,9 +261,18 @@ class MindBillBillLifecycleComponent {
159
261
  <div class="money"><span>{{ data.bill.balanceDue | currency }}</span><small>balance</small></div>
160
262
  </header>
161
263
 
162
- <section class="card progress" aria-label="Bill lifecycle">
163
- <ol>@for (stage of lifecycleStages; track stage.id; let i=$index) { <li [class.complete]="i < currentStageIndex(data)" [class.current]="i === currentStageIndex(data)"><b>{{ i < currentStageIndex(data) ? '✓' : i + 1 }}</b><span>{{ stage.label }}</span></li> }</ol>
164
- </section>
264
+ @if (data.lifecycle.state.toLowerCase() === 'rejected' && data.rejection) {
265
+ <mindbill-bill-rejection-notice
266
+ class="rejection"
267
+ [rejection]="data.rejection"
268
+ [submittedAt]="data.lifecycle.submittedAt ?? null"
269
+ [appearance]="appearance"
270
+ />
271
+ } @else {
272
+ <section class="card progress" aria-label="Bill lifecycle">
273
+ <ol>@for (stage of lifecycleStages; track stage.id; let i=$index) { <li [class.complete]="i < currentStageIndex(data)" [class.current]="i === currentStageIndex(data)"><b>{{ i < currentStageIndex(data) ? '✓' : i + 1 }}</b><span>{{ stage.label }}</span></li> }</ol>
274
+ </section>
275
+ }
165
276
 
166
277
  <section class="card snapshot" aria-label="Bill snapshot">
167
278
  <div class="card-title"><div><h3>Bill snapshot</h3><p>The immutable values submitted to the payer.</p></div></div>
@@ -187,11 +298,11 @@ class MindBillBillLifecycleComponent {
187
298
  @if (panel === 'close') { <form class="card action-form" (submit)="$event.preventDefault(); closeBill()"><h3>Close bill</h3><label>Reason<textarea required [(ngModel)]="closeReason" name="closeReason"></textarea></label><div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit">Close bill</button></div></form> }
188
299
  }
189
300
  </section>
190
- `, isInline: true, styles: [":host{display:block}.mb{font-family:var(--font);color:var(--t);background:var(--bg);padding:20px}.summary,.card,.columns{max-width:1120px;margin:0 auto 16px}.summary{display:flex;justify-content:space-between;align-items:end}.summary h2{margin:4px 0}.summary p,.muted{color:var(--m)}.eyebrow,dt{font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--m)}.money{text-align:right}.money span{display:block;font-size:28px;font-weight:800}.money small{color:var(--m)}.card{background:var(--s);border:1px solid var(--b);border-radius:var(--r);padding:20px}.card-title{display:flex;justify-content:space-between;gap:20px}.card-title h3{margin:0}.card-title p{margin:5px 0;color:var(--m)}.progress ol{display:flex;list-style:none;padding:0;margin:0}.progress li{flex:1;text-align:center;position:relative;color:var(--m)}.progress li:before{content:\"\";position:absolute;top:16px;left:0;right:0;border-top:2px solid var(--b)}.progress li:first-child:before{left:50%}.progress li:last-child:before{right:50%}.progress b{position:relative;z-index:1;display:grid;place-items:center;width:32px;height:32px;margin:auto;border:2px solid var(--b);border-radius:50%;background:var(--s)}.progress .complete b,.progress .current b{border-color:var(--a);background:var(--a);color:var(--ac)}.progress span{display:block;margin-top:8px;font-size:12px;font-weight:700}.snapshot dl,.columns dl{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}.snapshot dd,.columns dd{font-weight:700;margin:6px 0}.columns{display:grid;grid-template-columns:1fr 1fr;gap:16px}.columns .card{margin:0}.rows,.timeline{list-style:none;margin:12px 0 0;padding:0}.rows li{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-top:1px solid var(--b)}.rows small{display:block;color:var(--m);margin-top:3px}.timeline li{display:flex;gap:14px;padding:10px 0}.timeline i{width:10px;height:10px;margin-top:5px;border:3px solid var(--a);border-radius:50%}.timeline p{margin:4px 0}.timeline small{color:var(--m)}button,input,select,textarea{font:inherit;border:1px solid var(--b);border-radius:var(--cr);padding:9px 12px;background:var(--s);color:var(--t)}button{cursor:pointer;font-weight:700}.primary{background:var(--a);border-color:var(--a);color:var(--ac)}.actions{max-width:1120px;margin:0 auto;display:flex;justify-content:flex-end;gap:10px}.action-form{display:grid;gap:12px}.action-form label{display:grid;gap:5px;font-weight:700}.action-form div{display:flex;justify-content:flex-end;gap:10px}.state{max-width:720px;margin:auto;padding:32px;text-align:center}.state span{display:block;margin:8px}.error{color:#9b1c1c}.notice{max-width:1120px;margin:0 auto 12px;color:var(--m)}@media(max-width:760px){.mb{padding:12px}.summary,.columns{display:block}.money{text-align:left;margin-top:12px}.columns .card{margin-bottom:12px}.snapshot dl,.columns dl{grid-template-columns:1fr 1fr}.progress span{font-size:10px}.card{padding:15px}}\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.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" }] });
301
+ `, isInline: true, styles: [":host{display:block}.mb{font-family:var(--font);color:var(--t);background:var(--bg);padding:20px}.summary,.card,.columns,.rejection{display:block;max-width:1120px;margin:0 auto 16px}.summary{display:flex;justify-content:space-between;align-items:end}.summary h2{margin:4px 0}.summary p,.muted{color:var(--m)}.eyebrow,dt{font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--m)}.money{text-align:right}.money span{display:block;font-size:28px;font-weight:800}.money small{color:var(--m)}.card{background:var(--s);border:1px solid var(--b);border-radius:var(--r);padding:20px}.card-title{display:flex;justify-content:space-between;gap:20px}.card-title h3{margin:0}.card-title p{margin:5px 0;color:var(--m)}.progress ol{display:flex;list-style:none;padding:0;margin:0}.progress li{flex:1;text-align:center;position:relative;color:var(--m)}.progress li:before{content:\"\";position:absolute;top:16px;left:0;right:0;border-top:2px solid var(--b)}.progress li:first-child:before{left:50%}.progress li:last-child:before{right:50%}.progress b{position:relative;z-index:1;display:grid;place-items:center;width:32px;height:32px;margin:auto;border:2px solid var(--b);border-radius:50%;background:var(--s)}.progress .complete b,.progress .current b{border-color:var(--a);background:var(--a);color:var(--ac)}.progress span{display:block;margin-top:8px;font-size:12px;font-weight:700}.snapshot dl,.columns dl{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}.snapshot dd,.columns dd{font-weight:700;margin:6px 0}.columns{display:grid;grid-template-columns:1fr 1fr;gap:16px}.columns .card{margin:0}.rows,.timeline{list-style:none;margin:12px 0 0;padding:0}.rows li{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-top:1px solid var(--b)}.rows small{display:block;color:var(--m);margin-top:3px}.timeline li{display:flex;gap:14px;padding:10px 0}.timeline i{width:10px;height:10px;margin-top:5px;border:3px solid var(--a);border-radius:50%}.timeline p{margin:4px 0}.timeline small{color:var(--m)}button,input,select,textarea{font:inherit;border:1px solid var(--b);border-radius:var(--cr);padding:9px 12px;background:var(--s);color:var(--t)}button{cursor:pointer;font-weight:700}.primary{background:var(--a);border-color:var(--a);color:var(--ac)}.actions{max-width:1120px;margin:0 auto;display:flex;justify-content:flex-end;gap:10px}.action-form{display:grid;gap:12px}.action-form label{display:grid;gap:5px;font-weight:700}.action-form div{display:flex;justify-content:flex-end;gap:10px}.state{max-width:720px;margin:auto;padding:32px;text-align:center}.state span{display:block;margin:8px}.error{color:#9b1c1c}.notice{max-width:1120px;margin:0 auto 12px;color:var(--m)}@media(max-width:760px){.mb{padding:12px}.summary,.columns{display:block}.money{text-align:left;margin-top:12px}.columns .card{margin-bottom:12px}.snapshot dl,.columns dl{grid-template-columns:1fr 1fr}.progress span{font-size:10px}.card{padding:15px}}\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.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: "component", type: MindBillBillRejectionNoticeComponent, selector: "mindbill-bill-rejection-notice", inputs: ["rejection", "submittedAt", "title", "appearance"] }, { kind: "pipe", type: i1.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i1.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i1.DatePipe, name: "date" }] });
191
302
  }
192
303
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillBillLifecycleComponent, decorators: [{
193
304
  type: Component,
194
- args: [{ selector: "mindbill-bill-lifecycle", standalone: true, imports: [CommonModule, FormsModule], template: `
305
+ args: [{ selector: "mindbill-bill-lifecycle", standalone: true, imports: [CommonModule, FormsModule, MindBillBillRejectionNoticeComponent], template: `
195
306
  <section class="mb" [ngStyle]="themeStyle">
196
307
  @if (!billId) {
197
308
  <div class="state error"><strong>A submitted bill ID is required.</strong></div>
@@ -205,9 +316,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
205
316
  <div class="money"><span>{{ data.bill.balanceDue | currency }}</span><small>balance</small></div>
206
317
  </header>
207
318
 
208
- <section class="card progress" aria-label="Bill lifecycle">
209
- <ol>@for (stage of lifecycleStages; track stage.id; let i=$index) { <li [class.complete]="i < currentStageIndex(data)" [class.current]="i === currentStageIndex(data)"><b>{{ i < currentStageIndex(data) ? '✓' : i + 1 }}</b><span>{{ stage.label }}</span></li> }</ol>
210
- </section>
319
+ @if (data.lifecycle.state.toLowerCase() === 'rejected' && data.rejection) {
320
+ <mindbill-bill-rejection-notice
321
+ class="rejection"
322
+ [rejection]="data.rejection"
323
+ [submittedAt]="data.lifecycle.submittedAt ?? null"
324
+ [appearance]="appearance"
325
+ />
326
+ } @else {
327
+ <section class="card progress" aria-label="Bill lifecycle">
328
+ <ol>@for (stage of lifecycleStages; track stage.id; let i=$index) { <li [class.complete]="i < currentStageIndex(data)" [class.current]="i === currentStageIndex(data)"><b>{{ i < currentStageIndex(data) ? '✓' : i + 1 }}</b><span>{{ stage.label }}</span></li> }</ol>
329
+ </section>
330
+ }
211
331
 
212
332
  <section class="card snapshot" aria-label="Bill snapshot">
213
333
  <div class="card-title"><div><h3>Bill snapshot</h3><p>The immutable values submitted to the payer.</p></div></div>
@@ -233,7 +353,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
233
353
  @if (panel === 'close') { <form class="card action-form" (submit)="$event.preventDefault(); closeBill()"><h3>Close bill</h3><label>Reason<textarea required [(ngModel)]="closeReason" name="closeReason"></textarea></label><div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit">Close bill</button></div></form> }
234
354
  }
235
355
  </section>
236
- `, styles: [":host{display:block}.mb{font-family:var(--font);color:var(--t);background:var(--bg);padding:20px}.summary,.card,.columns{max-width:1120px;margin:0 auto 16px}.summary{display:flex;justify-content:space-between;align-items:end}.summary h2{margin:4px 0}.summary p,.muted{color:var(--m)}.eyebrow,dt{font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--m)}.money{text-align:right}.money span{display:block;font-size:28px;font-weight:800}.money small{color:var(--m)}.card{background:var(--s);border:1px solid var(--b);border-radius:var(--r);padding:20px}.card-title{display:flex;justify-content:space-between;gap:20px}.card-title h3{margin:0}.card-title p{margin:5px 0;color:var(--m)}.progress ol{display:flex;list-style:none;padding:0;margin:0}.progress li{flex:1;text-align:center;position:relative;color:var(--m)}.progress li:before{content:\"\";position:absolute;top:16px;left:0;right:0;border-top:2px solid var(--b)}.progress li:first-child:before{left:50%}.progress li:last-child:before{right:50%}.progress b{position:relative;z-index:1;display:grid;place-items:center;width:32px;height:32px;margin:auto;border:2px solid var(--b);border-radius:50%;background:var(--s)}.progress .complete b,.progress .current b{border-color:var(--a);background:var(--a);color:var(--ac)}.progress span{display:block;margin-top:8px;font-size:12px;font-weight:700}.snapshot dl,.columns dl{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}.snapshot dd,.columns dd{font-weight:700;margin:6px 0}.columns{display:grid;grid-template-columns:1fr 1fr;gap:16px}.columns .card{margin:0}.rows,.timeline{list-style:none;margin:12px 0 0;padding:0}.rows li{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-top:1px solid var(--b)}.rows small{display:block;color:var(--m);margin-top:3px}.timeline li{display:flex;gap:14px;padding:10px 0}.timeline i{width:10px;height:10px;margin-top:5px;border:3px solid var(--a);border-radius:50%}.timeline p{margin:4px 0}.timeline small{color:var(--m)}button,input,select,textarea{font:inherit;border:1px solid var(--b);border-radius:var(--cr);padding:9px 12px;background:var(--s);color:var(--t)}button{cursor:pointer;font-weight:700}.primary{background:var(--a);border-color:var(--a);color:var(--ac)}.actions{max-width:1120px;margin:0 auto;display:flex;justify-content:flex-end;gap:10px}.action-form{display:grid;gap:12px}.action-form label{display:grid;gap:5px;font-weight:700}.action-form div{display:flex;justify-content:flex-end;gap:10px}.state{max-width:720px;margin:auto;padding:32px;text-align:center}.state span{display:block;margin:8px}.error{color:#9b1c1c}.notice{max-width:1120px;margin:0 auto 12px;color:var(--m)}@media(max-width:760px){.mb{padding:12px}.summary,.columns{display:block}.money{text-align:left;margin-top:12px}.columns .card{margin-bottom:12px}.snapshot dl,.columns dl{grid-template-columns:1fr 1fr}.progress span{font-size:10px}.card{padding:15px}}\n"] }]
356
+ `, styles: [":host{display:block}.mb{font-family:var(--font);color:var(--t);background:var(--bg);padding:20px}.summary,.card,.columns,.rejection{display:block;max-width:1120px;margin:0 auto 16px}.summary{display:flex;justify-content:space-between;align-items:end}.summary h2{margin:4px 0}.summary p,.muted{color:var(--m)}.eyebrow,dt{font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--m)}.money{text-align:right}.money span{display:block;font-size:28px;font-weight:800}.money small{color:var(--m)}.card{background:var(--s);border:1px solid var(--b);border-radius:var(--r);padding:20px}.card-title{display:flex;justify-content:space-between;gap:20px}.card-title h3{margin:0}.card-title p{margin:5px 0;color:var(--m)}.progress ol{display:flex;list-style:none;padding:0;margin:0}.progress li{flex:1;text-align:center;position:relative;color:var(--m)}.progress li:before{content:\"\";position:absolute;top:16px;left:0;right:0;border-top:2px solid var(--b)}.progress li:first-child:before{left:50%}.progress li:last-child:before{right:50%}.progress b{position:relative;z-index:1;display:grid;place-items:center;width:32px;height:32px;margin:auto;border:2px solid var(--b);border-radius:50%;background:var(--s)}.progress .complete b,.progress .current b{border-color:var(--a);background:var(--a);color:var(--ac)}.progress span{display:block;margin-top:8px;font-size:12px;font-weight:700}.snapshot dl,.columns dl{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}.snapshot dd,.columns dd{font-weight:700;margin:6px 0}.columns{display:grid;grid-template-columns:1fr 1fr;gap:16px}.columns .card{margin:0}.rows,.timeline{list-style:none;margin:12px 0 0;padding:0}.rows li{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-top:1px solid var(--b)}.rows small{display:block;color:var(--m);margin-top:3px}.timeline li{display:flex;gap:14px;padding:10px 0}.timeline i{width:10px;height:10px;margin-top:5px;border:3px solid var(--a);border-radius:50%}.timeline p{margin:4px 0}.timeline small{color:var(--m)}button,input,select,textarea{font:inherit;border:1px solid var(--b);border-radius:var(--cr);padding:9px 12px;background:var(--s);color:var(--t)}button{cursor:pointer;font-weight:700}.primary{background:var(--a);border-color:var(--a);color:var(--ac)}.actions{max-width:1120px;margin:0 auto;display:flex;justify-content:flex-end;gap:10px}.action-form{display:grid;gap:12px}.action-form label{display:grid;gap:5px;font-weight:700}.action-form div{display:flex;justify-content:flex-end;gap:10px}.state{max-width:720px;margin:auto;padding:32px;text-align:center}.state span{display:block;margin:8px}.error{color:#9b1c1c}.notice{max-width:1120px;margin:0 auto 12px;color:var(--m)}@media(max-width:760px){.mb{padding:12px}.summary,.columns{display:block}.money{text-align:left;margin-top:12px}.columns .card{margin-bottom:12px}.snapshot dl,.columns dl{grid-template-columns:1fr 1fr}.progress span{font-size:10px}.card{padding:15px}}\n"] }]
237
357
  }], ctorParameters: () => [], propDecorators: { billId: [{
238
358
  type: Input
239
359
  }], sessionEndpoint: [{
@@ -275,7 +395,7 @@ function ensureTrailingProcedureLine(lines) {
275
395
  : entered;
276
396
  }
277
397
 
278
- const THEME$3 = {
398
+ const THEME$4 = {
279
399
  mindbill: { a: "#238dbd", ac: "#fff", bg: "#f3f8fa", s: "#fff", t: "#203743", m: "#657982", b: "#dbe6ea", r: "14px", cr: "8px", font: "Inter,system-ui,sans-serif" },
280
400
  "qme-companion": { a: "#53b5dc", ac: "#173542", bg: "#f2f8fb", s: "#fff", t: "#1d3440", m: "#617783", b: "#d7e5eb", r: "12px", cr: "8px", font: "Inter,system-ui,sans-serif" },
281
401
  "orange-bright": { a: "#f4510b", ac: "#fff", bg: "#fffaf6", s: "#fffefd", t: "#090f1f", m: "#626a73", b: "#e7e1da", r: "16px", cr: "10px", font: "Inter,system-ui,sans-serif" },
@@ -349,7 +469,7 @@ function buildMindBillReportCsv(rows) {
349
469
  class DashboardBase {
350
470
  appearance = { preset: "mindbill" };
351
471
  get themeStyle() {
352
- const base = THEME$3[this.appearance.preset ?? "mindbill"] ?? THEME$3["mindbill"];
472
+ const base = THEME$4[this.appearance.preset ?? "mindbill"] ?? THEME$4["mindbill"];
353
473
  return {
354
474
  "--a": this.appearance.accentColor ?? base["a"], "--ac": this.appearance.accentTextColor ?? base["ac"],
355
475
  "--bg": this.appearance.backgroundColor ?? base["bg"], "--s": this.appearance.surfaceColor ?? base["s"],
@@ -512,7 +632,7 @@ function buildMindBillStatusAgingCsv(bills, stateOrder) {
512
632
  return [header, ...lines].map((line) => line.map(quote).join(",")).join("\n");
513
633
  }
514
634
 
515
- const THEME$2 = {
635
+ const THEME$3 = {
516
636
  mindbill: { a: "#238dbd", ac: "#fff", bg: "#f3f8fa", s: "#fff", t: "#203743", m: "#657982", b: "#dbe6ea", r: "14px", cr: "8px", font: "Inter,system-ui,sans-serif" },
517
637
  "qme-companion": { a: "#53b5dc", ac: "#173542", bg: "#f2f8fb", s: "#fff", t: "#1d3440", m: "#617783", b: "#d7e5eb", r: "12px", cr: "8px", font: "Inter,system-ui,sans-serif" },
518
638
  "orange-bright": { a: "#f4510b", ac: "#fff", bg: "#fffaf6", s: "#fffefd", t: "#090f1f", m: "#626a73", b: "#e7e1da", r: "16px", cr: "10px", font: "Inter,system-ui,sans-serif" },
@@ -531,7 +651,7 @@ class MindBillStatusAgingMatrixComponent {
531
651
  return buildMindBillStatusAgingMatrix(this.bills, this.stateOrder);
532
652
  }
533
653
  get themeStyle() {
534
- const base = THEME$2[this.appearance.preset ?? "mindbill"] ?? THEME$2["mindbill"];
654
+ const base = THEME$3[this.appearance.preset ?? "mindbill"] ?? THEME$3["mindbill"];
535
655
  return {
536
656
  "--a": this.appearance.accentColor ?? base["a"], "--ac": this.appearance.accentTextColor ?? base["ac"],
537
657
  "--bg": this.appearance.backgroundColor ?? base["bg"], "--s": this.appearance.surfaceColor ?? base["s"],
@@ -968,7 +1088,7 @@ const QUICK_DIAGNOSES = [
968
1088
  { label: "Left knee", code: "M25.562", description: "Pain in left knee" },
969
1089
  { label: "Right knee", code: "M25.561", description: "Pain in right knee" },
970
1090
  ];
971
- const THEME$1 = {
1091
+ const THEME$2 = {
972
1092
  mindbill: { a: "#238dbd", ac: "#fff", bg: "#f3f8fa", s: "#fff", t: "#203743", m: "#657982", b: "#dbe6ea", r: "14px", cr: "8px", font: "Inter,system-ui,sans-serif" },
973
1093
  "qme-companion": { a: "#53b5dc", ac: "#173542", bg: "#f2f8fb", s: "#fff", t: "#1d3440", m: "#617783", b: "#d7e5eb", r: "12px", cr: "8px", font: "Inter,system-ui,sans-serif" },
974
1094
  "orange-bright": { a: "#f4510b", ac: "#fff", bg: "#fffaf6", s: "#fffefd", t: "#090f1f", m: "#626a73", b: "#e7e1da", r: "16px", cr: "10px", font: "Inter,system-ui,sans-serif" },
@@ -1041,7 +1161,7 @@ class MindBillBillSubmissionComponent {
1041
1161
  this.workingAttachments = this.attachments.map((item) => ({ ...item }));
1042
1162
  }
1043
1163
  get themeStyle() {
1044
- const base = THEME$1[this.appearance.preset ?? "mindbill"] ?? THEME$1["mindbill"];
1164
+ const base = THEME$2[this.appearance.preset ?? "mindbill"] ?? THEME$2["mindbill"];
1045
1165
  return {
1046
1166
  "--a": this.appearance.accentColor ?? base["a"], "--ac": this.appearance.accentTextColor ?? base["ac"],
1047
1167
  "--bg": this.appearance.backgroundColor ?? base["bg"], "--s": this.appearance.surfaceColor ?? base["s"],
@@ -1593,7 +1713,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
1593
1713
  args: ["window:drop", ["$event"]]
1594
1714
  }] } });
1595
1715
 
1596
- const THEME = {
1716
+ const THEME$1 = {
1597
1717
  mindbill: { a: "#238dbd", ac: "#fff", b: "#dbe6ea", r: "8px", font: "Inter,system-ui,sans-serif" },
1598
1718
  "qme-companion": { a: "#53b5dc", ac: "#173542", b: "#d7e5eb", r: "8px", font: "Inter,system-ui,sans-serif" },
1599
1719
  "orange-bright": { a: "#f4510b", ac: "#fff", b: "#e7e1da", r: "10px", font: "Inter,system-ui,sans-serif" },
@@ -1611,7 +1731,7 @@ class MindBillBillingManagementButtonComponent {
1611
1731
  errorMessage = "";
1612
1732
  changeDetector = inject(ChangeDetectorRef);
1613
1733
  get themeStyle() {
1614
- const base = THEME[this.appearance.preset ?? "mindbill"] ?? THEME["mindbill"];
1734
+ const base = THEME$1[this.appearance.preset ?? "mindbill"] ?? THEME$1["mindbill"];
1615
1735
  return {
1616
1736
  "--a": this.appearance.accentColor ?? base["a"],
1617
1737
  "--ac": this.appearance.accentTextColor ?? base["ac"],
@@ -1700,9 +1820,342 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
1700
1820
  type: Output
1701
1821
  }] } });
1702
1822
 
1823
+ // Embeddable organization onboarding (INC-1470): practice identity, billing
1824
+ // provider, locations, and the W-9 captured once and saved straight to
1825
+ // MindBill through the partner browser session (organization:manage
1826
+ // permission). variant="settings" stacks every section for edit-after-setup.
1827
+ const THEME = {
1828
+ mindbill: { a: "#238dbd", ac: "#fff", bg: "#f3f8fa", s: "#fff", t: "#203743", m: "#657982", b: "#dbe6ea", r: "14px", cr: "8px", font: "Inter,system-ui,sans-serif" },
1829
+ "qme-companion": { a: "#53b5dc", ac: "#173542", bg: "#f2f8fb", s: "#fff", t: "#1d3440", m: "#617783", b: "#d7e5eb", r: "12px", cr: "8px", font: "Inter,system-ui,sans-serif" },
1830
+ "orange-bright": { a: "#f4510b", ac: "#fff", bg: "#fffaf6", s: "#fffefd", t: "#090f1f", m: "#626a73", b: "#e7e1da", r: "16px", cr: "10px", font: "Inter,system-ui,sans-serif" },
1831
+ "clinical-blue": { a: "#1677ff", ac: "#fff", bg: "#fff", s: "#fff", t: "#1f2d3d", m: "#66788a", b: "#d9e2ec", r: "8px", cr: "6px", font: "Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" },
1832
+ };
1833
+ async function fileToBase64(file) {
1834
+ const buffer = new Uint8Array(await file.arrayBuffer());
1835
+ let binary = "";
1836
+ for (const byte of buffer)
1837
+ binary += String.fromCharCode(byte);
1838
+ return btoa(binary);
1839
+ }
1840
+ class MindBillOrganizationOnboardingComponent {
1841
+ appearance = { preset: "mindbill" };
1842
+ sessionEndpoint = "/api/mindbill/session";
1843
+ getSession;
1844
+ apiBaseUrl;
1845
+ heading = "Billing setup";
1846
+ description = "Practice identity, locations, and the W-9 — saved once, used on every bill.";
1847
+ variant = "onboarding";
1848
+ saved$ = new EventEmitter();
1849
+ completed = new EventEmitter();
1850
+ organizationError = new EventEmitter();
1851
+ steps = [
1852
+ { id: "practice", label: "Practice & billing" },
1853
+ { id: "locations", label: "Locations" },
1854
+ { id: "w9", label: "W-9" },
1855
+ { id: "review", label: "Review" },
1856
+ ];
1857
+ profile = null;
1858
+ loadError = "";
1859
+ errorMessage = "";
1860
+ step = "practice";
1861
+ saving = false;
1862
+ saved = {};
1863
+ identity = { name: "", legalName: "", taxId: "", npi: "", phone: "", email: "" };
1864
+ provider = { name: "", taxId: "", npi: "", billType: "Professional", phone: "", billingStreet: "", billingCity: "", billingState: "", billingZip: "" };
1865
+ locations = [{ name: "", street: "", city: "", state: "", zip: "", isPrimary: false }];
1866
+ w9File = null;
1867
+ changeDetector = inject(ChangeDetectorRef);
1868
+ completedFired = false;
1869
+ client;
1870
+ ngOnInit() {
1871
+ this.client = createOrganizationClient({
1872
+ sessionEndpoint: this.sessionEndpoint,
1873
+ ...(this.getSession ? { getSession: this.getSession } : {}),
1874
+ ...(this.apiBaseUrl ? { apiBaseUrl: this.apiBaseUrl } : {}),
1875
+ });
1876
+ this.client.getOrganization()
1877
+ .then((profile) => { this.loadError = ""; this.adoptProfile(profile); })
1878
+ .catch((error) => {
1879
+ const failure = error instanceof Error ? error : new Error("The organization could not be loaded.");
1880
+ this.loadError = failure.message;
1881
+ this.organizationError.emit(failure);
1882
+ })
1883
+ .finally(() => this.changeDetector.markForCheck());
1884
+ }
1885
+ get themeStyle() {
1886
+ const base = THEME[this.appearance.preset ?? "mindbill"] ?? THEME["mindbill"];
1887
+ return {
1888
+ "--a": this.appearance.accentColor ?? base["a"], "--ac": this.appearance.accentTextColor ?? base["ac"],
1889
+ "--bg": this.appearance.backgroundColor ?? base["bg"], "--s": this.appearance.surfaceColor ?? base["s"],
1890
+ "--t": this.appearance.textColor ?? base["t"], "--m": this.appearance.mutedColor ?? base["m"],
1891
+ "--b": this.appearance.borderColor ?? base["b"], "--r": this.appearance.borderRadius ?? base["r"],
1892
+ "--cr": this.appearance.controlRadius ?? base["cr"], "--font": this.appearance.fontFamily ?? base["font"],
1893
+ };
1894
+ }
1895
+ adoptProfile(profile) {
1896
+ this.profile = profile;
1897
+ this.identity = {
1898
+ name: profile.practiceIdentity.name ?? this.identity.name,
1899
+ legalName: profile.practiceIdentity.legalName ?? this.identity.legalName,
1900
+ taxId: profile.practiceIdentity.taxId ?? this.identity.taxId,
1901
+ npi: profile.practiceIdentity.npi ?? this.identity.npi,
1902
+ phone: profile.practiceIdentity.phone ?? this.identity.phone,
1903
+ email: profile.practiceIdentity.email ?? this.identity.email,
1904
+ };
1905
+ if (profile.billingProviders[0])
1906
+ this.provider = { billType: "Professional", ...profile.billingProviders[0] };
1907
+ if (profile.locations.length)
1908
+ this.locations = profile.locations.map((item) => ({ ...item }));
1909
+ if (profile.onboarding.complete && !this.completedFired) {
1910
+ this.completedFired = true;
1911
+ this.completed.emit(profile);
1912
+ }
1913
+ }
1914
+ addLocation() {
1915
+ this.locations.push({ name: "", street: "", city: "", state: "", zip: "", isPrimary: false });
1916
+ }
1917
+ setPrimary(index) {
1918
+ this.locations = this.locations.map((item, itemIndex) => ({ ...item, isPrimary: itemIndex === index }));
1919
+ }
1920
+ w9Selected(event) {
1921
+ this.w9File = event.target.files?.[0] ?? null;
1922
+ }
1923
+ async run(work, stepId) {
1924
+ this.saving = true;
1925
+ this.errorMessage = "";
1926
+ try {
1927
+ const profile = await work();
1928
+ this.adoptProfile(profile);
1929
+ this.saved[stepId] = true;
1930
+ this.saved$.emit(profile);
1931
+ if (this.variant === "onboarding") {
1932
+ const order = ["practice", "locations", "w9", "review"];
1933
+ const next = order[order.indexOf(stepId) + 1];
1934
+ if (next)
1935
+ this.step = next;
1936
+ }
1937
+ }
1938
+ catch (error) {
1939
+ const failure = error instanceof Error ? error : new Error("Saving failed.");
1940
+ this.errorMessage = failure.message;
1941
+ this.organizationError.emit(failure);
1942
+ }
1943
+ finally {
1944
+ this.saving = false;
1945
+ this.changeDetector.markForCheck();
1946
+ }
1947
+ }
1948
+ savePractice() {
1949
+ void this.run(() => this.client.saveBillingProfile({
1950
+ practiceIdentity: this.identity,
1951
+ ...(this.provider.name.trim() || this.provider.taxId.trim() || this.provider.npi.trim()
1952
+ ? { billingProviders: [this.provider] }
1953
+ : {}),
1954
+ }), "practice");
1955
+ }
1956
+ saveLocations() {
1957
+ void this.run(() => this.client.saveLocations(this.locations.filter((item) => item.name.trim() || item.street.trim())), "locations");
1958
+ }
1959
+ saveW9() {
1960
+ void this.run(async () => {
1961
+ if (!this.w9File)
1962
+ throw new Error("Choose the practice W-9 PDF first.");
1963
+ return this.client.saveW9({ filename: this.w9File.name, contentBase64: await fileToBase64(this.w9File) });
1964
+ }, "w9");
1965
+ }
1966
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillOrganizationOnboardingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1967
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: MindBillOrganizationOnboardingComponent, isStandalone: true, selector: "mindbill-organization-onboarding", inputs: { appearance: "appearance", sessionEndpoint: "sessionEndpoint", getSession: "getSession", apiBaseUrl: "apiBaseUrl", heading: "heading", description: "description", variant: "variant" }, outputs: { saved$: "saved$", completed: "completed", organizationError: "organizationError" }, ngImport: i0, template: `
1968
+ <section class="mbob" [ngStyle]="themeStyle">
1969
+ <div class="card">
1970
+ <header><h2>{{ heading }}</h2><p>{{ description }}</p></header>
1971
+ @if (loadError) { <div class="error" role="alert">{{ loadError }}</div> }
1972
+
1973
+ @if (variant === 'onboarding') {
1974
+ <div class="steps">
1975
+ @for (item of steps; track item.id) {
1976
+ <button type="button" [class.active]="step === item.id" [class.done]="saved[item.id]" (click)="step = item.id"><i>{{ saved[item.id] ? '✓' : '' }}</i>{{ item.label }}</button>
1977
+ }
1978
+ </div>
1979
+ }
1980
+
1981
+ @if (variant === 'settings' || step === 'practice') {
1982
+ <div class="grid">
1983
+ <label>Practice name<input [(ngModel)]="identity.name" [disabled]="saving"></label>
1984
+ <label>Legal name<input [(ngModel)]="identity.legalName" [disabled]="saving"></label>
1985
+ <label>Tax ID (EIN)<input [(ngModel)]="identity.taxId" placeholder="94-1234567" [disabled]="saving"></label>
1986
+ <label>Group NPI<input [(ngModel)]="identity.npi" [disabled]="saving"></label>
1987
+ <label>Phone<input [(ngModel)]="identity.phone" [disabled]="saving"></label>
1988
+ <label>Email<input [(ngModel)]="identity.email" [disabled]="saving"></label>
1989
+ </div>
1990
+ <h3>Billing provider (pay-to)</h3>
1991
+ <div class="grid">
1992
+ <label>Billing provider name<input [(ngModel)]="provider.name" [disabled]="saving"></label>
1993
+ <label>Billing tax ID<input [(ngModel)]="provider.taxId" [disabled]="saving"></label>
1994
+ <label>Billing NPI<input [(ngModel)]="provider.npi" [disabled]="saving"></label>
1995
+ <label>Billing phone<input [(ngModel)]="provider.phone" [disabled]="saving"></label>
1996
+ <label class="span">Street<input [(ngModel)]="provider.billingStreet" [disabled]="saving"></label>
1997
+ <label>City<input [(ngModel)]="provider.billingCity" [disabled]="saving"></label>
1998
+ <label>State<input [(ngModel)]="provider.billingState" maxlength="2" [disabled]="saving"></label>
1999
+ <label>ZIP<input [(ngModel)]="provider.billingZip" [disabled]="saving"></label>
2000
+ </div>
2001
+ <div class="actions"><span>{{ saved['practice'] ? 'Saved to MindBill.' : 'Saved once, used on every bill.' }}</span><button type="button" class="save" [disabled]="saving" (click)="savePractice()">{{ saving ? 'Saving…' : 'Save practice' }}</button></div>
2002
+ }
2003
+
2004
+ @if (variant === 'settings') { <h3>Locations</h3> }
2005
+ @if (variant === 'settings' || step === 'locations') {
2006
+ @for (location of locations; track $index; let index = $index) {
2007
+ <div class="loc">
2008
+ <label>Name<input [(ngModel)]="location.name" [disabled]="saving"></label>
2009
+ <label>Street<input [(ngModel)]="location.street" [disabled]="saving"></label>
2010
+ <label>City<input [(ngModel)]="location.city" [disabled]="saving"></label>
2011
+ <label>State<input [(ngModel)]="location.state" maxlength="2" [disabled]="saving"></label>
2012
+ <label>ZIP<input [(ngModel)]="location.zip" [disabled]="saving"></label>
2013
+ <label class="primary"><input type="radio" name="mbob-primary" [checked]="location.isPrimary === true" (change)="setPrimary(index)"> Primary</label>
2014
+ <button type="button" class="remove" aria-label="Remove location" (click)="locations.splice(index, 1)">×</button>
2015
+ </div>
2016
+ }
2017
+ <button type="button" class="add" (click)="addLocation()">+ Add location</button>
2018
+ <div class="actions"><span>{{ saved['locations'] ? 'Saved to MindBill.' : 'Where evaluations happen.' }}</span><button type="button" class="save" [disabled]="saving" (click)="saveLocations()">{{ saving ? 'Saving…' : 'Save locations' }}</button></div>
2019
+ }
2020
+
2021
+ @if (variant === 'settings') { <h3>Practice W-9</h3> }
2022
+ @if (variant === 'settings' || step === 'w9') {
2023
+ @if (profile?.w9; as w9) {
2024
+ <div class="w9-current"><div><strong>{{ w9.filename }}</strong><span> · added {{ w9.addDate }}</span></div><span>Rides on every bill automatically</span></div>
2025
+ }
2026
+ <label class="drop">
2027
+ <input type="file" accept="application/pdf,.pdf" (change)="w9Selected($event)">
2028
+ <strong>{{ w9File ? w9File.name : (profile?.w9 ? 'Replace the W-9 PDF' : 'Drop the practice W-9 PDF here, or click to choose') }}</strong>
2029
+ <span>The W-9 is auto-attached to every submission.</span>
2030
+ </label>
2031
+ <div class="actions"><span>{{ saved['w9'] ? 'Saved to MindBill.' : '' }}</span><button type="button" class="save" [disabled]="saving || !w9File" (click)="saveW9()">{{ saving ? 'Uploading…' : 'Save W-9' }}</button></div>
2032
+ }
2033
+
2034
+ @if (variant === 'settings') { <h3>Checklist</h3> }
2035
+ @if (variant === 'settings' || step === 'review') {
2036
+ <div class="check">
2037
+ @for (item of profile?.onboarding?.checklist ?? []; track item.id) {
2038
+ <div class="check-item" [class.complete]="item.complete"><i>{{ item.complete ? '✓' : '•' }}</i><span>{{ item.label }}</span></div>
2039
+ }
2040
+ @if (profile?.onboarding?.complete) { <p class="done-copy">Billing setup is complete — bills submitted from your product carry this profile automatically.</p> }
2041
+ @else { <p class="muted">Items above complete themselves as each section is saved.</p> }
2042
+ </div>
2043
+ }
2044
+
2045
+ @if (errorMessage) { <div class="error" role="alert">{{ errorMessage }}</div> }
2046
+ </div>
2047
+ </section>
2048
+ `, isInline: true, styles: [":host{display:block}.mbob{font-family:var(--font);color:var(--t);font-size:15px}.mbob *{box-sizing:border-box}.card{border:1px solid var(--b);border-radius:var(--r);background:var(--s);padding:24px}header{margin-bottom:18px}header h2{margin:0;font-size:22px}header p{margin:5px 0 0;color:var(--m)}.steps{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}.steps button{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--b);border-radius:999px;background:var(--s);padding:7px 13px;color:var(--m);font:inherit;font-size:13px;font-weight:700;cursor:pointer}.steps button.active{border-color:var(--a);color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.steps button.done i{color:#159447;font-style:normal}.grid{display:grid;grid-template-columns:1fr 1fr;gap:16px 22px}.span{grid-column:1/-1}label{display:grid;gap:7px;font-size:13px;font-weight:720}input:not([type=radio]):not([type=file]){width:100%;min-height:44px;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 12px;color:var(--t);font:inherit;font-weight:450}input:focus{outline:3px solid color-mix(in srgb,var(--a) 22%,transparent);border-color:var(--a)}h3{margin:20px 0 12px;padding-top:16px;border-top:1px solid var(--b);font-size:15px}.loc{display:grid;grid-template-columns:1.2fr 1.4fr .9fr .4fr .6fr auto auto;gap:10px;align-items:end;border-top:1px solid color-mix(in srgb,var(--b) 60%,transparent);padding:12px 0}.loc:first-of-type{border-top:0}.primary{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--m);white-space:nowrap;padding-bottom:12px}.remove{border:0;background:transparent;color:var(--m);font-size:20px;cursor:pointer;padding-bottom:8px}.add{border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 14px;color:var(--t);font:inherit;font-weight:700;cursor:pointer}.drop{display:grid;place-content:center;gap:6px;min-height:150px;border:2px dashed color-mix(in srgb,var(--m) 55%,transparent);border-radius:var(--cr);text-align:center;cursor:pointer;position:relative}.drop input{position:absolute;inset:0;opacity:0;cursor:pointer}.drop span{color:var(--m);font-size:13px}.w9-current{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid #9fd6b4;border-radius:var(--cr);background:#f3fcf6;padding:12px 14px;margin-bottom:14px}.w9-current span{color:var(--m);font-size:13px}.check{display:grid;gap:9px}.check-item{display:flex;align-items:center;gap:10px;border:1px solid var(--b);border-radius:var(--cr);padding:11px 14px}.check-item.complete{border-color:#9fd6b4;background:#f3fcf6}.check-item i{font-style:normal}.actions{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-top:20px}.actions>span{color:var(--m)}.save{min-width:170px;border:0;border-radius:var(--cr);background:var(--a);color:var(--ac);padding:12px 22px;font:inherit;font-weight:780;cursor:pointer}.save:disabled{opacity:.6;cursor:wait}.error{margin-top:14px;border-left:4px solid #c83c3c;border-radius:var(--cr);background:color-mix(in srgb,#c83c3c 8%,var(--s));padding:12px 14px;color:#c83c3c}.done-copy{color:#159447;font-weight:750}.muted{color:var(--m)}@media(max-width:820px){.grid{grid-template-columns:1fr}.span{grid-column:auto}.loc{grid-template-columns:1fr 1fr;align-items:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
2049
+ }
2050
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillOrganizationOnboardingComponent, decorators: [{
2051
+ type: Component,
2052
+ args: [{ selector: "mindbill-organization-onboarding", standalone: true, imports: [CommonModule, FormsModule], template: `
2053
+ <section class="mbob" [ngStyle]="themeStyle">
2054
+ <div class="card">
2055
+ <header><h2>{{ heading }}</h2><p>{{ description }}</p></header>
2056
+ @if (loadError) { <div class="error" role="alert">{{ loadError }}</div> }
2057
+
2058
+ @if (variant === 'onboarding') {
2059
+ <div class="steps">
2060
+ @for (item of steps; track item.id) {
2061
+ <button type="button" [class.active]="step === item.id" [class.done]="saved[item.id]" (click)="step = item.id"><i>{{ saved[item.id] ? '✓' : '' }}</i>{{ item.label }}</button>
2062
+ }
2063
+ </div>
2064
+ }
2065
+
2066
+ @if (variant === 'settings' || step === 'practice') {
2067
+ <div class="grid">
2068
+ <label>Practice name<input [(ngModel)]="identity.name" [disabled]="saving"></label>
2069
+ <label>Legal name<input [(ngModel)]="identity.legalName" [disabled]="saving"></label>
2070
+ <label>Tax ID (EIN)<input [(ngModel)]="identity.taxId" placeholder="94-1234567" [disabled]="saving"></label>
2071
+ <label>Group NPI<input [(ngModel)]="identity.npi" [disabled]="saving"></label>
2072
+ <label>Phone<input [(ngModel)]="identity.phone" [disabled]="saving"></label>
2073
+ <label>Email<input [(ngModel)]="identity.email" [disabled]="saving"></label>
2074
+ </div>
2075
+ <h3>Billing provider (pay-to)</h3>
2076
+ <div class="grid">
2077
+ <label>Billing provider name<input [(ngModel)]="provider.name" [disabled]="saving"></label>
2078
+ <label>Billing tax ID<input [(ngModel)]="provider.taxId" [disabled]="saving"></label>
2079
+ <label>Billing NPI<input [(ngModel)]="provider.npi" [disabled]="saving"></label>
2080
+ <label>Billing phone<input [(ngModel)]="provider.phone" [disabled]="saving"></label>
2081
+ <label class="span">Street<input [(ngModel)]="provider.billingStreet" [disabled]="saving"></label>
2082
+ <label>City<input [(ngModel)]="provider.billingCity" [disabled]="saving"></label>
2083
+ <label>State<input [(ngModel)]="provider.billingState" maxlength="2" [disabled]="saving"></label>
2084
+ <label>ZIP<input [(ngModel)]="provider.billingZip" [disabled]="saving"></label>
2085
+ </div>
2086
+ <div class="actions"><span>{{ saved['practice'] ? 'Saved to MindBill.' : 'Saved once, used on every bill.' }}</span><button type="button" class="save" [disabled]="saving" (click)="savePractice()">{{ saving ? 'Saving…' : 'Save practice' }}</button></div>
2087
+ }
2088
+
2089
+ @if (variant === 'settings') { <h3>Locations</h3> }
2090
+ @if (variant === 'settings' || step === 'locations') {
2091
+ @for (location of locations; track $index; let index = $index) {
2092
+ <div class="loc">
2093
+ <label>Name<input [(ngModel)]="location.name" [disabled]="saving"></label>
2094
+ <label>Street<input [(ngModel)]="location.street" [disabled]="saving"></label>
2095
+ <label>City<input [(ngModel)]="location.city" [disabled]="saving"></label>
2096
+ <label>State<input [(ngModel)]="location.state" maxlength="2" [disabled]="saving"></label>
2097
+ <label>ZIP<input [(ngModel)]="location.zip" [disabled]="saving"></label>
2098
+ <label class="primary"><input type="radio" name="mbob-primary" [checked]="location.isPrimary === true" (change)="setPrimary(index)"> Primary</label>
2099
+ <button type="button" class="remove" aria-label="Remove location" (click)="locations.splice(index, 1)">×</button>
2100
+ </div>
2101
+ }
2102
+ <button type="button" class="add" (click)="addLocation()">+ Add location</button>
2103
+ <div class="actions"><span>{{ saved['locations'] ? 'Saved to MindBill.' : 'Where evaluations happen.' }}</span><button type="button" class="save" [disabled]="saving" (click)="saveLocations()">{{ saving ? 'Saving…' : 'Save locations' }}</button></div>
2104
+ }
2105
+
2106
+ @if (variant === 'settings') { <h3>Practice W-9</h3> }
2107
+ @if (variant === 'settings' || step === 'w9') {
2108
+ @if (profile?.w9; as w9) {
2109
+ <div class="w9-current"><div><strong>{{ w9.filename }}</strong><span> · added {{ w9.addDate }}</span></div><span>Rides on every bill automatically</span></div>
2110
+ }
2111
+ <label class="drop">
2112
+ <input type="file" accept="application/pdf,.pdf" (change)="w9Selected($event)">
2113
+ <strong>{{ w9File ? w9File.name : (profile?.w9 ? 'Replace the W-9 PDF' : 'Drop the practice W-9 PDF here, or click to choose') }}</strong>
2114
+ <span>The W-9 is auto-attached to every submission.</span>
2115
+ </label>
2116
+ <div class="actions"><span>{{ saved['w9'] ? 'Saved to MindBill.' : '' }}</span><button type="button" class="save" [disabled]="saving || !w9File" (click)="saveW9()">{{ saving ? 'Uploading…' : 'Save W-9' }}</button></div>
2117
+ }
2118
+
2119
+ @if (variant === 'settings') { <h3>Checklist</h3> }
2120
+ @if (variant === 'settings' || step === 'review') {
2121
+ <div class="check">
2122
+ @for (item of profile?.onboarding?.checklist ?? []; track item.id) {
2123
+ <div class="check-item" [class.complete]="item.complete"><i>{{ item.complete ? '✓' : '•' }}</i><span>{{ item.label }}</span></div>
2124
+ }
2125
+ @if (profile?.onboarding?.complete) { <p class="done-copy">Billing setup is complete — bills submitted from your product carry this profile automatically.</p> }
2126
+ @else { <p class="muted">Items above complete themselves as each section is saved.</p> }
2127
+ </div>
2128
+ }
2129
+
2130
+ @if (errorMessage) { <div class="error" role="alert">{{ errorMessage }}</div> }
2131
+ </div>
2132
+ </section>
2133
+ `, styles: [":host{display:block}.mbob{font-family:var(--font);color:var(--t);font-size:15px}.mbob *{box-sizing:border-box}.card{border:1px solid var(--b);border-radius:var(--r);background:var(--s);padding:24px}header{margin-bottom:18px}header h2{margin:0;font-size:22px}header p{margin:5px 0 0;color:var(--m)}.steps{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}.steps button{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--b);border-radius:999px;background:var(--s);padding:7px 13px;color:var(--m);font:inherit;font-size:13px;font-weight:700;cursor:pointer}.steps button.active{border-color:var(--a);color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.steps button.done i{color:#159447;font-style:normal}.grid{display:grid;grid-template-columns:1fr 1fr;gap:16px 22px}.span{grid-column:1/-1}label{display:grid;gap:7px;font-size:13px;font-weight:720}input:not([type=radio]):not([type=file]){width:100%;min-height:44px;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 12px;color:var(--t);font:inherit;font-weight:450}input:focus{outline:3px solid color-mix(in srgb,var(--a) 22%,transparent);border-color:var(--a)}h3{margin:20px 0 12px;padding-top:16px;border-top:1px solid var(--b);font-size:15px}.loc{display:grid;grid-template-columns:1.2fr 1.4fr .9fr .4fr .6fr auto auto;gap:10px;align-items:end;border-top:1px solid color-mix(in srgb,var(--b) 60%,transparent);padding:12px 0}.loc:first-of-type{border-top:0}.primary{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--m);white-space:nowrap;padding-bottom:12px}.remove{border:0;background:transparent;color:var(--m);font-size:20px;cursor:pointer;padding-bottom:8px}.add{border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 14px;color:var(--t);font:inherit;font-weight:700;cursor:pointer}.drop{display:grid;place-content:center;gap:6px;min-height:150px;border:2px dashed color-mix(in srgb,var(--m) 55%,transparent);border-radius:var(--cr);text-align:center;cursor:pointer;position:relative}.drop input{position:absolute;inset:0;opacity:0;cursor:pointer}.drop span{color:var(--m);font-size:13px}.w9-current{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid #9fd6b4;border-radius:var(--cr);background:#f3fcf6;padding:12px 14px;margin-bottom:14px}.w9-current span{color:var(--m);font-size:13px}.check{display:grid;gap:9px}.check-item{display:flex;align-items:center;gap:10px;border:1px solid var(--b);border-radius:var(--cr);padding:11px 14px}.check-item.complete{border-color:#9fd6b4;background:#f3fcf6}.check-item i{font-style:normal}.actions{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-top:20px}.actions>span{color:var(--m)}.save{min-width:170px;border:0;border-radius:var(--cr);background:var(--a);color:var(--ac);padding:12px 22px;font:inherit;font-weight:780;cursor:pointer}.save:disabled{opacity:.6;cursor:wait}.error{margin-top:14px;border-left:4px solid #c83c3c;border-radius:var(--cr);background:color-mix(in srgb,#c83c3c 8%,var(--s));padding:12px 14px;color:#c83c3c}.done-copy{color:#159447;font-weight:750}.muted{color:var(--m)}@media(max-width:820px){.grid{grid-template-columns:1fr}.span{grid-column:auto}.loc{grid-template-columns:1fr 1fr;align-items:center}}\n"] }]
2134
+ }], propDecorators: { appearance: [{
2135
+ type: Input
2136
+ }], sessionEndpoint: [{
2137
+ type: Input
2138
+ }], getSession: [{
2139
+ type: Input
2140
+ }], apiBaseUrl: [{
2141
+ type: Input
2142
+ }], heading: [{
2143
+ type: Input
2144
+ }], description: [{
2145
+ type: Input
2146
+ }], variant: [{
2147
+ type: Input
2148
+ }], saved$: [{
2149
+ type: Output
2150
+ }], completed: [{
2151
+ type: Output
2152
+ }], organizationError: [{
2153
+ type: Output
2154
+ }] } });
2155
+
1703
2156
  /**
1704
2157
  * Generated bundle index. Do not edit.
1705
2158
  */
1706
2159
 
1707
- export { MINDBILL_STATUS_AGING_BUCKETS, MindBillBillAgingSummaryComponent, MindBillBillLifecycleComponent, MindBillBillListComponent, MindBillBillSubmissionComponent, MindBillBillingDashboardComponent, MindBillBillingManagementButtonComponent, MindBillBillingReportComponent, MindBillComboBoxComponent, MindBillDateInputComponent, MindBillLifecycleStore, MindBillStatusAgingMatrixComponent, buildMindBillReportCsv, buildMindBillReportRows, buildMindBillStatusAgingCsv, buildMindBillStatusAgingMatrix, ensureTrailingProcedureLine, formatMindBillSubmissionDate, isEmptyProcedureLine, mindBillAgingBucket, mindBillAgingDays, mindBillCustomProcedureOption, parseMindBillSubmissionDate, summarizeMindBillDashboard };
2160
+ export { MINDBILL_STATUS_AGING_BUCKETS, MindBillBillAgingSummaryComponent, MindBillBillLifecycleComponent, MindBillBillListComponent, MindBillBillRejectionNoticeComponent, MindBillBillSubmissionComponent, MindBillBillingDashboardComponent, MindBillBillingManagementButtonComponent, MindBillBillingReportComponent, MindBillComboBoxComponent, MindBillDateInputComponent, MindBillLifecycleStore, MindBillOrganizationOnboardingComponent, MindBillStatusAgingMatrixComponent, billRejectionIssueSummary, billRejectionIssues, buildMindBillReportCsv, buildMindBillReportRows, buildMindBillStatusAgingCsv, buildMindBillStatusAgingMatrix, ensureTrailingProcedureLine, formatMindBillSubmissionDate, isEmptyProcedureLine, mindBillAgingBucket, mindBillAgingDays, mindBillAngularAppearanceStyle, mindBillCustomProcedureOption, parseMindBillSubmissionDate, summarizeMindBillDashboard };
1708
2161
  //# sourceMappingURL=mindbill-angular.mjs.map