@rolatech/angular-billing 20.3.2-beta.4 → 20.3.3-beta.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.
@@ -14,7 +14,7 @@ import * as i5 from '@angular/material/select';
14
14
  import { MatSelectModule } from '@angular/material/select';
15
15
  import * as i1$1 from '@angular/router';
16
16
  import { RouterModule, RouterLink } from '@angular/router';
17
- import { Skeleton, BaseComponent, PageCollectionShellComponent, ToolbarComponent, TabsComponent, TabComponent, EnumSelect, ConfirmationDialogComponent, MaterialModule } from '@rolatech/angular-components';
17
+ import { Skeleton, BaseComponent, PageCollectionShellComponent, ToolbarComponent, TabsComponent, TabComponent, EnumSelect, ConfirmationDialogComponent, MaterialModule, Breadcrumb } from '@rolatech/angular-components';
18
18
  import { PricePipe } from '@rolatech/angular-common';
19
19
  import { InvoiceService, PaymentService, EnumApiClient, BillingProfileService } from '@rolatech/angular-services';
20
20
  import * as i6 from '@angular/material/paginator';
@@ -75,7 +75,7 @@ var InvoiceStatus;
75
75
 
76
76
  class InvoiceItem {
77
77
  constructor() {
78
- this.invoice = input.required(...(ngDevMode ? [{ debugName: "invoice" }] : []));
78
+ this.invoice = input.required(...(ngDevMode ? [{ debugName: "invoice" }] : /* istanbul ignore next */ []));
79
79
  this.status = InvoiceStatus;
80
80
  this.download = output();
81
81
  }
@@ -101,31 +101,31 @@ class InvoiceItem {
101
101
  return 'invoice-item__status invoice-item__status--neutral';
102
102
  }
103
103
  }
104
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceItem, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
105
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceItem, isStandalone: true, selector: "rolatech-invoice-item", inputs: { invoice: { classPropertyName: "invoice", publicName: "invoice", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { download: "download" }, ngImport: i0, template: "<article class=\"invoice-item\">\n <div class=\"invoice-item__top\">\n <div class=\"invoice-item__identity\">\n <span class=\"invoice-item__eyebrow\">Invoice</span>\n <h3 class=\"invoice-item__number\">{{ invoice().invoiceNumber || invoice().id }}</h3>\n <p class=\"invoice-item__customer\">{{ customerName() }}</p>\n </div>\n\n <div class=\"invoice-item__summary\">\n <span [ngClass]=\"statusBadgeClass(invoice().status)\">{{ status[invoice().status] }}</span>\n <strong class=\"invoice-item__total\">{{ invoice().total | price }}</strong>\n </div>\n </div>\n\n <div class=\"invoice-item__meta\">\n <div class=\"invoice-item__meta-card\">\n <span class=\"invoice-item__meta-label\">Created</span>\n <strong>{{ invoice().createdAt | date: 'dd/MM/yyyy':'Europe/London' }}</strong>\n </div>\n\n <div class=\"invoice-item__meta-card\">\n <span class=\"invoice-item__meta-label\">Due</span>\n <strong>\n @if (invoice().dueAt) {\n {{ invoice().dueAt | date: 'dd/MM/yyyy':'Europe/London' }}\n } @else {\n On receipt\n }\n </strong>\n </div>\n\n <div class=\"invoice-item__meta-card\">\n <span class=\"invoice-item__meta-label\">Type</span>\n <strong>{{ invoice().type }}</strong>\n </div>\n\n <button mat-stroked-button class=\"invoice-item__download\" (click)=\"onDownload(); $event.stopPropagation()\">\n <mat-icon>download</mat-icon>\n <span>Download</span>\n </button>\n </div>\n</article>\n", styles: [".scrollbar-hide::-webkit-scrollbar{display:none}.scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}:host{display:block;--rt-workspace-status-issued-surface: color-mix(in srgb, var(--rt-brand-color) 14%, transparent);--rt-workspace-status-issued-color: color-mix(in srgb, var(--rt-brand-color) 82%, var(--rt-text-primary) 18%);--rt-workspace-status-paid-surface: color-mix(in srgb, var(--rt-brand-color) 16%, var(--rt-base-background, #ffffff));--rt-workspace-status-paid-color: color-mix(in srgb, var(--rt-brand-color) 58%, var(--rt-text-primary) 42%)}.invoice-item{display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.35rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 18px 40px -36px color-mix(in srgb,var(--rt-text-primary) 18%,transparent)}.invoice-item__top{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}.invoice-item__identity{display:flex;flex-direction:column;gap:.32rem}.invoice-item__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.28rem .62rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase}.invoice-item__number{margin:0;color:var(--rt-text-primary);font-size:1.08rem;font-weight:700}.invoice-item__customer{margin:0;color:var(--rt-text-secondary);line-height:1.5}.invoice-item__summary{display:flex;flex-direction:column;gap:.5rem;align-items:flex-end}.invoice-item__total{color:var(--rt-text-primary);font-size:1.08rem}.invoice-item__status{display:inline-flex;align-items:center;border-radius:9999px;padding:.42rem .78rem;font-size:.78rem;font-weight:700}.invoice-item__status--draft{background:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-brand-color)}.invoice-item__status--issued{background:var(--rt-workspace-status-issued-surface);color:var(--rt-workspace-status-issued-color)}.invoice-item__status--paid{background:var(--rt-workspace-status-paid-surface);color:var(--rt-workspace-status-paid-color)}.invoice-item__status--void{background:color-mix(in srgb,var(--mat-sys-error, #b91c1c) 14%,transparent);color:var(--mat-sys-error, #b91c1c)}.invoice-item__status--neutral{background:color-mix(in srgb,var(--rt-10-percent-layer, rgba(15, 23, 42, .08)) 72%,transparent);color:var(--rt-text-secondary)}.invoice-item__meta{display:grid;gap:.85rem}.invoice-item__meta-card{display:flex;flex-direction:column;gap:.22rem;padding:.85rem .95rem;border-radius:1rem;background:color-mix(in srgb,var(--rt-10-percent-layer, rgba(15, 23, 42, .08)) 72%,transparent)}.invoice-item__meta-label{color:var(--rt-text-secondary);font-size:.82rem}.invoice-item__meta-card strong{color:var(--rt-text-primary);font-size:.96rem}.invoice-item__download{min-height:100%;border-radius:1rem}@media(min-width:900px){.invoice-item__meta{grid-template-columns:repeat(4,minmax(0,1fr));align-items:stretch}.invoice-item__download{justify-content:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
104
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceItem, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
105
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceItem, isStandalone: true, selector: "rolatech-invoice-item", inputs: { invoice: { classPropertyName: "invoice", publicName: "invoice", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { download: "download" }, ngImport: i0, template: "<article class=\"invoice-item\">\n <div class=\"invoice-item__top\">\n <div class=\"invoice-item__identity\">\n <span class=\"invoice-item__eyebrow\">Invoice</span>\n <h3 class=\"invoice-item__number\">{{ invoice().invoiceNumber || invoice().id }}</h3>\n <p class=\"invoice-item__customer\">{{ customerName() }}</p>\n </div>\n\n <div class=\"invoice-item__summary\">\n <span [ngClass]=\"statusBadgeClass(invoice().status)\">{{ status[invoice().status] }}</span>\n <strong class=\"invoice-item__total\">{{ invoice().total | price }}</strong>\n </div>\n </div>\n\n <div class=\"invoice-item__meta\">\n <div class=\"invoice-item__meta-card\">\n <span class=\"invoice-item__meta-label\">Created</span>\n <strong>{{ invoice().createdAt | date: 'dd/MM/yyyy':'Europe/London' }}</strong>\n </div>\n\n <div class=\"invoice-item__meta-card\">\n <span class=\"invoice-item__meta-label\">Due</span>\n <strong>\n @if (invoice().dueAt) {\n {{ invoice().dueAt | date: 'dd/MM/yyyy':'Europe/London' }}\n } @else {\n On receipt\n }\n </strong>\n </div>\n\n <div class=\"invoice-item__meta-card\">\n <span class=\"invoice-item__meta-label\">Type</span>\n <strong>{{ invoice().type }}</strong>\n </div>\n\n <button mat-stroked-button class=\"invoice-item__download\" (click)=\"onDownload(); $event.stopPropagation()\">\n <mat-icon>download</mat-icon>\n <span>Download</span>\n </button>\n </div>\n</article>\n", styles: [".scrollbar-hide::-webkit-scrollbar{display:none}.scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}:host{display:block;--rt-workspace-status-issued-surface: color-mix(in srgb, var(--rt-brand-color) 14%, transparent);--rt-workspace-status-issued-color: color-mix(in srgb, var(--rt-brand-color) 82%, var(--rt-text-primary) 18%);--rt-workspace-status-paid-surface: color-mix(in srgb, var(--rt-brand-color) 16%, var(--rt-base-background, #ffffff));--rt-workspace-status-paid-color: color-mix(in srgb, var(--rt-brand-color) 58%, var(--rt-text-primary) 42%)}.invoice-item{display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.35rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 18px 40px -36px color-mix(in srgb,var(--rt-text-primary) 18%,transparent)}.invoice-item__top{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}.invoice-item__identity{display:flex;flex-direction:column;gap:.32rem}.invoice-item__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.28rem .62rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase}.invoice-item__number{margin:0;color:var(--rt-text-primary);font-size:1.08rem;font-weight:700}.invoice-item__customer{margin:0;color:var(--rt-text-secondary);line-height:1.5}.invoice-item__summary{display:flex;flex-direction:column;gap:.5rem;align-items:flex-end}.invoice-item__total{color:var(--rt-text-primary);font-size:1.08rem}.invoice-item__status{display:inline-flex;align-items:center;border-radius:9999px;padding:.42rem .78rem;font-size:.78rem;font-weight:700}.invoice-item__status--draft{background:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-brand-color)}.invoice-item__status--issued{background:var(--rt-workspace-status-issued-surface);color:var(--rt-workspace-status-issued-color)}.invoice-item__status--paid{background:var(--rt-workspace-status-paid-surface);color:var(--rt-workspace-status-paid-color)}.invoice-item__status--void{background:color-mix(in srgb,var(--mat-sys-error, #b91c1c) 14%,transparent);color:var(--mat-sys-error, #b91c1c)}.invoice-item__status--neutral{background:color-mix(in srgb,var(--rt-10-percent-layer, rgba(15, 23, 42, .08)) 72%,transparent);color:var(--rt-text-secondary)}.invoice-item__meta{display:grid;gap:.85rem}.invoice-item__meta-card{display:flex;flex-direction:column;gap:.22rem;padding:.85rem .95rem;border-radius:1rem;background:color-mix(in srgb,var(--rt-10-percent-layer, rgba(15, 23, 42, .08)) 72%,transparent)}.invoice-item__meta-label{color:var(--rt-text-secondary);font-size:.82rem}.invoice-item__meta-card strong{color:var(--rt-text-primary);font-size:.96rem}.invoice-item__download{min-height:100%;border-radius:1rem}@media(min-width:900px){.invoice-item__meta{grid-template-columns:repeat(4,minmax(0,1fr));align-items:stretch}.invoice-item__download{justify-content:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
106
106
  }
107
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceItem, decorators: [{
107
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceItem, decorators: [{
108
108
  type: Component,
109
109
  args: [{ selector: 'rolatech-invoice-item', imports: [CommonModule, MatButtonModule, MatIcon, DatePipe, PricePipe], template: "<article class=\"invoice-item\">\n <div class=\"invoice-item__top\">\n <div class=\"invoice-item__identity\">\n <span class=\"invoice-item__eyebrow\">Invoice</span>\n <h3 class=\"invoice-item__number\">{{ invoice().invoiceNumber || invoice().id }}</h3>\n <p class=\"invoice-item__customer\">{{ customerName() }}</p>\n </div>\n\n <div class=\"invoice-item__summary\">\n <span [ngClass]=\"statusBadgeClass(invoice().status)\">{{ status[invoice().status] }}</span>\n <strong class=\"invoice-item__total\">{{ invoice().total | price }}</strong>\n </div>\n </div>\n\n <div class=\"invoice-item__meta\">\n <div class=\"invoice-item__meta-card\">\n <span class=\"invoice-item__meta-label\">Created</span>\n <strong>{{ invoice().createdAt | date: 'dd/MM/yyyy':'Europe/London' }}</strong>\n </div>\n\n <div class=\"invoice-item__meta-card\">\n <span class=\"invoice-item__meta-label\">Due</span>\n <strong>\n @if (invoice().dueAt) {\n {{ invoice().dueAt | date: 'dd/MM/yyyy':'Europe/London' }}\n } @else {\n On receipt\n }\n </strong>\n </div>\n\n <div class=\"invoice-item__meta-card\">\n <span class=\"invoice-item__meta-label\">Type</span>\n <strong>{{ invoice().type }}</strong>\n </div>\n\n <button mat-stroked-button class=\"invoice-item__download\" (click)=\"onDownload(); $event.stopPropagation()\">\n <mat-icon>download</mat-icon>\n <span>Download</span>\n </button>\n </div>\n</article>\n", styles: [".scrollbar-hide::-webkit-scrollbar{display:none}.scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}:host{display:block;--rt-workspace-status-issued-surface: color-mix(in srgb, var(--rt-brand-color) 14%, transparent);--rt-workspace-status-issued-color: color-mix(in srgb, var(--rt-brand-color) 82%, var(--rt-text-primary) 18%);--rt-workspace-status-paid-surface: color-mix(in srgb, var(--rt-brand-color) 16%, var(--rt-base-background, #ffffff));--rt-workspace-status-paid-color: color-mix(in srgb, var(--rt-brand-color) 58%, var(--rt-text-primary) 42%)}.invoice-item{display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.35rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 18px 40px -36px color-mix(in srgb,var(--rt-text-primary) 18%,transparent)}.invoice-item__top{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}.invoice-item__identity{display:flex;flex-direction:column;gap:.32rem}.invoice-item__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.28rem .62rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase}.invoice-item__number{margin:0;color:var(--rt-text-primary);font-size:1.08rem;font-weight:700}.invoice-item__customer{margin:0;color:var(--rt-text-secondary);line-height:1.5}.invoice-item__summary{display:flex;flex-direction:column;gap:.5rem;align-items:flex-end}.invoice-item__total{color:var(--rt-text-primary);font-size:1.08rem}.invoice-item__status{display:inline-flex;align-items:center;border-radius:9999px;padding:.42rem .78rem;font-size:.78rem;font-weight:700}.invoice-item__status--draft{background:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-brand-color)}.invoice-item__status--issued{background:var(--rt-workspace-status-issued-surface);color:var(--rt-workspace-status-issued-color)}.invoice-item__status--paid{background:var(--rt-workspace-status-paid-surface);color:var(--rt-workspace-status-paid-color)}.invoice-item__status--void{background:color-mix(in srgb,var(--mat-sys-error, #b91c1c) 14%,transparent);color:var(--mat-sys-error, #b91c1c)}.invoice-item__status--neutral{background:color-mix(in srgb,var(--rt-10-percent-layer, rgba(15, 23, 42, .08)) 72%,transparent);color:var(--rt-text-secondary)}.invoice-item__meta{display:grid;gap:.85rem}.invoice-item__meta-card{display:flex;flex-direction:column;gap:.22rem;padding:.85rem .95rem;border-radius:1rem;background:color-mix(in srgb,var(--rt-10-percent-layer, rgba(15, 23, 42, .08)) 72%,transparent)}.invoice-item__meta-label{color:var(--rt-text-secondary);font-size:.82rem}.invoice-item__meta-card strong{color:var(--rt-text-primary);font-size:.96rem}.invoice-item__download{min-height:100%;border-radius:1rem}@media(min-width:900px){.invoice-item__meta{grid-template-columns:repeat(4,minmax(0,1fr));align-items:stretch}.invoice-item__download{justify-content:center}}\n"] }]
110
110
  }], propDecorators: { invoice: [{ type: i0.Input, args: [{ isSignal: true, alias: "invoice", required: true }] }], download: [{ type: i0.Output, args: ["download"] }] } });
111
111
 
112
112
  class InvoiceManageItem {
113
113
  constructor() {
114
- this.invoice = input.required(...(ngDevMode ? [{ debugName: "invoice" }] : []));
114
+ this.invoice = input.required(...(ngDevMode ? [{ debugName: "invoice" }] : /* istanbul ignore next */ []));
115
115
  }
116
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageItem, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
117
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: InvoiceManageItem, isStandalone: true, selector: "rolatech-invoice-manage-item", inputs: { invoice: { classPropertyName: "invoice", publicName: "invoice", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<p>invoice-manage-item works!</p>\n<div>{{invoice().id}}</div>\n", styles: [""] }); }
116
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageItem, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
117
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.5", type: InvoiceManageItem, isStandalone: true, selector: "rolatech-invoice-manage-item", inputs: { invoice: { classPropertyName: "invoice", publicName: "invoice", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<p>invoice-manage-item works!</p>\n<div>{{invoice().id}}</div>\n", styles: [""] }); }
118
118
  }
119
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageItem, decorators: [{
119
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageItem, decorators: [{
120
120
  type: Component,
121
121
  args: [{ selector: 'rolatech-invoice-manage-item', imports: [], template: "<p>invoice-manage-item works!</p>\n<div>{{invoice().id}}</div>\n" }]
122
122
  }], propDecorators: { invoice: [{ type: i0.Input, args: [{ isSignal: true, alias: "invoice", required: true }] }] } });
123
123
 
124
124
  class InvoiceItemSkeleton {
125
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceItemSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
126
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.1", type: InvoiceItemSkeleton, isStandalone: true, selector: "rolatech-invoice-item-skeleton", ngImport: i0, template: "<div class=\"grid grid-cols-6 place-content-center h-16 p-3 gap-3\">\n <rolatech-skeleton class=\"col-span-1 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"col-start-3 col-span-2 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"col-start-6 col-span-1 h-4\"></rolatech-skeleton>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: Skeleton, selector: "rolatech-skeleton" }], encapsulation: i0.ViewEncapsulation.None }); }
125
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceItemSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
126
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: InvoiceItemSkeleton, isStandalone: true, selector: "rolatech-invoice-item-skeleton", ngImport: i0, template: "<div class=\"grid grid-cols-6 place-content-center h-16 p-3 gap-3\">\n <rolatech-skeleton class=\"col-span-1 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"col-start-3 col-span-2 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"col-start-6 col-span-1 h-4\"></rolatech-skeleton>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: Skeleton, selector: "rolatech-skeleton" }], encapsulation: i0.ViewEncapsulation.None }); }
127
127
  }
128
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceItemSkeleton, decorators: [{
128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceItemSkeleton, decorators: [{
129
129
  type: Component,
130
130
  args: [{ selector: 'rolatech-invoice-item-skeleton', imports: [Skeleton], encapsulation: ViewEncapsulation.None, template: "<div class=\"grid grid-cols-6 place-content-center h-16 p-3 gap-3\">\n <rolatech-skeleton class=\"col-span-1 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"col-start-3 col-span-2 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"col-start-6 col-span-1 h-4\"></rolatech-skeleton>\n</div>\n" }]
131
131
  }] });
@@ -162,13 +162,13 @@ class InvoiceIndexComponent extends BaseComponent {
162
162
  status: 'paid',
163
163
  },
164
164
  ];
165
- this.invoices = signal([], ...(ngDevMode ? [{ debugName: "invoices" }] : []));
165
+ this.invoices = signal([], ...(ngDevMode ? [{ debugName: "invoices" }] : /* istanbul ignore next */ []));
166
166
  this.select = 0;
167
167
  this.filter = false;
168
168
  this.length = 100;
169
169
  this.pageSize = 15;
170
170
  this.pageSizeOptions = [5, 10, 25, 100];
171
- this.pageIndex = signal(0, ...(ngDevMode ? [{ debugName: "pageIndex" }] : []));
171
+ this.pageIndex = signal(0, ...(ngDevMode ? [{ debugName: "pageIndex" }] : /* istanbul ignore next */ []));
172
172
  this.pageMeta = {
173
173
  baseLink: this.readRouteData('invoiceBaseLink', '/invoices'),
174
174
  eyebrow: this.readRouteData('invoiceEyebrow', 'Billing workspace'),
@@ -183,7 +183,7 @@ class InvoiceIndexComponent extends BaseComponent {
183
183
  { label: 'Issued', value: invoices.filter((item) => item.status === InvoiceStatus.ISSUED || item.status === InvoiceStatus.SENT).length, hint: 'Sent and awaiting payment' },
184
184
  { label: 'Paid', value: invoices.filter((item) => item.status === InvoiceStatus.PAID).length, hint: 'Successfully settled' },
185
185
  ];
186
- }, ...(ngDevMode ? [{ debugName: "stats" }] : []));
186
+ }, ...(ngDevMode ? [{ debugName: "stats" }] : /* istanbul ignore next */ []));
187
187
  }
188
188
  ngOnInit() {
189
189
  const sub = this.route.queryParamMap
@@ -279,10 +279,10 @@ class InvoiceIndexComponent extends BaseComponent {
279
279
  }
280
280
  return fallback;
281
281
  }
282
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceIndexComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
283
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceIndexComponent, isStandalone: true, selector: "rolatech-invoice-index", usesInheritance: true, ngImport: i0, template: "<rolatech-page-collection-shell [eyebrow]=\"pageMeta.eyebrow\" [title]=\"pageMeta.title\" [subtitle]=\"pageMeta.description\">\n <div page-shell-header-meta class=\"invoice-index-page__stats\">\n @for (stat of stats(); track stat.label) {\n <article class=\"invoice-index-page__stat\">\n <span class=\"invoice-index-page__stat-value\">{{ stat.value }}</span>\n <span class=\"invoice-index-page__stat-label\">{{ stat.label }}</span>\n <span class=\"invoice-index-page__stat-hint\">{{ stat.hint }}</span>\n </article>\n }\n </div>\n\n <section class=\"invoice-index-page__filters\">\n <nav class=\"invoice-index-page__status-nav\" aria-label=\"Invoice status filters\">\n @for (item of links; track item.name; let index = $index) {\n <a\n class=\"invoice-index-page__status-link\"\n [class.invoice-index-page__status-link--active]=\"select === index\"\n routerLink=\"./\"\n [queryParams]=\"item.status ? { status: item.status } : {}\"\n >\n {{ item.name }}\n </a>\n }\n </nav>\n\n <div class=\"invoice-index-page__filter-grid\">\n <mat-form-field appearance=\"fill\">\n <mat-label>Type</mat-label>\n <mat-select name=\"type\" [(ngModel)]=\"filterOptions.type\">\n @for (type of invoiceType | keyvalue; track type.key) {\n <mat-option [value]=\"type.key\">{{ type.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Status</mat-label>\n <mat-select [compareWith]=\"statusCompareFn\" [(ngModel)]=\"filterOptions.status\">\n @for (status of invoiceStatus | keyvalue; track status.key) {\n <mat-option [value]=\"status.key\">{{ status.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <div class=\"invoice-index-page__filter-actions\">\n <button mat-flat-button (click)=\"find()\">Apply filters</button>\n <button mat-stroked-button (click)=\"resetFilter()\">Reset</button>\n </div>\n </div>\n </section>\n\n <section class=\"invoice-index-page__list\">\n @if (loading) {\n @for (dummy of [0, 1, 2, 3]; track dummy) {\n <rolatech-invoice-item-skeleton></rolatech-invoice-item-skeleton>\n }\n } @else if (invoices().length > 0) {\n @for (item of invoices(); track item.id) {\n <rolatech-invoice-item class=\"cursor-pointer\" [routerLink]=\"['./', item.id]\" [invoice]=\"item\"></rolatech-invoice-item>\n }\n } @else {\n <div class=\"invoice-index-page__empty\">\n <h3>No invoices yet</h3>\n <p>The invoices for this workspace will appear here once billing is created.</p>\n </div>\n }\n\n <mat-paginator\n #paginator\n [length]=\"length\"\n [pageSize]=\"pageSize\"\n [pageIndex]=\"pageIndex()\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onPage($event)\"\n hidePageSize\n showFirstLastButtons\n >\n </mat-paginator>\n </section>\n</rolatech-page-collection-shell>\n", styles: [".collapsed{max-height:0;overflow:hidden;transition:max-height .5s cubic-bezier(.4,0,.2,1)}.expanded{max-height:1000px}:host{display:block}.invoice-index-page__filters,.invoice-index-page__list{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-index-page__stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.85rem}.invoice-index-page__stat{display:flex;flex-direction:column;gap:.2rem;padding:.95rem 1rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.1rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 88%,var(--rt-brand-color) 12%)}.invoice-index-page__stat-value{color:var(--rt-text-primary);font-size:1.2rem;font-weight:700}.invoice-index-page__stat-label,.invoice-index-page__stat-hint{color:var(--rt-text-secondary);font-size:.84rem}.invoice-index-page__filters,.invoice-index-page__list{padding:1rem 1.1rem}.invoice-index-page__filters,.invoice-index-page__list{display:flex;flex-direction:column;gap:1rem}.invoice-index-page__status-nav{display:flex;flex-wrap:wrap;gap:.65rem}.invoice-index-page__status-link{display:inline-flex;align-items:center;justify-content:center;min-height:2.75rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:9999px;padding:.55rem .95rem;color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-index-page__status-link:hover,.invoice-index-page__status-link--active{border-color:color-mix(in srgb,var(--rt-brand-color) 24%,var(--rt-border-color, rgba(15, 23, 42, .08)));background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color)}.invoice-index-page__filter-grid{display:grid;gap:.85rem}.invoice-index-page__filter-grid mat-form-field{width:100%}.invoice-index-page__filter-actions{display:flex;flex-wrap:wrap;gap:.75rem}.invoice-index-page__empty{display:flex;flex-direction:column;justify-content:center;min-height:10rem;gap:.45rem;padding:1.25rem;border:1px dashed var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.35rem;background:var(--rt-base-background, #ffffff)}.invoice-index-page__empty h3{margin:0;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-index-page__empty p{margin:0;color:var(--rt-text-secondary);line-height:1.65}@media(min-width:900px){.invoice-index-page__filter-grid{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}.invoice-index-page__stats{grid-template-columns:repeat(4,minmax(0,1fr))}}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: InvoiceItem, selector: "rolatech-invoice-item", inputs: ["invoice"], outputs: ["download"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i6.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: InvoiceItemSkeleton, selector: "rolatech-invoice-item-skeleton" }, { kind: "component", type: PageCollectionShellComponent, selector: "rolatech-page-collection-shell", inputs: ["eyebrow", "title", "subtitle"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], encapsulation: i0.ViewEncapsulation.None }); }
282
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceIndexComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
283
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceIndexComponent, isStandalone: true, selector: "rolatech-invoice-index", usesInheritance: true, ngImport: i0, template: "<rolatech-page-collection-shell [eyebrow]=\"pageMeta.eyebrow\" [title]=\"pageMeta.title\" [subtitle]=\"pageMeta.description\">\n <div page-shell-header-meta class=\"invoice-index-page__stats\">\n @for (stat of stats(); track stat.label) {\n <article class=\"invoice-index-page__stat\">\n <span class=\"invoice-index-page__stat-value\">{{ stat.value }}</span>\n <span class=\"invoice-index-page__stat-label\">{{ stat.label }}</span>\n <span class=\"invoice-index-page__stat-hint\">{{ stat.hint }}</span>\n </article>\n }\n </div>\n\n <section class=\"invoice-index-page__filters\">\n <nav class=\"invoice-index-page__status-nav\" aria-label=\"Invoice status filters\">\n @for (item of links; track item.name; let index = $index) {\n <a\n class=\"invoice-index-page__status-link\"\n [class.invoice-index-page__status-link--active]=\"select === index\"\n routerLink=\"./\"\n [queryParams]=\"item.status ? { status: item.status } : {}\"\n >\n {{ item.name }}\n </a>\n }\n </nav>\n\n <div class=\"invoice-index-page__filter-grid\">\n <mat-form-field appearance=\"fill\">\n <mat-label>Type</mat-label>\n <mat-select name=\"type\" [(ngModel)]=\"filterOptions.type\">\n @for (type of invoiceType | keyvalue; track type.key) {\n <mat-option [value]=\"type.key\">{{ type.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Status</mat-label>\n <mat-select [compareWith]=\"statusCompareFn\" [(ngModel)]=\"filterOptions.status\">\n @for (status of invoiceStatus | keyvalue; track status.key) {\n <mat-option [value]=\"status.key\">{{ status.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <div class=\"invoice-index-page__filter-actions\">\n <button mat-flat-button (click)=\"find()\">Apply filters</button>\n <button mat-stroked-button (click)=\"resetFilter()\">Reset</button>\n </div>\n </div>\n </section>\n\n <section class=\"invoice-index-page__list\">\n @if (loading) {\n @for (dummy of [0, 1, 2, 3]; track dummy) {\n <rolatech-invoice-item-skeleton></rolatech-invoice-item-skeleton>\n }\n } @else if (invoices().length > 0) {\n @for (item of invoices(); track item.id) {\n <rolatech-invoice-item class=\"cursor-pointer\" [routerLink]=\"['./', item.id]\" [invoice]=\"item\"></rolatech-invoice-item>\n }\n } @else {\n <div class=\"invoice-index-page__empty\">\n <h3>No invoices yet</h3>\n <p>The invoices for this workspace will appear here once billing is created.</p>\n </div>\n }\n\n <mat-paginator\n #paginator\n [length]=\"length\"\n [pageSize]=\"pageSize\"\n [pageIndex]=\"pageIndex()\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onPage($event)\"\n hidePageSize\n showFirstLastButtons\n >\n </mat-paginator>\n </section>\n</rolatech-page-collection-shell>\n", styles: [".collapsed{max-height:0;overflow:hidden;transition:max-height .5s cubic-bezier(.4,0,.2,1)}.expanded{max-height:1000px}:host{display:block}.invoice-index-page__filters,.invoice-index-page__list{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-index-page__stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.85rem}.invoice-index-page__stat{display:flex;flex-direction:column;gap:.2rem;padding:.95rem 1rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.1rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 88%,var(--rt-brand-color) 12%)}.invoice-index-page__stat-value{color:var(--rt-text-primary);font-size:1.2rem;font-weight:700}.invoice-index-page__stat-label,.invoice-index-page__stat-hint{color:var(--rt-text-secondary);font-size:.84rem}.invoice-index-page__filters,.invoice-index-page__list{padding:1rem 1.1rem}.invoice-index-page__filters,.invoice-index-page__list{display:flex;flex-direction:column;gap:1rem}.invoice-index-page__status-nav{display:flex;flex-wrap:wrap;gap:.65rem}.invoice-index-page__status-link{display:inline-flex;align-items:center;justify-content:center;min-height:2.75rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:9999px;padding:.55rem .95rem;color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-index-page__status-link:hover,.invoice-index-page__status-link--active{border-color:color-mix(in srgb,var(--rt-brand-color) 24%,var(--rt-border-color, rgba(15, 23, 42, .08)));background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color)}.invoice-index-page__filter-grid{display:grid;gap:.85rem}.invoice-index-page__filter-grid mat-form-field{width:100%}.invoice-index-page__filter-actions{display:flex;flex-wrap:wrap;gap:.75rem}.invoice-index-page__empty{display:flex;flex-direction:column;justify-content:center;min-height:10rem;gap:.45rem;padding:1.25rem;border:1px dashed var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.35rem;background:var(--rt-base-background, #ffffff)}.invoice-index-page__empty h3{margin:0;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-index-page__empty p{margin:0;color:var(--rt-text-secondary);line-height:1.65}@media(min-width:900px){.invoice-index-page__filter-grid{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}.invoice-index-page__stats{grid-template-columns:repeat(4,minmax(0,1fr))}}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: InvoiceItem, selector: "rolatech-invoice-item", inputs: ["invoice"], outputs: ["download"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i6.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: InvoiceItemSkeleton, selector: "rolatech-invoice-item-skeleton" }, { kind: "component", type: PageCollectionShellComponent, selector: "rolatech-page-collection-shell", inputs: ["eyebrow", "title", "subtitle"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], encapsulation: i0.ViewEncapsulation.None }); }
284
284
  }
285
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceIndexComponent, decorators: [{
285
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceIndexComponent, decorators: [{
286
286
  type: Component,
287
287
  args: [{ selector: 'rolatech-invoice-index', imports: [
288
288
  RouterModule,
@@ -301,15 +301,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
301
301
 
302
302
  class InvoiceUser {
303
303
  constructor() {
304
- this.firstName = input.required(...(ngDevMode ? [{ debugName: "firstName" }] : []));
305
- this.lastName = input.required(...(ngDevMode ? [{ debugName: "lastName" }] : []));
306
- this.email = input.required(...(ngDevMode ? [{ debugName: "email" }] : []));
307
- this.phone = input.required(...(ngDevMode ? [{ debugName: "phone" }] : []));
304
+ this.firstName = input.required(...(ngDevMode ? [{ debugName: "firstName" }] : /* istanbul ignore next */ []));
305
+ this.lastName = input.required(...(ngDevMode ? [{ debugName: "lastName" }] : /* istanbul ignore next */ []));
306
+ this.email = input.required(...(ngDevMode ? [{ debugName: "email" }] : /* istanbul ignore next */ []));
307
+ this.phone = input.required(...(ngDevMode ? [{ debugName: "phone" }] : /* istanbul ignore next */ []));
308
308
  }
309
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceUser, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
310
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: InvoiceUser, isStandalone: true, selector: "rolatech-invoice-user", inputs: { firstName: { classPropertyName: "firstName", publicName: "firstName", isSignal: true, isRequired: true, transformFunction: null }, lastName: { classPropertyName: "lastName", publicName: "lastName", isSignal: true, isRequired: true, transformFunction: null }, email: { classPropertyName: "email", publicName: "email", isSignal: true, isRequired: true, transformFunction: null }, phone: { classPropertyName: "phone", publicName: "phone", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "id": "rolatech-invoice-user" }, classAttribute: "rolatech-invoice-user" }, ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <h2 class=\"text-sm font-semibold\">User</h2>\n <div class=\"text-sm\">\n <div class=\"font-medium\">{{ firstName() }}, {{ lastName() }}</div>\n <div class=\"font-medium\">{{ phone() }}</div>\n <div>{{ email() }}</div>\n </div>\n</div>\n", styles: [""], encapsulation: i0.ViewEncapsulation.None }); }
309
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceUser, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
310
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.5", type: InvoiceUser, isStandalone: true, selector: "rolatech-invoice-user", inputs: { firstName: { classPropertyName: "firstName", publicName: "firstName", isSignal: true, isRequired: true, transformFunction: null }, lastName: { classPropertyName: "lastName", publicName: "lastName", isSignal: true, isRequired: true, transformFunction: null }, email: { classPropertyName: "email", publicName: "email", isSignal: true, isRequired: true, transformFunction: null }, phone: { classPropertyName: "phone", publicName: "phone", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "id": "rolatech-invoice-user" }, classAttribute: "rolatech-invoice-user" }, ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <h2 class=\"text-sm font-semibold\">User</h2>\n <div class=\"text-sm\">\n <div class=\"font-medium\">{{ firstName() }}, {{ lastName() }}</div>\n <div class=\"font-medium\">{{ phone() }}</div>\n <div>{{ email() }}</div>\n </div>\n</div>\n", styles: [""], encapsulation: i0.ViewEncapsulation.None }); }
311
311
  }
312
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceUser, decorators: [{
312
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceUser, decorators: [{
313
313
  type: Component,
314
314
  args: [{ selector: 'rolatech-invoice-user', imports: [], encapsulation: ViewEncapsulation.None, host: {
315
315
  id: 'rolatech-invoice-user',
@@ -319,28 +319,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
319
319
 
320
320
  class InvoiceLines {
321
321
  constructor() {
322
- this.lines = input([], ...(ngDevMode ? [{ debugName: "lines" }] : []));
322
+ this.lines = input([], ...(ngDevMode ? [{ debugName: "lines" }] : /* istanbul ignore next */ []));
323
323
  }
324
324
  add() { }
325
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceLines, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
326
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceLines, isStandalone: true, selector: "rolatech-invoice-lines", inputs: { lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <div class=\"flex justify-between\">\n <h2 class=\"text-sm font-semibold\">Invoice lines</h2>\n </div>\n\n <div class=\"overflow-x-auto\">\n <table class=\"min-w-full text-sm border border-(--rt-border-color) rounded-lg\">\n <thead class=\"bg-(--rt-raised-background)\">\n <tr>\n <th class=\"px-3 py-2 text-left font-medium border-b border-(--rt-border-color)\">Title</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">Unit (\u00A3)</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-20\">VAT %</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">VAT (\u00A3)</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-32\">Total (\u00A3)</th>\n </tr>\n </thead>\n\n <tbody class=\"[&>tr:nth-child(even)]:bg-(--rt-raised-background)\">\n @if (lines().length > 0) { @for (line of lines(); track line.id) {\n <tr class=\"hover:bg-(--rt-raised-background) cursor-pointer\">\n <!-- Title -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color)\">\n <div class=\"font-medium\">{{ line.title }}</div>\n </td>\n\n <!-- Unit price -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n {{ line.unitPrice | price }}\n </td>\n\n <!-- VAT rate -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n {{ line.vatRate }}%\n </td>\n\n <!-- VAT amount -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n {{ line.vatAmount | price }}\n </td>\n\n <!-- Total -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right font-semibold text-(--rt-text-secondary)\">\n {{ line.lineTotal | price }}\n </td>\n </tr>\n } } @else {\n <tr>\n <td [attr.colspan]=\"6\" class=\"px-3 py-4 text-center text-(--rt-text-secondary) text-sm\">No invoice lines</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n", styles: [".cdk-drag-preview{box-shadow:0 10px 20px #00000026;border-radius:12px}.cdk-drag-placeholder{opacity:.3}\n"], dependencies: [{ kind: "pipe", type: PricePipe, name: "price" }], encapsulation: i0.ViewEncapsulation.None }); }
325
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceLines, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
326
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceLines, isStandalone: true, selector: "rolatech-invoice-lines", inputs: { lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <div class=\"flex justify-between\">\n <h2 class=\"text-sm font-semibold\">Invoice lines</h2>\n </div>\n\n <div class=\"overflow-x-auto\">\n <table class=\"min-w-full text-sm border border-(--rt-border-color) rounded-lg\">\n <thead class=\"bg-(--rt-raised-background)\">\n <tr>\n <th class=\"px-3 py-2 text-left font-medium border-b border-(--rt-border-color)\">Title</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">Unit (\u00A3)</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-20\">VAT %</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">VAT (\u00A3)</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-32\">Total (\u00A3)</th>\n </tr>\n </thead>\n\n <tbody class=\"[&>tr:nth-child(even)]:bg-(--rt-raised-background)\">\n @if (lines().length > 0) { @for (line of lines(); track line.id) {\n <tr class=\"hover:bg-(--rt-raised-background) cursor-pointer\">\n <!-- Title -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color)\">\n <div class=\"font-medium\">{{ line.title }}</div>\n </td>\n\n <!-- Unit price -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n {{ line.unitPrice | price }}\n </td>\n\n <!-- VAT rate -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n {{ line.vatRate }}%\n </td>\n\n <!-- VAT amount -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n {{ line.vatAmount | price }}\n </td>\n\n <!-- Total -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right font-semibold text-(--rt-text-secondary)\">\n {{ line.lineTotal | price }}\n </td>\n </tr>\n } } @else {\n <tr>\n <td [attr.colspan]=\"6\" class=\"px-3 py-4 text-center text-(--rt-text-secondary) text-sm\">No invoice lines</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n", styles: [".cdk-drag-preview{box-shadow:0 10px 20px #00000026;border-radius:12px}.cdk-drag-placeholder{opacity:.3}\n"], dependencies: [{ kind: "pipe", type: PricePipe, name: "price" }], encapsulation: i0.ViewEncapsulation.None }); }
327
327
  }
328
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceLines, decorators: [{
328
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceLines, decorators: [{
329
329
  type: Component,
330
330
  args: [{ selector: 'rolatech-invoice-lines', imports: [PricePipe], encapsulation: ViewEncapsulation.None, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <div class=\"flex justify-between\">\n <h2 class=\"text-sm font-semibold\">Invoice lines</h2>\n </div>\n\n <div class=\"overflow-x-auto\">\n <table class=\"min-w-full text-sm border border-(--rt-border-color) rounded-lg\">\n <thead class=\"bg-(--rt-raised-background)\">\n <tr>\n <th class=\"px-3 py-2 text-left font-medium border-b border-(--rt-border-color)\">Title</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">Unit (\u00A3)</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-20\">VAT %</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">VAT (\u00A3)</th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-32\">Total (\u00A3)</th>\n </tr>\n </thead>\n\n <tbody class=\"[&>tr:nth-child(even)]:bg-(--rt-raised-background)\">\n @if (lines().length > 0) { @for (line of lines(); track line.id) {\n <tr class=\"hover:bg-(--rt-raised-background) cursor-pointer\">\n <!-- Title -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color)\">\n <div class=\"font-medium\">{{ line.title }}</div>\n </td>\n\n <!-- Unit price -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n {{ line.unitPrice | price }}\n </td>\n\n <!-- VAT rate -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n {{ line.vatRate }}%\n </td>\n\n <!-- VAT amount -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n {{ line.vatAmount | price }}\n </td>\n\n <!-- Total -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right font-semibold text-(--rt-text-secondary)\">\n {{ line.lineTotal | price }}\n </td>\n </tr>\n } } @else {\n <tr>\n <td [attr.colspan]=\"6\" class=\"px-3 py-4 text-center text-(--rt-text-secondary) text-sm\">No invoice lines</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n", styles: [".cdk-drag-preview{box-shadow:0 10px 20px #00000026;border-radius:12px}.cdk-drag-placeholder{opacity:.3}\n"] }]
331
331
  }], propDecorators: { lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }] } });
332
332
 
333
333
  class InvoiceSummary {
334
334
  constructor() {
335
- this.tax = input.required(...(ngDevMode ? [{ debugName: "tax" }] : []));
336
- this.credit = input(0, ...(ngDevMode ? [{ debugName: "credit" }] : []));
337
- this.subtotal = input.required(...(ngDevMode ? [{ debugName: "subtotal" }] : []));
338
- this.total = input.required(...(ngDevMode ? [{ debugName: "total" }] : []));
335
+ this.tax = input.required(...(ngDevMode ? [{ debugName: "tax" }] : /* istanbul ignore next */ []));
336
+ this.credit = input(0, ...(ngDevMode ? [{ debugName: "credit" }] : /* istanbul ignore next */ []));
337
+ this.subtotal = input.required(...(ngDevMode ? [{ debugName: "subtotal" }] : /* istanbul ignore next */ []));
338
+ this.total = input.required(...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
339
339
  }
340
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceSummary, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
341
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceSummary, isStandalone: true, selector: "rolatech-invoice-summary", inputs: { tax: { classPropertyName: "tax", publicName: "tax", isSignal: true, isRequired: true, transformFunction: null }, credit: { classPropertyName: "credit", publicName: "credit", isSignal: true, isRequired: false, transformFunction: null }, subtotal: { classPropertyName: "subtotal", publicName: "subtotal", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "id": "rolatech-invoice-summary" }, classAttribute: "rolatech-invoice-summary" }, ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <h2 class=\"text-sm font-semibold text-(--rt-text-secondary)\">Totals</h2>\n\n <dl class=\"space-y-2 text-sm\">\n <div class=\"flex justify-between\">\n <dt class=\"text-(--rt-text-secondary)\">Subtotal</dt>\n <dd class=\"font-medium\">{{ subtotal() | price }}</dd>\n </div>\n\n <div class=\"flex justify-between\">\n <dt class=\"text-(--rt-text-secondary)\">VAT</dt>\n <dd class=\"font-medium\">{{ tax() | price}}</dd>\n </div>\n\n @if (credit() > 0) {\n <div class=\"flex justify-between\">\n <dt class=\"text-(--rt-text-secondary)\">Less holding deposit</dt>\n <dd class=\"font-medium text-red-600\">\u2212{{ credit() | price }}</dd>\n </div>\n }\n\n <div class=\"border-t border-dashed border-(--rt-border-color) my-2\"></div>\n\n <div class=\"flex justify-between items-center\">\n <dt class=\"text-(--rt-text-secondary) font-semibold\">Total</dt>\n <dd class=\"text-lg font-semibold\">{{ total() | price }}</dd>\n </div>\n </dl>\n</div>\n", styles: [""], dependencies: [{ kind: "pipe", type: PricePipe, name: "price" }], encapsulation: i0.ViewEncapsulation.None }); }
340
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceSummary, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
341
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceSummary, isStandalone: true, selector: "rolatech-invoice-summary", inputs: { tax: { classPropertyName: "tax", publicName: "tax", isSignal: true, isRequired: true, transformFunction: null }, credit: { classPropertyName: "credit", publicName: "credit", isSignal: true, isRequired: false, transformFunction: null }, subtotal: { classPropertyName: "subtotal", publicName: "subtotal", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "id": "rolatech-invoice-summary" }, classAttribute: "rolatech-invoice-summary" }, ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <h2 class=\"text-sm font-semibold text-(--rt-text-secondary)\">Totals</h2>\n\n <dl class=\"space-y-2 text-sm\">\n <div class=\"flex justify-between\">\n <dt class=\"text-(--rt-text-secondary)\">Subtotal</dt>\n <dd class=\"font-medium\">{{ subtotal() | price }}</dd>\n </div>\n\n <div class=\"flex justify-between\">\n <dt class=\"text-(--rt-text-secondary)\">VAT</dt>\n <dd class=\"font-medium\">{{ tax() | price}}</dd>\n </div>\n\n @if (credit() > 0) {\n <div class=\"flex justify-between\">\n <dt class=\"text-(--rt-text-secondary)\">Less holding deposit</dt>\n <dd class=\"font-medium text-red-600\">\u2212{{ credit() | price }}</dd>\n </div>\n }\n\n <div class=\"border-t border-dashed border-(--rt-border-color) my-2\"></div>\n\n <div class=\"flex justify-between items-center\">\n <dt class=\"text-(--rt-text-secondary) font-semibold\">Total</dt>\n <dd class=\"text-lg font-semibold\">{{ total() | price }}</dd>\n </div>\n </dl>\n</div>\n", styles: [""], dependencies: [{ kind: "pipe", type: PricePipe, name: "price" }], encapsulation: i0.ViewEncapsulation.None }); }
342
342
  }
343
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceSummary, decorators: [{
343
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceSummary, decorators: [{
344
344
  type: Component,
345
345
  args: [{ selector: 'rolatech-invoice-summary', imports: [PricePipe], encapsulation: ViewEncapsulation.None, host: {
346
346
  id: 'rolatech-invoice-summary',
@@ -349,28 +349,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
349
349
  }], propDecorators: { tax: [{ type: i0.Input, args: [{ isSignal: true, alias: "tax", required: true }] }], credit: [{ type: i0.Input, args: [{ isSignal: true, alias: "credit", required: false }] }], subtotal: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtotal", required: true }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: true }] }] } });
350
350
 
351
351
  class InvoiceUserSkeleton {
352
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceUserSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
353
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.1", type: InvoiceUserSkeleton, isStandalone: true, selector: "rolatech-invoice-user-skeleton", ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <rolatech-skeleton class=\"w-12 h-6\"></rolatech-skeleton>\n <div class=\"flex flex-col gap-2\">\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-32 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-36 h-4\"></rolatech-skeleton>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: Skeleton, selector: "rolatech-skeleton" }], encapsulation: i0.ViewEncapsulation.None }); }
352
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceUserSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
353
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: InvoiceUserSkeleton, isStandalone: true, selector: "rolatech-invoice-user-skeleton", ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <rolatech-skeleton class=\"w-12 h-6\"></rolatech-skeleton>\n <div class=\"flex flex-col gap-2\">\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-32 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-36 h-4\"></rolatech-skeleton>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: Skeleton, selector: "rolatech-skeleton" }], encapsulation: i0.ViewEncapsulation.None }); }
354
354
  }
355
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceUserSkeleton, decorators: [{
355
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceUserSkeleton, decorators: [{
356
356
  type: Component,
357
357
  args: [{ selector: 'rolatech-invoice-user-skeleton', imports: [Skeleton], encapsulation: ViewEncapsulation.None, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <rolatech-skeleton class=\"w-12 h-6\"></rolatech-skeleton>\n <div class=\"flex flex-col gap-2\">\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-32 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-36 h-4\"></rolatech-skeleton>\n </div>\n</div>\n" }]
358
358
  }] });
359
359
 
360
360
  class InvoiceSummarySkeleton {
361
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceSummarySkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
362
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.1", type: InvoiceSummarySkeleton, isStandalone: true, selector: "rolatech-invoice-summary-skeleton", ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <rolatech-skeleton class=\"w-12 h-6\"></rolatech-skeleton>\n\n <dl class=\"space-y-2 text-sm\">\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n </div>\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n </div>\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-32 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n </div>\n\n <div class=\"border-t border-dashed border-(--rt-border-color) my-2\"></div>\n\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n </div>\n </dl>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: Skeleton, selector: "rolatech-skeleton" }], encapsulation: i0.ViewEncapsulation.None }); }
361
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceSummarySkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
362
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: InvoiceSummarySkeleton, isStandalone: true, selector: "rolatech-invoice-summary-skeleton", ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <rolatech-skeleton class=\"w-12 h-6\"></rolatech-skeleton>\n\n <dl class=\"space-y-2 text-sm\">\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n </div>\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n </div>\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-32 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n </div>\n\n <div class=\"border-t border-dashed border-(--rt-border-color) my-2\"></div>\n\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n </div>\n </dl>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: Skeleton, selector: "rolatech-skeleton" }], encapsulation: i0.ViewEncapsulation.None }); }
363
363
  }
364
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceSummarySkeleton, decorators: [{
364
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceSummarySkeleton, decorators: [{
365
365
  type: Component,
366
366
  args: [{ selector: 'rolatech-invoice-summary-skeleton', imports: [Skeleton], encapsulation: ViewEncapsulation.None, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <rolatech-skeleton class=\"w-12 h-6\"></rolatech-skeleton>\n\n <dl class=\"space-y-2 text-sm\">\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n </div>\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n </div>\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-32 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n </div>\n\n <div class=\"border-t border-dashed border-(--rt-border-color) my-2\"></div>\n\n <div class=\"flex justify-between\">\n <rolatech-skeleton class=\"w-11 h-4\"></rolatech-skeleton>\n <rolatech-skeleton class=\"w-28 h-4\"></rolatech-skeleton>\n </div>\n </dl>\n</div>\n" }]
367
367
  }] });
368
368
 
369
369
  class InvoiceLinesSkeleton {
370
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceLinesSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
371
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceLinesSkeleton, isStandalone: true, selector: "rolatech-invoice-lines-skeleton", ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <rolatech-skeleton class=\"w-20 h-6\"></rolatech-skeleton>\n\n <div class=\"overflow-x-auto\">\n <table class=\"min-w-full text-sm border border-(--rt-border-color) rounded-lg\">\n <thead class=\"bg-(--rt-raised-background)\">\n <tr>\n <th class=\"px-3 py-2 text-left font-medium border-b border-(--rt-border-color)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-center font-medium border-b border-(--rt-border-color) w-20\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-20\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-32\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n </tr>\n </thead>\n\n <tbody class=\"[&>tr:nth-child(even)]:bg-(--rt-raised-background)\">\n @for (dummy of [0, 1, 2, 3]; track dummy) {\n <tr>\n <!-- Title -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color)\">\n <rolatech-skeleton class=\"h-6\"></rolatech-skeleton>\n </td>\n\n <!-- Qty -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-center text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n\n <!-- Unit price -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n\n <!-- VAT rate -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n <!-- VAT amount -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n\n <!-- Total -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right font-semibold text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: Skeleton, selector: "rolatech-skeleton" }], encapsulation: i0.ViewEncapsulation.None }); }
370
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceLinesSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
371
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceLinesSkeleton, isStandalone: true, selector: "rolatech-invoice-lines-skeleton", ngImport: i0, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <rolatech-skeleton class=\"w-20 h-6\"></rolatech-skeleton>\n\n <div class=\"overflow-x-auto\">\n <table class=\"min-w-full text-sm border border-(--rt-border-color) rounded-lg\">\n <thead class=\"bg-(--rt-raised-background)\">\n <tr>\n <th class=\"px-3 py-2 text-left font-medium border-b border-(--rt-border-color)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-center font-medium border-b border-(--rt-border-color) w-20\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-20\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-32\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n </tr>\n </thead>\n\n <tbody class=\"[&>tr:nth-child(even)]:bg-(--rt-raised-background)\">\n @for (dummy of [0, 1, 2, 3]; track dummy) {\n <tr>\n <!-- Title -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color)\">\n <rolatech-skeleton class=\"h-6\"></rolatech-skeleton>\n </td>\n\n <!-- Qty -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-center text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n\n <!-- Unit price -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n\n <!-- VAT rate -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n <!-- VAT amount -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n\n <!-- Total -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right font-semibold text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: Skeleton, selector: "rolatech-skeleton" }], encapsulation: i0.ViewEncapsulation.None }); }
372
372
  }
373
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceLinesSkeleton, decorators: [{
373
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceLinesSkeleton, decorators: [{
374
374
  type: Component,
375
375
  args: [{ selector: 'rolatech-invoice-lines-skeleton', imports: [Skeleton], encapsulation: ViewEncapsulation.None, template: "<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <rolatech-skeleton class=\"w-20 h-6\"></rolatech-skeleton>\n\n <div class=\"overflow-x-auto\">\n <table class=\"min-w-full text-sm border border-(--rt-border-color) rounded-lg\">\n <thead class=\"bg-(--rt-raised-background)\">\n <tr>\n <th class=\"px-3 py-2 text-left font-medium border-b border-(--rt-border-color)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-center font-medium border-b border-(--rt-border-color) w-20\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-20\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-28\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n <th class=\"px-3 py-2 text-right font-medium border-b border-(--rt-border-color) w-32\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </th>\n </tr>\n </thead>\n\n <tbody class=\"[&>tr:nth-child(even)]:bg-(--rt-raised-background)\">\n @for (dummy of [0, 1, 2, 3]; track dummy) {\n <tr>\n <!-- Title -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color)\">\n <rolatech-skeleton class=\"h-6\"></rolatech-skeleton>\n </td>\n\n <!-- Qty -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-center text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n\n <!-- Unit price -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n\n <!-- VAT rate -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n <!-- VAT amount -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n\n <!-- Total -->\n <td class=\"px-3 py-2 border-t border-(--rt-border-color) text-right font-semibold text-(--rt-text-secondary)\">\n <rolatech-skeleton class=\"h-4\"></rolatech-skeleton>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n" }]
376
376
  }] });
@@ -380,10 +380,10 @@ class InvoiceDetailComponent extends BaseComponent {
380
380
  super(...arguments);
381
381
  this.invoiceService = inject(InvoiceService);
382
382
  this.paymentService = inject(PaymentService);
383
- this.invoice = signal(null, ...(ngDevMode ? [{ debugName: "invoice" }] : []));
383
+ this.invoice = signal(null, ...(ngDevMode ? [{ debugName: "invoice" }] : /* istanbul ignore next */ []));
384
384
  this.status = InvoiceStatus;
385
385
  this.paying = false;
386
- this.loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : []));
386
+ this.loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
387
387
  this.pageMeta = {
388
388
  baseLink: this.readRouteData('invoiceBaseLink', '/invoices'),
389
389
  collectionTitle: this.readRouteData('invoiceCollectionTitle', 'Invoices'),
@@ -414,7 +414,7 @@ class InvoiceDetailComponent extends BaseComponent {
414
414
  }
415
415
  get(id) {
416
416
  this.loading.set(true);
417
- this.invoiceService.get(id).subscribe({
417
+ this.invoiceService.getInvoice(id).subscribe({
418
418
  next: (res) => {
419
419
  this.invoice.set(res.data);
420
420
  this.loading.set(false);
@@ -479,10 +479,10 @@ class InvoiceDetailComponent extends BaseComponent {
479
479
  }
480
480
  return fallback;
481
481
  }
482
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceDetailComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
483
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceDetailComponent, isStandalone: true, selector: "rolatech-invoice-detail", usesInheritance: true, ngImport: i0, template: "<section class=\"invoice-detail-page\">\n @if (loading()) {\n <section class=\"invoice-detail-page__hero invoice-detail-page__hero--loading\">\n <div class=\"invoice-detail-page__hero-copy\">\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">Loading invoice...</h1>\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user-skeleton></rolatech-invoice-user-skeleton>\n <rolatech-invoice-lines-skeleton></rolatech-invoice-lines-skeleton>\n </div>\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary-skeleton></rolatech-invoice-summary-skeleton>\n </div>\n </section>\n } @else if (invoice(); as invoice) {\n <section class=\"invoice-detail-page__hero\">\n <div class=\"invoice-detail-page__hero-copy\">\n <a class=\"invoice-detail-page__back\" [routerLink]=\"pageMeta.baseLink\">\u2190 {{ pageMeta.collectionTitle }}</a>\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">{{ invoice.invoiceNumber || invoice.id }}</h1>\n <p class=\"invoice-detail-page__description\">\n Invoice for {{ invoice.fullName || invoice.firstName + ' ' + invoice.lastName }} created\n {{ invoice.createdAt | date: 'mediumDate' }}.\n </p>\n </div>\n\n <div class=\"invoice-detail-page__hero-side\">\n <span [class]=\"statusToneClass(invoice.status)\">{{ status[invoice.status] }}</span>\n <div class=\"invoice-detail-page__total\">{{ invoice.total | price }}</div>\n <div class=\"invoice-detail-page__note\">\n @if (invoice.dueAt) {\n Due {{ invoice.dueAt | date: 'mediumDate' }}\n } @else {\n Payable on receipt\n }\n </div>\n\n @if (invoice.status.toString() === 'ISSUED' || invoice.status.toString() === 'SENT') {\n <button mat-flat-button [disabled]=\"paying\" class=\"invoice-detail-page__cta\" (click)=\"pay()\">\n {{ paying ? 'Processing payment...' : 'Pay invoice' }}\n </button>\n }\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user\n [firstName]=\"invoice.firstName\"\n [lastName]=\"invoice.lastName\"\n [email]=\"invoice.email\"\n [phone]=\"invoice.phone\"\n ></rolatech-invoice-user>\n\n @if (invoice.lines; as lines) {\n <rolatech-invoice-lines [lines]=\"lines\"></rolatech-invoice-lines>\n }\n </div>\n\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary\n [tax]=\"invoice.vatTotal\"\n [credit]=\"invoice.holdingDepositApplied\"\n [subtotal]=\"invoice.subtotal\"\n [total]=\"invoice.total\"\n ></rolatech-invoice-summary>\n\n <article class=\"invoice-detail-page__panel\">\n <h2 class=\"invoice-detail-page__panel-title\">Invoice note</h2>\n <p class=\"invoice-detail-page__panel-copy\">{{ invoice.note || 'No note added for this invoice.' }}</p>\n\n @if (invoice.status.toString() === 'CREATED' || invoice.status.toString() === 'PAID') {\n <div class=\"invoice-detail-page__panel-row\">\n <span>Payment method</span>\n <strong>Stripe</strong>\n </div>\n }\n </article>\n </div>\n </section>\n }\n</section>\n", styles: [":host{display:block;padding:1rem;--rt-workspace-status-issued-surface: color-mix(in srgb, var(--rt-brand-color) 14%, transparent);--rt-workspace-status-issued-color: color-mix(in srgb, var(--rt-brand-color) 82%, var(--rt-text-primary) 18%);--rt-workspace-status-paid-surface: color-mix(in srgb, var(--rt-brand-color) 16%, var(--rt-base-background, #ffffff));--rt-workspace-status-paid-color: color-mix(in srgb, var(--rt-brand-color) 58%, var(--rt-text-primary) 42%)}.invoice-detail-page{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__hero,.invoice-detail-page__panel{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-detail-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-detail-page__hero-copy,.invoice-detail-page__hero-side,.invoice-detail-page__main,.invoice-detail-page__side{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__back{color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-detail-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-detail-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-detail-page__description,.invoice-detail-page__note,.invoice-detail-page__panel-copy{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-detail-page__status{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.45rem .82rem;font-size:.8rem;font-weight:700}.invoice-detail-page__status--neutral{background:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-brand-color)}.invoice-detail-page__status--issued{background:var(--rt-workspace-status-issued-surface);color:var(--rt-workspace-status-issued-color)}.invoice-detail-page__status--paid{background:var(--rt-workspace-status-paid-surface);color:var(--rt-workspace-status-paid-color)}.invoice-detail-page__status--void{background:color-mix(in srgb,var(--mat-sys-error, #b91c1c) 14%,transparent);color:var(--mat-sys-error, #b91c1c)}.invoice-detail-page__total{color:var(--rt-text-primary);font-size:clamp(1.8rem,2.4vw,2.3rem);font-weight:800}.invoice-detail-page__cta{min-height:3rem;border-radius:9999px}.invoice-detail-page__content{display:grid;gap:1rem}.invoice-detail-page__panel{padding:1rem 1.1rem}.invoice-detail-page__panel-title{margin:0 0 .6rem;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-detail-page__panel-row{display:flex;justify-content:space-between;gap:1rem;margin-top:1rem;color:var(--rt-text-secondary)}.invoice-detail-page__panel-row strong{color:var(--rt-text-primary)}@media(min-width:1024px){.invoice-detail-page__hero{grid-template-columns:minmax(0,1.65fr) minmax(18rem,.85fr);align-items:start}.invoice-detail-page__content{grid-template-columns:minmax(0,1.65fr) minmax(20rem,.85fr);align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: InvoiceUser, selector: "rolatech-invoice-user", inputs: ["firstName", "lastName", "email", "phone"] }, { kind: "component", type: InvoiceLines, selector: "rolatech-invoice-lines", inputs: ["lines"] }, { kind: "component", type: InvoiceSummary, selector: "rolatech-invoice-summary", inputs: ["tax", "credit", "subtotal", "total"] }, { kind: "component", type: InvoiceUserSkeleton, selector: "rolatech-invoice-user-skeleton" }, { kind: "component", type: InvoiceSummarySkeleton, selector: "rolatech-invoice-summary-skeleton" }, { kind: "component", type: InvoiceLinesSkeleton, selector: "rolatech-invoice-lines-skeleton" }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
482
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceDetailComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
483
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceDetailComponent, isStandalone: true, selector: "rolatech-invoice-detail", usesInheritance: true, ngImport: i0, template: "<section class=\"invoice-detail-page\">\n @if (loading()) {\n <section class=\"invoice-detail-page__hero invoice-detail-page__hero--loading\">\n <div class=\"invoice-detail-page__hero-copy\">\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">Loading invoice...</h1>\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user-skeleton></rolatech-invoice-user-skeleton>\n <rolatech-invoice-lines-skeleton></rolatech-invoice-lines-skeleton>\n </div>\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary-skeleton></rolatech-invoice-summary-skeleton>\n </div>\n </section>\n } @else if (invoice(); as invoice) {\n <section class=\"invoice-detail-page__hero\">\n <div class=\"invoice-detail-page__hero-copy\">\n <a class=\"invoice-detail-page__back\" [routerLink]=\"pageMeta.baseLink\">\u2190 {{ pageMeta.collectionTitle }}</a>\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">{{ invoice.invoiceNumber || invoice.id }}</h1>\n <p class=\"invoice-detail-page__description\">\n Invoice for {{ invoice.fullName || invoice.firstName + ' ' + invoice.lastName }} created\n {{ invoice.createdAt | date: 'mediumDate' }}.\n </p>\n </div>\n\n <div class=\"invoice-detail-page__hero-side\">\n <span [class]=\"statusToneClass(invoice.status)\">{{ status[invoice.status] }}</span>\n <div class=\"invoice-detail-page__total\">{{ invoice.total | price }}</div>\n <div class=\"invoice-detail-page__note\">\n @if (invoice.dueAt) {\n Due {{ invoice.dueAt | date: 'mediumDate' }}\n } @else {\n Payable on receipt\n }\n </div>\n\n @if (invoice.status.toString() === 'ISSUED' || invoice.status.toString() === 'SENT') {\n <button mat-flat-button [disabled]=\"paying\" class=\"invoice-detail-page__cta\" (click)=\"pay()\">\n {{ paying ? 'Processing payment...' : 'Pay invoice' }}\n </button>\n }\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user\n [firstName]=\"invoice.firstName\"\n [lastName]=\"invoice.lastName\"\n [email]=\"invoice.email\"\n [phone]=\"invoice.phone\"\n ></rolatech-invoice-user>\n\n @if (invoice.lines; as lines) {\n <rolatech-invoice-lines [lines]=\"lines\"></rolatech-invoice-lines>\n }\n </div>\n\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary\n [tax]=\"invoice.vatTotal\"\n [credit]=\"invoice.holdingDepositApplied\"\n [subtotal]=\"invoice.subtotal\"\n [total]=\"invoice.total\"\n ></rolatech-invoice-summary>\n\n <article class=\"invoice-detail-page__panel\">\n <h2 class=\"invoice-detail-page__panel-title\">Invoice note</h2>\n <p class=\"invoice-detail-page__panel-copy\">{{ invoice.note || 'No note added for this invoice.' }}</p>\n\n @if (invoice.status.toString() === 'CREATED' || invoice.status.toString() === 'PAID') {\n <div class=\"invoice-detail-page__panel-row\">\n <span>Payment method</span>\n <strong>Stripe</strong>\n </div>\n }\n </article>\n </div>\n </section>\n }\n</section>\n", styles: [":host{display:block;padding:1rem;--rt-workspace-status-issued-surface: color-mix(in srgb, var(--rt-brand-color) 14%, transparent);--rt-workspace-status-issued-color: color-mix(in srgb, var(--rt-brand-color) 82%, var(--rt-text-primary) 18%);--rt-workspace-status-paid-surface: color-mix(in srgb, var(--rt-brand-color) 16%, var(--rt-base-background, #ffffff));--rt-workspace-status-paid-color: color-mix(in srgb, var(--rt-brand-color) 58%, var(--rt-text-primary) 42%)}.invoice-detail-page{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__hero,.invoice-detail-page__panel{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-detail-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-detail-page__hero-copy,.invoice-detail-page__hero-side,.invoice-detail-page__main,.invoice-detail-page__side{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__back{color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-detail-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-detail-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-detail-page__description,.invoice-detail-page__note,.invoice-detail-page__panel-copy{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-detail-page__status{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.45rem .82rem;font-size:.8rem;font-weight:700}.invoice-detail-page__status--neutral{background:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-brand-color)}.invoice-detail-page__status--issued{background:var(--rt-workspace-status-issued-surface);color:var(--rt-workspace-status-issued-color)}.invoice-detail-page__status--paid{background:var(--rt-workspace-status-paid-surface);color:var(--rt-workspace-status-paid-color)}.invoice-detail-page__status--void{background:color-mix(in srgb,var(--mat-sys-error, #b91c1c) 14%,transparent);color:var(--mat-sys-error, #b91c1c)}.invoice-detail-page__total{color:var(--rt-text-primary);font-size:clamp(1.8rem,2.4vw,2.3rem);font-weight:800}.invoice-detail-page__cta{min-height:3rem;border-radius:9999px}.invoice-detail-page__content{display:grid;gap:1rem}.invoice-detail-page__panel{padding:1rem 1.1rem}.invoice-detail-page__panel-title{margin:0 0 .6rem;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-detail-page__panel-row{display:flex;justify-content:space-between;gap:1rem;margin-top:1rem;color:var(--rt-text-secondary)}.invoice-detail-page__panel-row strong{color:var(--rt-text-primary)}@media(min-width:1024px){.invoice-detail-page__hero{grid-template-columns:minmax(0,1.65fr) minmax(18rem,.85fr);align-items:start}.invoice-detail-page__content{grid-template-columns:minmax(0,1.65fr) minmax(20rem,.85fr);align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: InvoiceUser, selector: "rolatech-invoice-user", inputs: ["firstName", "lastName", "email", "phone"] }, { kind: "component", type: InvoiceLines, selector: "rolatech-invoice-lines", inputs: ["lines"] }, { kind: "component", type: InvoiceSummary, selector: "rolatech-invoice-summary", inputs: ["tax", "credit", "subtotal", "total"] }, { kind: "component", type: InvoiceUserSkeleton, selector: "rolatech-invoice-user-skeleton" }, { kind: "component", type: InvoiceSummarySkeleton, selector: "rolatech-invoice-summary-skeleton" }, { kind: "component", type: InvoiceLinesSkeleton, selector: "rolatech-invoice-lines-skeleton" }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
484
484
  }
485
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceDetailComponent, decorators: [{
485
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceDetailComponent, decorators: [{
486
486
  type: Component,
487
487
  args: [{ selector: 'rolatech-invoice-detail', imports: [
488
488
  CommonModule,
@@ -515,13 +515,13 @@ class InvoiceManageIndex extends BaseComponent {
515
515
  super(...arguments);
516
516
  this.invoiceService = inject(InvoiceService);
517
517
  this.enumApi = inject(EnumApiClient);
518
- this.invoiceTypeMap = signal({}, ...(ngDevMode ? [{ debugName: "invoiceTypeMap" }] : []));
518
+ this.invoiceTypeMap = signal({}, ...(ngDevMode ? [{ debugName: "invoiceTypeMap" }] : /* istanbul ignore next */ []));
519
519
  this.select = 0;
520
520
  this.loading = false;
521
- this.invoices = signal([], ...(ngDevMode ? [{ debugName: "invoices" }] : []));
521
+ this.invoices = signal([], ...(ngDevMode ? [{ debugName: "invoices" }] : /* istanbul ignore next */ []));
522
522
  this.length = 100;
523
523
  this.pageSize = 15;
524
- this.pageIndex = signal(0, ...(ngDevMode ? [{ debugName: "pageIndex" }] : []));
524
+ this.pageIndex = signal(0, ...(ngDevMode ? [{ debugName: "pageIndex" }] : /* istanbul ignore next */ []));
525
525
  this.pageSizeOptions = [5, 10, 25, 100];
526
526
  this.links = [
527
527
  {
@@ -572,10 +572,9 @@ class InvoiceManageIndex extends BaseComponent {
572
572
  }))
573
573
  .subscribe({
574
574
  next: (res) => {
575
- console.log(res);
576
- this.invoices.set(res.data);
575
+ this.invoices.set(res.data ?? []);
577
576
  this.meta = res.meta;
578
- this.length = res.meta.pagination.count;
577
+ this.length = res.meta?.pagination?.count ?? res.data?.length ?? 0;
579
578
  },
580
579
  error: () => {
581
580
  this.invoices.set([]);
@@ -618,10 +617,10 @@ class InvoiceManageIndex extends BaseComponent {
618
617
  return 'bg-gray-100 text-gray-700';
619
618
  }
620
619
  }
621
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageIndex, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
622
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceManageIndex, isStandalone: true, selector: "rolatech-invoice-manage-index", usesInheritance: true, ngImport: i0, template: "<rolatech-toolbar title=\"Invoices\">\n <div class=\"flex items-center gap-2\"></div>\n</rolatech-toolbar>\n<rolatech-tabs [select]=\"select\">\n @for (item of links; track item) { @if (item.status) {\n <rolatech-tab class=\"cursor-pointer\" [label]=\"item.name\" routerLink=\"./\" [queryParams]=\"{ status: item.status }\"></rolatech-tab>\n } @else {\n <rolatech-tab class=\"cursor-pointer\" [label]=\"item.name\" routerLink=\"./\"></rolatech-tab>\n } }\n</rolatech-tabs>\n<div class=\"p-3 overflow-x-auto\">\n <table class=\"min-w-full\">\n <thead class=\"bg-(--rt-raised-background)\">\n <tr>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">#ID</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Status</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Email</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Profile</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Type</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Total</th>\n </tr>\n </thead>\n <tbody>\n @for (item of invoices(); track $index) {\n <!-- <rolatech-invoice-manage-item [invoice]=\"item\"></rolatech-invoice-manage-item> -->\n <tr class=\"hover:bg-(--rt-raised-background) hover:cursor-pointer cursor-pointer\" [routerLink]=\"['./', item.id]\">\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.id}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">\n <span\n class=\"inline-flex items-center rounded-full px-3 py-1 text-xs font-medium\"\n [ngClass]=\"statusBadgeClass(item.status)\"\n >{{item.status}}</span\n >\n </td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.email}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.fullName}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{invoiceTypeMap()[item.type] || item.type}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.total | price}}</td>\n </tr>\n }\n </tbody>\n </table>\n</div>\n<!-- <div>\n <table class=\"min-w-full text-sm\">\n <thead class=\"border-b border-(--rt-border-color) bg-(--rt-raised-background)\">\n <tr>\n <th class=\"py-2 text-left font-medium text-gray-600\">#ID</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Status</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Email</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Profile</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Total</th>\n </tr>\n </thead>\n\n <tbody>\n @for (item of invoices(); track $index) {\n <tr class=\"border-b border-(--rt-border-color) hover:bg-(--rt-raised-background) hover:cursor-pointer\">\n <td class=\"py-2\">{{item.id}}</td>\n <td class=\"py-2 text-right\">{{item.status}}</td>\n <td class=\"py-2 text-right\">{{item.email}}</td>\n <td class=\"py-2 text-right\">{{item.firstName}}, {{item.lastName}}</td>\n <td class=\"py-2 text-right font-semibold\">{{item.total | price}}</td>\n </tr>\n }\n </tbody>\n </table>\n</div> -->\n<mat-paginator\n #paginator\n [length]=\"length\"\n [pageSize]=\"pageSize\"\n [pageIndex]=\"pageIndex()\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onPage($event)\"\n hidePageSize\n showFirstLastButtons\n>\n</mat-paginator>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: ToolbarComponent, selector: "rolatech-toolbar", inputs: ["title", "subtitle", "back", "link", "large", "divider"] }, { kind: "component", type: TabsComponent, selector: "rolatech-tabs", inputs: ["select", "loading", "block", "mode"], outputs: ["selectChange"] }, { kind: "component", type: TabComponent, selector: "rolatech-tab", inputs: ["label"], outputs: ["selectRequested"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i6.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
620
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageIndex, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
621
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceManageIndex, isStandalone: true, selector: "rolatech-invoice-manage-index", usesInheritance: true, ngImport: i0, template: "<rolatech-toolbar title=\"Invoices\">\n <div class=\"flex items-center gap-2\"></div>\n</rolatech-toolbar>\n<rolatech-tabs [select]=\"select\">\n @for (item of links; track item) { @if (item.status) {\n <rolatech-tab class=\"cursor-pointer\" [label]=\"item.name\" routerLink=\"./\" [queryParams]=\"{ status: item.status }\"></rolatech-tab>\n } @else {\n <rolatech-tab class=\"cursor-pointer\" [label]=\"item.name\" routerLink=\"./\"></rolatech-tab>\n } }\n</rolatech-tabs>\n<div class=\"p-3 overflow-x-auto\">\n <table class=\"min-w-full\">\n <thead class=\"bg-(--rt-raised-background)\">\n <tr>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">#ID</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Status</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Email</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Profile</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Type</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Total</th>\n </tr>\n </thead>\n <tbody>\n @for (item of invoices(); track $index) {\n <!-- <rolatech-invoice-manage-item [invoice]=\"item\"></rolatech-invoice-manage-item> -->\n <tr class=\"hover:bg-(--rt-raised-background) hover:cursor-pointer cursor-pointer\" [routerLink]=\"['./', item.id]\">\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.id}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">\n <span\n class=\"inline-flex items-center rounded-full px-3 py-1 text-xs font-medium\"\n [ngClass]=\"statusBadgeClass(item.status)\"\n >{{item.status}}</span\n >\n </td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.email}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.fullName}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{invoiceTypeMap()[item.type] || item.type}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.total | price}}</td>\n </tr>\n }\n </tbody>\n </table>\n</div>\n<!-- <div>\n <table class=\"min-w-full text-sm\">\n <thead class=\"border-b border-(--rt-border-color) bg-(--rt-raised-background)\">\n <tr>\n <th class=\"py-2 text-left font-medium text-gray-600\">#ID</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Status</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Email</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Profile</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Total</th>\n </tr>\n </thead>\n\n <tbody>\n @for (item of invoices(); track $index) {\n <tr class=\"border-b border-(--rt-border-color) hover:bg-(--rt-raised-background) hover:cursor-pointer\">\n <td class=\"py-2\">{{item.id}}</td>\n <td class=\"py-2 text-right\">{{item.status}}</td>\n <td class=\"py-2 text-right\">{{item.email}}</td>\n <td class=\"py-2 text-right\">{{item.firstName}}, {{item.lastName}}</td>\n <td class=\"py-2 text-right font-semibold\">{{item.total | price}}</td>\n </tr>\n }\n </tbody>\n </table>\n</div> -->\n<mat-paginator\n #paginator\n [length]=\"length\"\n [pageSize]=\"pageSize\"\n [pageIndex]=\"pageIndex()\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onPage($event)\"\n hidePageSize\n showFirstLastButtons\n>\n</mat-paginator>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: ToolbarComponent, selector: "rolatech-toolbar", inputs: ["title", "subtitle", "back", "link", "large", "divider"] }, { kind: "component", type: TabsComponent, selector: "rolatech-tabs", inputs: ["select", "loading", "block", "mode"], outputs: ["selectChange"] }, { kind: "component", type: TabComponent, selector: "rolatech-tab", inputs: ["label"], outputs: ["selectRequested"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i6.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
623
622
  }
624
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageIndex, decorators: [{
623
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageIndex, decorators: [{
625
624
  type: Component,
626
625
  args: [{ selector: 'rolatech-invoice-manage-index', imports: [CommonModule, RouterLink, ToolbarComponent, TabsComponent, TabComponent, MatPaginatorModule, PricePipe], template: "<rolatech-toolbar title=\"Invoices\">\n <div class=\"flex items-center gap-2\"></div>\n</rolatech-toolbar>\n<rolatech-tabs [select]=\"select\">\n @for (item of links; track item) { @if (item.status) {\n <rolatech-tab class=\"cursor-pointer\" [label]=\"item.name\" routerLink=\"./\" [queryParams]=\"{ status: item.status }\"></rolatech-tab>\n } @else {\n <rolatech-tab class=\"cursor-pointer\" [label]=\"item.name\" routerLink=\"./\"></rolatech-tab>\n } }\n</rolatech-tabs>\n<div class=\"p-3 overflow-x-auto\">\n <table class=\"min-w-full\">\n <thead class=\"bg-(--rt-raised-background)\">\n <tr>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">#ID</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Status</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Email</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Profile</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Type</th>\n <th class=\"p-3 border-b border-(--rt-border-color) text-left\">Total</th>\n </tr>\n </thead>\n <tbody>\n @for (item of invoices(); track $index) {\n <!-- <rolatech-invoice-manage-item [invoice]=\"item\"></rolatech-invoice-manage-item> -->\n <tr class=\"hover:bg-(--rt-raised-background) hover:cursor-pointer cursor-pointer\" [routerLink]=\"['./', item.id]\">\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.id}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">\n <span\n class=\"inline-flex items-center rounded-full px-3 py-1 text-xs font-medium\"\n [ngClass]=\"statusBadgeClass(item.status)\"\n >{{item.status}}</span\n >\n </td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.email}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.fullName}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{invoiceTypeMap()[item.type] || item.type}}</td>\n <td class=\"p-3 border-b border-(--rt-border-color)\">{{item.total | price}}</td>\n </tr>\n }\n </tbody>\n </table>\n</div>\n<!-- <div>\n <table class=\"min-w-full text-sm\">\n <thead class=\"border-b border-(--rt-border-color) bg-(--rt-raised-background)\">\n <tr>\n <th class=\"py-2 text-left font-medium text-gray-600\">#ID</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Status</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Email</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Profile</th>\n <th class=\"py-2 text-right font-medium text-gray-600\">Total</th>\n </tr>\n </thead>\n\n <tbody>\n @for (item of invoices(); track $index) {\n <tr class=\"border-b border-(--rt-border-color) hover:bg-(--rt-raised-background) hover:cursor-pointer\">\n <td class=\"py-2\">{{item.id}}</td>\n <td class=\"py-2 text-right\">{{item.status}}</td>\n <td class=\"py-2 text-right\">{{item.email}}</td>\n <td class=\"py-2 text-right\">{{item.firstName}}, {{item.lastName}}</td>\n <td class=\"py-2 text-right font-semibold\">{{item.total | price}}</td>\n </tr>\n }\n </tbody>\n </table>\n</div> -->\n<mat-paginator\n #paginator\n [length]=\"length\"\n [pageSize]=\"pageSize\"\n [pageIndex]=\"pageIndex()\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onPage($event)\"\n hidePageSize\n showFirstLastButtons\n>\n</mat-paginator>\n" }]
627
626
  }] });
@@ -716,10 +715,10 @@ class InvoiceManageCreate {
716
715
  todayIso() {
717
716
  return new Date().toISOString().slice(0, 10);
718
717
  }
719
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageCreate, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
720
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceManageCreate, isStandalone: true, selector: "rolatech-invoice-manage-create", ngImport: i0, template: "<rolatech-toolbar title=\"Create Invoice\">\n <button\n mat-flat-button\n color=\"primary\"\n (click)=\"save(invoiceForm)\"\n [disabled]=\"!invoiceForm.form.valid || invoice.lines.length === 0\"\n >\n Save\n </button>\n</rolatech-toolbar>\n<div class=\"p-4 space-y-6\">\n <form #invoiceForm=\"ngForm\" novalidate>\n <mat-card appearance=\"outlined\" class=\"p-4\">\n <div class=\"grid lg:grid-cols-2 gap-4\">\n <mat-form-field appearance=\"fill\">\n <mat-label>Customer name</mat-label>\n <input matInput name=\"customerName\" [(ngModel)]=\"invoice.customerName\" required />\n @if (invoiceForm.submitted && !invoice.customerName) {<mat-error>Name is required</mat-error>}\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Customer email</mat-label>\n <input matInput type=\"email\" name=\"customerEmail\" [(ngModel)]=\"invoice.customerEmail\" #email=\"ngModel\" email />\n @if (email.invalid && (email.dirty || email.touched)) {<mat-error>Invalid email</mat-error>}\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\" class=\"lg:col-span-2\">\n <mat-label>Customer address</mat-label>\n <textarea matInput rows=\"2\" name=\"customerAddress\" [(ngModel)]=\"invoice.customerAddress\"></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Currency</mat-label>\n <mat-select name=\"currency\" [(ngModel)]=\"invoice.currency\" required>\n <mat-option value=\"GBP\">GBP</mat-option>\n <mat-option value=\"USD\">USD</mat-option>\n <mat-option value=\"EUR\">EUR</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Issue date</mat-label>\n <input matInput type=\"date\" name=\"issueDate\" [(ngModel)]=\"invoice.issueDate\" required />\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Due date</mat-label>\n <input matInput type=\"date\" name=\"dueDate\" [(ngModel)]=\"invoice.dueDate\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\" class=\"lg:col-span-2\">\n <mat-label>Notes</mat-label>\n <textarea\n matInput\n rows=\"2\"\n name=\"notes\"\n [(ngModel)]=\"invoice.notes\"\n placeholder=\"Optional notes shown on the invoice\"\n ></textarea>\n </mat-form-field>\n </div>\n </mat-card>\n\n <mat-card appearance=\"outlined\" class=\"p-4 space-y-4 mt-4\">\n <div class=\"flex items-center justify-between\">\n <h2 class=\"text-xl font-medium\">Line items</h2>\n <button mat-stroked-button type=\"button\" (click)=\"addLine()\">\n <mat-icon>add</mat-icon>\n Add line\n </button>\n </div>\n\n <div class=\"hidden lg:grid grid-cols-12 gap-2 text-sm font-medium px-2\">\n <div class=\"col-span-3\">Type</div>\n <div class=\"col-span-3\">Description</div>\n <div class=\"col-span-1 text-right\">Qty</div>\n <div class=\"col-span-2 text-right\">Unit Price</div>\n <div class=\"col-span-2 text-right\">Tax %</div>\n <div class=\"col-span-1\"></div>\n </div>\n\n <div class=\"space-y-3\">\n @for ( line of invoice.lines; track line; let i = $index) {\n <div class=\"grid grid-cols-1 lg:grid-cols-12 gap-2 items-start\">\n <rolatech-enum-select\n class=\"lg:col-span-3\"\n [resource]=\"'billing'\"\n [enumName]=\"'InvoiceLineType'\"\n [label]=\"'Line type'\"\n [placeholder]=\"'Select\u2026'\"\n [(value)]=\"line.type\"\n ></rolatech-enum-select>\n <mat-form-field class=\"lg:col-span-3\" appearance=\"fill\">\n <mat-label>Description</mat-label>\n <input\n matInput\n [name]=\"'desc'+i\"\n [(ngModel)]=\"line.description\"\n required\n placeholder=\"e.g. Photo editing package\"\n />\n </mat-form-field>\n\n <mat-form-field class=\"lg:col-span-1\" appearance=\"fill\">\n <mat-label>Quantity</mat-label>\n <input matInput type=\"number\" min=\"1\" step=\"1\" [name]=\"'qty'+i\" [(ngModel)]=\"line.quantity\" required />\n </mat-form-field>\n\n <mat-form-field class=\"lg:col-span-2\" appearance=\"fill\">\n <mat-label>Unit Price</mat-label>\n <input matInput type=\"number\" min=\"0\" step=\"0.01\" [name]=\"'unit'+i\" [(ngModel)]=\"line.unitPrice\" required />\n <mat-hint>e.g. 99.99</mat-hint>\n </mat-form-field>\n\n <mat-form-field class=\"lg:col-span-2\" appearance=\"fill\">\n <mat-label>Tax %</mat-label>\n <input matInput type=\"number\" min=\"0\" step=\"0.01\" [name]=\"'tax'+i\" [(ngModel)]=\"line.taxRate\" />\n </mat-form-field>\n\n <div class=\"lg:col-span-1 flex items-center justify-end\">\n <button mat-icon-button color=\"warn\" type=\"button\" (click)=\"removeLine(i)\" aria-label=\"Remove line\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n <mat-divider></mat-divider>\n }\n </div>\n\n <div class=\"flex flex-col items-end space-y-1\">\n <div class=\"text-sm\">\n Subtotal: <span class=\"font-medium\">{{ subtotalMajor() | number:'1.2-2' }} {{ invoice.currency }}</span>\n </div>\n <div class=\"text-sm\">\n Tax: <span class=\"font-medium\">{{ taxMajor() | number:'1.2-2' }} {{ invoice.currency }}</span>\n </div>\n <div class=\"text-lg font-semibold\">Total: {{ totalMajor() | number:'1.2-2' }} {{ invoice.currency }}</div>\n </div>\n </mat-card>\n </form>\n\n @if (lastResponse) {\n <mat-card appearance=\"outlined\" class=\"p-4 flex items-center justify-between\">\n <div>\n <div class=\"font-medium\">Created invoice #{{ lastResponse.data.id }}</div>\n <div class=\"text-sm opacity-70\">\n Total: {{ penceToMajor(lastResponse.data.total) | number:'1.2-2' }} {{ invoice.currency }}\n </div>\n </div>\n <div class=\"space-x-2\">\n <button mat-stroked-button (click)=\"resetForm()\">Create another</button>\n <button mat-flat-button color=\"primary\">Download PDF</button>\n </div>\n </mat-card>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.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: i1$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i1$2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i7.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i8.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: ToolbarComponent, selector: "rolatech-toolbar", inputs: ["title", "subtitle", "back", "link", "large", "divider"] }, { kind: "component", type: EnumSelect, selector: "rolatech-enum-select", inputs: ["resource", "enumName", "label", "placeholder", "disabled", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }] }); }
718
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageCreate, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
719
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceManageCreate, isStandalone: true, selector: "rolatech-invoice-manage-create", ngImport: i0, template: "<rolatech-toolbar title=\"Create Invoice\">\n <button\n mat-flat-button\n color=\"primary\"\n (click)=\"save(invoiceForm)\"\n [disabled]=\"!invoiceForm.form.valid || invoice.lines.length === 0\"\n >\n Save\n </button>\n</rolatech-toolbar>\n<div class=\"p-4 space-y-6\">\n <form #invoiceForm=\"ngForm\" novalidate>\n <mat-card appearance=\"outlined\" class=\"p-4\">\n <div class=\"grid lg:grid-cols-2 gap-4\">\n <mat-form-field appearance=\"fill\">\n <mat-label>Customer name</mat-label>\n <input matInput name=\"customerName\" [(ngModel)]=\"invoice.customerName\" required />\n @if (invoiceForm.submitted && !invoice.customerName) {<mat-error>Name is required</mat-error>}\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Customer email</mat-label>\n <input matInput type=\"email\" name=\"customerEmail\" [(ngModel)]=\"invoice.customerEmail\" #email=\"ngModel\" email />\n @if (email.invalid && (email.dirty || email.touched)) {<mat-error>Invalid email</mat-error>}\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\" class=\"lg:col-span-2\">\n <mat-label>Customer address</mat-label>\n <textarea matInput rows=\"2\" name=\"customerAddress\" [(ngModel)]=\"invoice.customerAddress\"></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Currency</mat-label>\n <mat-select name=\"currency\" [(ngModel)]=\"invoice.currency\" required>\n <mat-option value=\"GBP\">GBP</mat-option>\n <mat-option value=\"USD\">USD</mat-option>\n <mat-option value=\"EUR\">EUR</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Issue date</mat-label>\n <input matInput type=\"date\" name=\"issueDate\" [(ngModel)]=\"invoice.issueDate\" required />\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Due date</mat-label>\n <input matInput type=\"date\" name=\"dueDate\" [(ngModel)]=\"invoice.dueDate\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\" class=\"lg:col-span-2\">\n <mat-label>Notes</mat-label>\n <textarea\n matInput\n rows=\"2\"\n name=\"notes\"\n [(ngModel)]=\"invoice.notes\"\n placeholder=\"Optional notes shown on the invoice\"\n ></textarea>\n </mat-form-field>\n </div>\n </mat-card>\n\n <mat-card appearance=\"outlined\" class=\"p-4 space-y-4 mt-4\">\n <div class=\"flex items-center justify-between\">\n <h2 class=\"text-xl font-medium\">Line items</h2>\n <button mat-stroked-button type=\"button\" (click)=\"addLine()\">\n <mat-icon>add</mat-icon>\n Add line\n </button>\n </div>\n\n <div class=\"hidden lg:grid grid-cols-12 gap-2 text-sm font-medium px-2\">\n <div class=\"col-span-3\">Type</div>\n <div class=\"col-span-3\">Description</div>\n <div class=\"col-span-1 text-right\">Qty</div>\n <div class=\"col-span-2 text-right\">Unit Price</div>\n <div class=\"col-span-2 text-right\">Tax %</div>\n <div class=\"col-span-1\"></div>\n </div>\n\n <div class=\"space-y-3\">\n @for ( line of invoice.lines; track line; let i = $index) {\n <div class=\"grid grid-cols-1 lg:grid-cols-12 gap-2 items-start\">\n <rolatech-enum-select\n class=\"lg:col-span-3\"\n [resource]=\"'billing'\"\n [enumName]=\"'InvoiceLineType'\"\n [label]=\"'Line type'\"\n [placeholder]=\"'Select\u2026'\"\n [(value)]=\"line.type\"\n ></rolatech-enum-select>\n <mat-form-field class=\"lg:col-span-3\" appearance=\"fill\">\n <mat-label>Description</mat-label>\n <input\n matInput\n [name]=\"'desc'+i\"\n [(ngModel)]=\"line.description\"\n required\n placeholder=\"e.g. Photo editing package\"\n />\n </mat-form-field>\n\n <mat-form-field class=\"lg:col-span-1\" appearance=\"fill\">\n <mat-label>Quantity</mat-label>\n <input matInput type=\"number\" min=\"1\" step=\"1\" [name]=\"'qty'+i\" [(ngModel)]=\"line.quantity\" required />\n </mat-form-field>\n\n <mat-form-field class=\"lg:col-span-2\" appearance=\"fill\">\n <mat-label>Unit Price</mat-label>\n <input matInput type=\"number\" min=\"0\" step=\"0.01\" [name]=\"'unit'+i\" [(ngModel)]=\"line.unitPrice\" required />\n <mat-hint>e.g. 99.99</mat-hint>\n </mat-form-field>\n\n <mat-form-field class=\"lg:col-span-2\" appearance=\"fill\">\n <mat-label>Tax %</mat-label>\n <input matInput type=\"number\" min=\"0\" step=\"0.01\" [name]=\"'tax'+i\" [(ngModel)]=\"line.taxRate\" />\n </mat-form-field>\n\n <div class=\"lg:col-span-1 flex items-center justify-end\">\n <button mat-icon-button color=\"warn\" type=\"button\" (click)=\"removeLine(i)\" aria-label=\"Remove line\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n <mat-divider></mat-divider>\n }\n </div>\n\n <div class=\"flex flex-col items-end space-y-1\">\n <div class=\"text-sm\">\n Subtotal: <span class=\"font-medium\">{{ subtotalMajor() | number:'1.2-2' }} {{ invoice.currency }}</span>\n </div>\n <div class=\"text-sm\">\n Tax: <span class=\"font-medium\">{{ taxMajor() | number:'1.2-2' }} {{ invoice.currency }}</span>\n </div>\n <div class=\"text-lg font-semibold\">Total: {{ totalMajor() | number:'1.2-2' }} {{ invoice.currency }}</div>\n </div>\n </mat-card>\n </form>\n\n @if (lastResponse) {\n <mat-card appearance=\"outlined\" class=\"p-4 flex items-center justify-between\">\n <div>\n <div class=\"font-medium\">Created invoice #{{ lastResponse.data.id }}</div>\n <div class=\"text-sm opacity-70\">\n Total: {{ penceToMajor(lastResponse.data.total) | number:'1.2-2' }} {{ invoice.currency }}\n </div>\n </div>\n <div class=\"space-x-2\">\n <button mat-stroked-button (click)=\"resetForm()\">Create another</button>\n <button mat-flat-button color=\"primary\">Download PDF</button>\n </div>\n </mat-card>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.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: i1$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i1$2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i7.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i8.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: ToolbarComponent, selector: "rolatech-toolbar", inputs: ["title", "subtitle", "back", "link", "large", "divider"] }, { kind: "component", type: EnumSelect, selector: "rolatech-enum-select", inputs: ["resource", "enumName", "label", "placeholder", "disabled", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }] }); }
721
720
  }
722
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageCreate, decorators: [{
721
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageCreate, decorators: [{
723
722
  type: Component,
724
723
  args: [{ selector: 'rolatech-invoice-manage-create', imports: [
725
724
  CommonModule,
@@ -751,14 +750,14 @@ class InvoiceEdit extends BaseComponent {
751
750
  constructor() {
752
751
  super(...arguments);
753
752
  this.minDate = new Date();
754
- this.invoice = model.required(...(ngDevMode ? [{ debugName: "invoice" }] : []));
753
+ this.invoice = model.required(...(ngDevMode ? [{ debugName: "invoice" }] : /* istanbul ignore next */ []));
755
754
  this.output = output();
756
755
  }
757
756
  ngDoCheck() {
758
757
  this.output.emit(this.invoice());
759
758
  }
760
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceEdit, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
761
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: InvoiceEdit, isStandalone: true, selector: "rolatech-invoice-edit", inputs: { invoice: { classPropertyName: "invoice", publicName: "invoice", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { invoice: "invoiceChange", output: "output" }, providers: [
759
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceEdit, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
760
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.5", type: InvoiceEdit, isStandalone: true, selector: "rolatech-invoice-edit", inputs: { invoice: { classPropertyName: "invoice", publicName: "invoice", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { invoice: "invoiceChange", output: "output" }, providers: [
762
761
  {
763
762
  provide: DateAdapter,
764
763
  useClass: MomentDateAdapter,
@@ -767,7 +766,7 @@ class InvoiceEdit extends BaseComponent {
767
766
  { provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
768
767
  ], usesInheritance: true, ngImport: i0, template: "<div class=\"flex flex-col gap-2\">\n <div class=\"flex justify-between gap-3\">\n <mat-form-field appearance=\"fill\" subscriptSizing=\"dynamic\">\n <mat-label>Firstname</mat-label>\n <input matInput [(ngModel)]=\"invoice().firstName\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" subscriptSizing=\"dynamic\">\n <mat-label>Lastname</mat-label>\n <input matInput [(ngModel)]=\"invoice().lastName\" />\n </mat-form-field>\n </div>\n <mat-form-field appearance=\"fill\" subscriptSizing=\"dynamic\">\n <mat-label>Email</mat-label>\n <input matInput [(ngModel)]=\"invoice().email\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" subscriptSizing=\"dynamic\">\n <mat-label>Phone</mat-label>\n <input matInput [(ngModel)]=\"invoice().phone\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" subscriptSizing=\"dynamic\">\n <mat-label>Discount total</mat-label>\n <input matInput [(ngModel)]=\"invoice().discountAmount\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" subscriptSizing=\"dynamic\">\n <mat-label>Total</mat-label>\n <input matInput [(ngModel)]=\"invoice().total\" />\n </mat-form-field>\n <!-- <mat-form-field appearance=\"fill\" subscriptSizing=\"dynamic\">\n <mat-label i18n>Move-in date</mat-label>\n <input\n matInput\n placeholder=\"Move-in date\"\n [min]=\"minDate\"\n [matDatepicker]=\"startDatePicker\"\n (focus)=\"startDatePicker.open()\"\n [(ngModel)]=\"invoice().startDate\"\n (dateInput)=\"invoice().startDate = $event.value.format('YYYY-MM-DD')\"\n required\n readonly\n />\n <mat-datepicker-toggle matIconPrefix [for]=\"startDatePicker\"></mat-datepicker-toggle>\n <mat-datepicker #startDatePicker></mat-datepicker>\n </mat-form-field> -->\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.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: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatOptionModule }] }); }
769
768
  }
770
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceEdit, decorators: [{
769
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceEdit, decorators: [{
771
770
  type: Component,
772
771
  args: [{ selector: 'rolatech-invoice-edit', imports: [CommonModule, FormsModule, MatInputModule, MatDatepickerModule, MatSelectModule, MatOptionModule], providers: [
773
772
  {
@@ -782,21 +781,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
782
781
  class InvoiceStore {
783
782
  constructor() {
784
783
  this.api = inject(InvoiceService);
785
- this._lines = signal([], ...(ngDevMode ? [{ debugName: "_lines" }] : []));
784
+ this._lines = signal([], ...(ngDevMode ? [{ debugName: "_lines" }] : /* istanbul ignore next */ []));
786
785
  // --- state ---
787
- this.invoiceId = signal(null, ...(ngDevMode ? [{ debugName: "invoiceId" }] : []));
788
- this.invoice = signal(null, ...(ngDevMode ? [{ debugName: "invoice" }] : []));
786
+ this.invoiceId = signal(null, ...(ngDevMode ? [{ debugName: "invoiceId" }] : /* istanbul ignore next */ []));
787
+ this.invoice = signal(null, ...(ngDevMode ? [{ debugName: "invoice" }] : /* istanbul ignore next */ []));
789
788
  /** last server-saved snapshot */
790
- this.pristine = signal(null, ...(ngDevMode ? [{ debugName: "pristine" }] : []));
791
- this.status = signal('idle', ...(ngDevMode ? [{ debugName: "status" }] : []));
792
- this.error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
789
+ this.pristine = signal(null, ...(ngDevMode ? [{ debugName: "pristine" }] : /* istanbul ignore next */ []));
790
+ this.status = signal('idle', ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
791
+ this.error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
793
792
  // editor UI state
794
- this.editorOpen = signal(false, ...(ngDevMode ? [{ debugName: "editorOpen" }] : []));
795
- this.editingLineId = signal(null, ...(ngDevMode ? [{ debugName: "editingLineId" }] : []));
793
+ this.editorOpen = signal(false, ...(ngDevMode ? [{ debugName: "editorOpen" }] : /* istanbul ignore next */ []));
794
+ this.editingLineId = signal(null, ...(ngDevMode ? [{ debugName: "editingLineId" }] : /* istanbul ignore next */ []));
796
795
  // --- derived ---
797
- this.lines = computed(() => this.invoice()?.lines ?? [], ...(ngDevMode ? [{ debugName: "lines" }] : []));
798
- this.currency = computed(() => this.invoice()?.currency ?? 'GBP', ...(ngDevMode ? [{ debugName: "currency" }] : []));
799
- this.vatMode = computed(() => this.invoice()?.vatMode ?? InvoiceVatMode.EXCLUSIVE, ...(ngDevMode ? [{ debugName: "vatMode" }] : []));
796
+ this.lines = computed(() => this.invoice()?.lines ?? [], ...(ngDevMode ? [{ debugName: "lines" }] : /* istanbul ignore next */ []));
797
+ this.currency = computed(() => this.invoice()?.currency ?? 'GBP', ...(ngDevMode ? [{ debugName: "currency" }] : /* istanbul ignore next */ []));
798
+ this.vatMode = computed(() => this.invoice()?.vatMode ?? InvoiceVatMode.EXCLUSIVE, ...(ngDevMode ? [{ debugName: "vatMode" }] : /* istanbul ignore next */ []));
800
799
  this.totals = computed(() => {
801
800
  const inv = this.invoice();
802
801
  if (!inv) {
@@ -807,7 +806,7 @@ class InvoiceStore {
807
806
  const vatTotal = lines.reduce((s, l) => s + (l.vatAmount ?? 0), 0);
808
807
  const total = lines.reduce((s, l) => s + (l.lineTotal ?? 0), 0);
809
808
  return { subtotal, vatTotal, total };
810
- }, ...(ngDevMode ? [{ debugName: "totals" }] : []));
809
+ }, ...(ngDevMode ? [{ debugName: "totals" }] : /* istanbul ignore next */ []));
811
810
  /** 🔴 DIRTY FLAG */
812
811
  this.dirty = computed(() => {
813
812
  const a = this.invoice();
@@ -815,7 +814,7 @@ class InvoiceStore {
815
814
  if (!a || !b)
816
815
  return false;
817
816
  return JSON.stringify(a) !== JSON.stringify(b);
818
- }, ...(ngDevMode ? [{ debugName: "dirty" }] : []));
817
+ }, ...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
819
818
  }
820
819
  // --- API: load / refresh ---
821
820
  load(id) {
@@ -825,7 +824,7 @@ class InvoiceStore {
825
824
  // ✅ Adapt to your actual API signature:
826
825
  // e.g. this.api.get(id) or this.api.getInvoice(id)
827
826
  this.api
828
- .get(id)
827
+ .getInvoice(id)
829
828
  .pipe(finalize$1(() => this.status.set('idle')))
830
829
  .subscribe({
831
830
  next: (inv) => {
@@ -1043,19 +1042,19 @@ class InvoiceStore {
1043
1042
  errMsg(e) {
1044
1043
  return e?.error?.message || e?.message || 'Request failed';
1045
1044
  }
1046
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1047
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceStore, providedIn: 'root' }); }
1045
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1046
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceStore, providedIn: 'root' }); }
1048
1047
  }
1049
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceStore, decorators: [{
1048
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceStore, decorators: [{
1050
1049
  type: Injectable,
1051
1050
  args: [{ providedIn: 'root' }]
1052
1051
  }] });
1053
1052
 
1054
1053
  class InvoiceLinePropertySelector {
1055
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceLinePropertySelector, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1056
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.1", type: InvoiceLinePropertySelector, isStandalone: true, selector: "rolatech-invoice-line-property-selector", ngImport: i0, template: "<p>invoice-line-property-selector works!</p>\n", styles: [""] }); }
1054
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceLinePropertySelector, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1055
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: InvoiceLinePropertySelector, isStandalone: true, selector: "rolatech-invoice-line-property-selector", ngImport: i0, template: "<p>invoice-line-property-selector works!</p>\n", styles: [""] }); }
1057
1056
  }
1058
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceLinePropertySelector, decorators: [{
1057
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceLinePropertySelector, decorators: [{
1059
1058
  type: Component,
1060
1059
  args: [{ selector: 'rolatech-invoice-line-property-selector', imports: [], template: "<p>invoice-line-property-selector works!</p>\n" }]
1061
1060
  }] });
@@ -1066,7 +1065,7 @@ class InvoiceManageLine {
1066
1065
  this.dialog = inject(MatDialog);
1067
1066
  this.lines = this.store.lines;
1068
1067
  this.vatMode = this.store.vatMode;
1069
- this.editMode = signal(false, ...(ngDevMode ? [{ debugName: "editMode" }] : []));
1068
+ this.editMode = signal(false, ...(ngDevMode ? [{ debugName: "editMode" }] : /* istanbul ignore next */ []));
1070
1069
  this.openingForLine = new Set();
1071
1070
  this.isVatExclusive = () => this.vatMode() === 'EXCLUSIVE';
1072
1071
  }
@@ -1137,10 +1136,10 @@ class InvoiceManageLine {
1137
1136
  });
1138
1137
  }
1139
1138
  saveLines() { }
1140
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageLine, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1141
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceManageLine, isStandalone: true, selector: "rolatech-invoice-manage-line", ngImport: i0, template: "<!-- invoice-lines.html -->\n<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <!-- Header -->\n <div class=\"flex items-center justify-between\">\n <h2 class=\"text-sm font-semibold\">Invoice lines</h2>\n\n <div class=\"flex items-center gap-2\">\n <button mat-icon-button type=\"button\" aria-label=\"Toggle edit\" (click)=\"toggleEdit()\">\n <mat-icon> {{ editMode() ? 'done' : 'edit' }} </mat-icon>\n </button>\n <button mat-stroked-button type=\"button\" [disabled]=\"store.dirty() || store.status() === 'saving'\" (click)=\"saveLines()\">\n @if (store.status() === 'saving') { Saving\u2026 } @else { Save lines }\n </button>\n </div>\n </div>\n\n <!-- Column labels (desktop only) -->\n <div class=\"hidden lg:grid grid-cols-12 gap-2 text-sm font-medium px-2 text-(--rt-text-secondary)\">\n <!-- Drag column -->\n @if (editMode()) {\n <div class=\"col-span-1\"></div>\n }\n\n <!-- Type -->\n <div [class]=\"editMode() ? 'col-span-3' : 'col-span-3'\">Type</div>\n\n <!-- Description (take extra space when not editing) -->\n <div [class]=\"editMode() ? 'col-span-4' : 'col-span-5'\">Title</div>\n\n <!-- Unit Price -->\n <div class=\"col-span-2 text-right\">Unit Price</div>\n\n <!-- Tax % (optional) -->\n @if (!isVatExclusive()) {\n <div class=\"col-span-1 text-right\">Tax %</div>\n }\n\n <!-- Amount (take extra space when not editing) -->\n <div [class]=\"editMode() ? 'col-span-1' : 'col-span-2'\" class=\"text-right\">Amount</div>\n\n <!-- Delete column -->\n @if (editMode()) {\n <div class=\"col-span-1\"></div>\n }\n </div>\n\n <!-- invoice-lines.html (rows section) -->\n\n <div cdkDropList (cdkDropListDropped)=\"drop($event)\" [cdkDropListDisabled]=\"!editMode()\" class=\"space-y-2\">\n @if (lines().length > 0) { @for (line of lines(); track line.id; let i = $index) {\n\n <div\n cdkDrag\n class=\"grid grid-cols-12 gap-2 items-start rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-2 hover:bg-(--rt-raised-background)\"\n [class.opacity-70]=\"!editMode()\"\n >\n <!-- Drag handle column (only in edit mode) -->\n @if (editMode()) {\n <div class=\"col-span-1 flex items-center justify-center\">\n <button mat-icon-button type=\"button\" cdkDragHandle aria-label=\"Reorder line\" (click)=\"$event.stopPropagation()\">\n <mat-icon>drag_indicator</mat-icon>\n </button>\n </div>\n }\n\n <!-- Type -->\n <div class=\"col-span-12 lg:col-span-3\">\n <rolatech-enum-select\n [resource]=\"'billing'\"\n [enumName]=\"'InvoiceLineType'\"\n [label]=\"'Line type'\"\n [placeholder]=\"'Select\u2026'\"\n [value]=\"line.type\"\n (valueChange)=\"editMode() && update(line.id!, { type: $event })\"\n ></rolatech-enum-select>\n </div>\n\n <!-- Title (expands when NOT editMode) -->\n <div [class]=\"editMode() ? 'col-span-12 lg:col-span-4' : 'col-span-12 lg:col-span-5'\">\n <mat-form-field appearance=\"fill\" class=\"w-full\" subscriptSizing=\"dynamic\">\n <mat-label>Title</mat-label>\n <input\n matInput\n placeholder=\"e.g. Photo editing package\"\n [readonly]=\"!editMode()\"\n [readonly]=\"isPropertyLine(line.type)\"\n (focus)=\"onTitleFocus(line)\"\n (click)=\"onTitleFocus(line)\"\n (keydown)=\"onTitleKeydown($event, line)\"\n [value]=\"line.title\"\n (input)=\"editMode() && update(line.id!, { title: $any($event.target).value })\"\n />\n </mat-form-field>\n </div>\n\n <!-- Unit Price -->\n <div class=\"col-span-6 lg:col-span-2\">\n <mat-form-field appearance=\"fill\" class=\"w-full\" subscriptSizing=\"dynamic\">\n <mat-label>Unit</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n class=\"text-right\"\n [readonly]=\"!editMode()\"\n [value]=\"line.unitPrice\"\n (input)=\"editMode() && update(line.id!, { unitPrice: +$any($event.target).value })\"\n />\n </mat-form-field>\n </div>\n\n <!-- Tax % (optional, hidden if VAT exclusive) -->\n @if (!isVatExclusive()) {\n <div class=\"col-span-6 lg:col-span-1\">\n <mat-form-field appearance=\"fill\" class=\"w-full\" subscriptSizing=\"dynamic\">\n <mat-label>Tax %</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n class=\"text-right\"\n [readonly]=\"!editMode()\"\n [value]=\"line.vatRate\"\n (input)=\"editMode() && update(line.id!, { vatRate: +$any($event.target).value })\"\n />\n </mat-form-field>\n </div>\n }\n\n <!-- Amount (expands when NOT editMode) -->\n <div\n [class]=\"editMode() ? 'col-span-6 lg:col-span-1' : 'col-span-6 lg:col-span-2'\"\n class=\"flex items-center justify-end px-1 lg:pt-3\"\n >\n <div class=\"text-right font-semibold text-(--rt-text-secondary)\">{{ line.lineTotal | price }}</div>\n </div>\n\n <!-- Delete column (only in edit mode) -->\n @if (editMode()) {\n <div class=\"col-span-6 lg:col-span-1 flex items-center justify-end lg:pt-1\">\n <button mat-icon-button color=\"warn\" type=\"button\" aria-label=\"Delete line\" (click)=\"remove(line.id!)\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n }\n </div>\n } } @else {\n <div class=\"py-8 text-center text-sm text-(--rt-text-secondary)\">No invoice lines</div>\n }\n </div>\n\n <!-- Footer -->\n <div>\n <button mat-stroked-button (click)=\"add()\">Add item</button>\n </div>\n</div>\n", styles: [".cdk-drag-preview{box-shadow:0 10px 20px #00000026;border-radius:12px}.cdk-drag-placeholder{opacity:.3}\n"], dependencies: [{ kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$3.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$3.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i1$3.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: EnumSelect, selector: "rolatech-enum-select", inputs: ["resource", "enumName", "label", "placeholder", "disabled", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: PricePipe, name: "price" }], encapsulation: i0.ViewEncapsulation.None }); }
1139
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageLine, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1140
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceManageLine, isStandalone: true, selector: "rolatech-invoice-manage-line", ngImport: i0, template: "<!-- invoice-lines.html -->\n<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <!-- Header -->\n <div class=\"flex items-center justify-between\">\n <h2 class=\"text-sm font-semibold\">Invoice lines</h2>\n\n <div class=\"flex items-center gap-2\">\n <button mat-icon-button type=\"button\" aria-label=\"Toggle edit\" (click)=\"toggleEdit()\">\n <mat-icon> {{ editMode() ? 'done' : 'edit' }} </mat-icon>\n </button>\n <button mat-stroked-button type=\"button\" [disabled]=\"store.dirty() || store.status() === 'saving'\" (click)=\"saveLines()\">\n @if (store.status() === 'saving') { Saving\u2026 } @else { Save lines }\n </button>\n </div>\n </div>\n\n <!-- Column labels (desktop only) -->\n <div class=\"hidden lg:grid grid-cols-12 gap-2 text-sm font-medium px-2 text-(--rt-text-secondary)\">\n <!-- Drag column -->\n @if (editMode()) {\n <div class=\"col-span-1\"></div>\n }\n\n <!-- Type -->\n <div [class]=\"editMode() ? 'col-span-3' : 'col-span-3'\">Type</div>\n\n <!-- Description (take extra space when not editing) -->\n <div [class]=\"editMode() ? 'col-span-4' : 'col-span-5'\">Title</div>\n\n <!-- Unit Price -->\n <div class=\"col-span-2 text-right\">Unit Price</div>\n\n <!-- Tax % (optional) -->\n @if (!isVatExclusive()) {\n <div class=\"col-span-1 text-right\">Tax %</div>\n }\n\n <!-- Amount (take extra space when not editing) -->\n <div [class]=\"editMode() ? 'col-span-1' : 'col-span-2'\" class=\"text-right\">Amount</div>\n\n <!-- Delete column -->\n @if (editMode()) {\n <div class=\"col-span-1\"></div>\n }\n </div>\n\n <!-- invoice-lines.html (rows section) -->\n\n <div cdkDropList (cdkDropListDropped)=\"drop($event)\" [cdkDropListDisabled]=\"!editMode()\" class=\"space-y-2\">\n @if (lines().length > 0) { @for (line of lines(); track line.id; let i = $index) {\n\n <div\n cdkDrag\n class=\"grid grid-cols-12 gap-2 items-start rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-2 hover:bg-(--rt-raised-background)\"\n [class.opacity-70]=\"!editMode()\"\n >\n <!-- Drag handle column (only in edit mode) -->\n @if (editMode()) {\n <div class=\"col-span-1 flex items-center justify-center\">\n <button mat-icon-button type=\"button\" cdkDragHandle aria-label=\"Reorder line\" (click)=\"$event.stopPropagation()\">\n <mat-icon>drag_indicator</mat-icon>\n </button>\n </div>\n }\n\n <!-- Type -->\n <div class=\"col-span-12 lg:col-span-3\">\n <rolatech-enum-select\n [resource]=\"'billing'\"\n [enumName]=\"'InvoiceLineType'\"\n [label]=\"'Line type'\"\n [placeholder]=\"'Select\u2026'\"\n [value]=\"line.type\"\n (valueChange)=\"editMode() && update(line.id!, { type: $event })\"\n ></rolatech-enum-select>\n </div>\n\n <!-- Title (expands when NOT editMode) -->\n <div [class]=\"editMode() ? 'col-span-12 lg:col-span-4' : 'col-span-12 lg:col-span-5'\">\n <mat-form-field appearance=\"fill\" class=\"w-full\" subscriptSizing=\"dynamic\">\n <mat-label>Title</mat-label>\n <input\n matInput\n placeholder=\"e.g. Photo editing package\"\n [readonly]=\"!editMode()\"\n [readonly]=\"isPropertyLine(line.type)\"\n (focus)=\"onTitleFocus(line)\"\n (click)=\"onTitleFocus(line)\"\n (keydown)=\"onTitleKeydown($event, line)\"\n [value]=\"line.title\"\n (input)=\"editMode() && update(line.id!, { title: $any($event.target).value })\"\n />\n </mat-form-field>\n </div>\n\n <!-- Unit Price -->\n <div class=\"col-span-6 lg:col-span-2\">\n <mat-form-field appearance=\"fill\" class=\"w-full\" subscriptSizing=\"dynamic\">\n <mat-label>Unit</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n class=\"text-right\"\n [readonly]=\"!editMode()\"\n [value]=\"line.unitPrice\"\n (input)=\"editMode() && update(line.id!, { unitPrice: +$any($event.target).value })\"\n />\n </mat-form-field>\n </div>\n\n <!-- Tax % (optional, hidden if VAT exclusive) -->\n @if (!isVatExclusive()) {\n <div class=\"col-span-6 lg:col-span-1\">\n <mat-form-field appearance=\"fill\" class=\"w-full\" subscriptSizing=\"dynamic\">\n <mat-label>Tax %</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n class=\"text-right\"\n [readonly]=\"!editMode()\"\n [value]=\"line.vatRate\"\n (input)=\"editMode() && update(line.id!, { vatRate: +$any($event.target).value })\"\n />\n </mat-form-field>\n </div>\n }\n\n <!-- Amount (expands when NOT editMode) -->\n <div\n [class]=\"editMode() ? 'col-span-6 lg:col-span-1' : 'col-span-6 lg:col-span-2'\"\n class=\"flex items-center justify-end px-1 lg:pt-3\"\n >\n <div class=\"text-right font-semibold text-(--rt-text-secondary)\">{{ line.lineTotal | price }}</div>\n </div>\n\n <!-- Delete column (only in edit mode) -->\n @if (editMode()) {\n <div class=\"col-span-6 lg:col-span-1 flex items-center justify-end lg:pt-1\">\n <button mat-icon-button color=\"warn\" type=\"button\" aria-label=\"Delete line\" (click)=\"remove(line.id!)\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n }\n </div>\n } } @else {\n <div class=\"py-8 text-center text-sm text-(--rt-text-secondary)\">No invoice lines</div>\n }\n </div>\n\n <!-- Footer -->\n <div>\n <button mat-stroked-button (click)=\"add()\">Add item</button>\n </div>\n</div>\n", styles: [".cdk-drag-preview{box-shadow:0 10px 20px #00000026;border-radius:12px}.cdk-drag-placeholder{opacity:.3}\n"], dependencies: [{ kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$3.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$3.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i1$3.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: EnumSelect, selector: "rolatech-enum-select", inputs: ["resource", "enumName", "label", "placeholder", "disabled", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: PricePipe, name: "price" }], encapsulation: i0.ViewEncapsulation.None }); }
1142
1141
  }
1143
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageLine, decorators: [{
1142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageLine, decorators: [{
1144
1143
  type: Component,
1145
1144
  args: [{ selector: 'rolatech-invoice-manage-line', imports: [DragDropModule, MatButtonModule, MatIcon, MatFormFieldModule, MatInputModule, PricePipe, EnumSelect], encapsulation: ViewEncapsulation.None, template: "<!-- invoice-lines.html -->\n<div class=\"rounded-xl border border-(--rt-border-color) p-4 grid space-y-3\">\n <!-- Header -->\n <div class=\"flex items-center justify-between\">\n <h2 class=\"text-sm font-semibold\">Invoice lines</h2>\n\n <div class=\"flex items-center gap-2\">\n <button mat-icon-button type=\"button\" aria-label=\"Toggle edit\" (click)=\"toggleEdit()\">\n <mat-icon> {{ editMode() ? 'done' : 'edit' }} </mat-icon>\n </button>\n <button mat-stroked-button type=\"button\" [disabled]=\"store.dirty() || store.status() === 'saving'\" (click)=\"saveLines()\">\n @if (store.status() === 'saving') { Saving\u2026 } @else { Save lines }\n </button>\n </div>\n </div>\n\n <!-- Column labels (desktop only) -->\n <div class=\"hidden lg:grid grid-cols-12 gap-2 text-sm font-medium px-2 text-(--rt-text-secondary)\">\n <!-- Drag column -->\n @if (editMode()) {\n <div class=\"col-span-1\"></div>\n }\n\n <!-- Type -->\n <div [class]=\"editMode() ? 'col-span-3' : 'col-span-3'\">Type</div>\n\n <!-- Description (take extra space when not editing) -->\n <div [class]=\"editMode() ? 'col-span-4' : 'col-span-5'\">Title</div>\n\n <!-- Unit Price -->\n <div class=\"col-span-2 text-right\">Unit Price</div>\n\n <!-- Tax % (optional) -->\n @if (!isVatExclusive()) {\n <div class=\"col-span-1 text-right\">Tax %</div>\n }\n\n <!-- Amount (take extra space when not editing) -->\n <div [class]=\"editMode() ? 'col-span-1' : 'col-span-2'\" class=\"text-right\">Amount</div>\n\n <!-- Delete column -->\n @if (editMode()) {\n <div class=\"col-span-1\"></div>\n }\n </div>\n\n <!-- invoice-lines.html (rows section) -->\n\n <div cdkDropList (cdkDropListDropped)=\"drop($event)\" [cdkDropListDisabled]=\"!editMode()\" class=\"space-y-2\">\n @if (lines().length > 0) { @for (line of lines(); track line.id; let i = $index) {\n\n <div\n cdkDrag\n class=\"grid grid-cols-12 gap-2 items-start rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-2 hover:bg-(--rt-raised-background)\"\n [class.opacity-70]=\"!editMode()\"\n >\n <!-- Drag handle column (only in edit mode) -->\n @if (editMode()) {\n <div class=\"col-span-1 flex items-center justify-center\">\n <button mat-icon-button type=\"button\" cdkDragHandle aria-label=\"Reorder line\" (click)=\"$event.stopPropagation()\">\n <mat-icon>drag_indicator</mat-icon>\n </button>\n </div>\n }\n\n <!-- Type -->\n <div class=\"col-span-12 lg:col-span-3\">\n <rolatech-enum-select\n [resource]=\"'billing'\"\n [enumName]=\"'InvoiceLineType'\"\n [label]=\"'Line type'\"\n [placeholder]=\"'Select\u2026'\"\n [value]=\"line.type\"\n (valueChange)=\"editMode() && update(line.id!, { type: $event })\"\n ></rolatech-enum-select>\n </div>\n\n <!-- Title (expands when NOT editMode) -->\n <div [class]=\"editMode() ? 'col-span-12 lg:col-span-4' : 'col-span-12 lg:col-span-5'\">\n <mat-form-field appearance=\"fill\" class=\"w-full\" subscriptSizing=\"dynamic\">\n <mat-label>Title</mat-label>\n <input\n matInput\n placeholder=\"e.g. Photo editing package\"\n [readonly]=\"!editMode()\"\n [readonly]=\"isPropertyLine(line.type)\"\n (focus)=\"onTitleFocus(line)\"\n (click)=\"onTitleFocus(line)\"\n (keydown)=\"onTitleKeydown($event, line)\"\n [value]=\"line.title\"\n (input)=\"editMode() && update(line.id!, { title: $any($event.target).value })\"\n />\n </mat-form-field>\n </div>\n\n <!-- Unit Price -->\n <div class=\"col-span-6 lg:col-span-2\">\n <mat-form-field appearance=\"fill\" class=\"w-full\" subscriptSizing=\"dynamic\">\n <mat-label>Unit</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n class=\"text-right\"\n [readonly]=\"!editMode()\"\n [value]=\"line.unitPrice\"\n (input)=\"editMode() && update(line.id!, { unitPrice: +$any($event.target).value })\"\n />\n </mat-form-field>\n </div>\n\n <!-- Tax % (optional, hidden if VAT exclusive) -->\n @if (!isVatExclusive()) {\n <div class=\"col-span-6 lg:col-span-1\">\n <mat-form-field appearance=\"fill\" class=\"w-full\" subscriptSizing=\"dynamic\">\n <mat-label>Tax %</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n class=\"text-right\"\n [readonly]=\"!editMode()\"\n [value]=\"line.vatRate\"\n (input)=\"editMode() && update(line.id!, { vatRate: +$any($event.target).value })\"\n />\n </mat-form-field>\n </div>\n }\n\n <!-- Amount (expands when NOT editMode) -->\n <div\n [class]=\"editMode() ? 'col-span-6 lg:col-span-1' : 'col-span-6 lg:col-span-2'\"\n class=\"flex items-center justify-end px-1 lg:pt-3\"\n >\n <div class=\"text-right font-semibold text-(--rt-text-secondary)\">{{ line.lineTotal | price }}</div>\n </div>\n\n <!-- Delete column (only in edit mode) -->\n @if (editMode()) {\n <div class=\"col-span-6 lg:col-span-1 flex items-center justify-end lg:pt-1\">\n <button mat-icon-button color=\"warn\" type=\"button\" aria-label=\"Delete line\" (click)=\"remove(line.id!)\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n }\n </div>\n } } @else {\n <div class=\"py-8 text-center text-sm text-(--rt-text-secondary)\">No invoice lines</div>\n }\n </div>\n\n <!-- Footer -->\n <div>\n <button mat-stroked-button (click)=\"add()\">Add item</button>\n </div>\n</div>\n", styles: [".cdk-drag-preview{box-shadow:0 10px 20px #00000026;border-radius:12px}.cdk-drag-placeholder{opacity:.3}\n"] }]
1146
1145
  }] });
@@ -1154,8 +1153,8 @@ class InvoiceManageDetail extends BaseComponent {
1154
1153
  this.invoice = this.store.invoice;
1155
1154
  this.status = InvoiceStatus;
1156
1155
  // convenience derived values for template
1157
- this.loading = computed(() => this.store.status() === 'loading', ...(ngDevMode ? [{ debugName: "loading" }] : []));
1158
- this.pdfUrl = computed(() => this.store.invoice()?.pdfUrl ?? '', ...(ngDevMode ? [{ debugName: "pdfUrl" }] : []));
1156
+ this.loading = computed(() => this.store.status() === 'loading', ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
1157
+ this.pdfUrl = computed(() => this.store.invoice()?.pdfUrl ?? '', ...(ngDevMode ? [{ debugName: "pdfUrl" }] : /* istanbul ignore next */ []));
1159
1158
  }
1160
1159
  ngOnInit() {
1161
1160
  this.store.load(this.id);
@@ -1254,19 +1253,19 @@ class InvoiceManageDetail extends BaseComponent {
1254
1253
  }
1255
1254
  });
1256
1255
  }
1257
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageDetail, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1258
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: InvoiceManageDetail, isStandalone: true, selector: "rolatech-invoice-manage-detail", usesInheritance: true, ngImport: i0, template: "@if (store.status() === 'loading') {\n<div class=\"flex justify-center py-16\">Loading invoice\u2026</div>\n} @else if (!store.invoice()) {\n<div class=\"flex justify-center py-16\">Invoice not found.</div>\n} @else { @if (store.invoice(); as inv) {\n\n<!-- Sticky header -->\n<div class=\"sticky top-0 z-10 border-b border-(--rt-border-color) bg-(--rt-background)\">\n <div class=\"px-4 py-3 flex items-start justify-between gap-4\">\n <div class=\"min-w-0\">\n <div class=\"flex items-center gap-2\">\n <h1 class=\"text-lg font-semibold truncate\">Invoice {{ inv.invoiceNumber || inv.id }}</h1>\n\n <span class=\"px-2 py-0.5 rounded-full text-xs font-semibold\" [class]=\"statusBadgeClass(inv.status)\">\n {{ inv.status }}\n </span>\n\n @if (store.dirty() ) {\n <span class=\"text-xs text-(--rt-text-secondary)\">\u2022 Unsaved changes</span>\n }\n </div>\n\n <div class=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-(--rt-text-secondary)\">\n <span class=\"truncate\"> {{ inv.fullName }} \u2022 {{ inv.email }} </span>\n <span>Created {{ inv.createdAt | date:'dd/MM/yyyy':'Europe/London' }}</span>\n @if (inv.dueAt) { <span>Due {{ inv.dueAt | date:'dd/MM/yyyy':'Europe/London' }}</span> }\n </div>\n </div>\n\n <!-- Desktop actions -->\n\n <div class=\"hidden lg:flex items-center gap-2 shrink-0\">\n @if (inv.pdfUrl) {\n <button mat-stroked-button type=\"button\" (click)=\"openPdf()\">Preview PDF</button>\n } @if (inv.status.toString() === 'ISSUED') {\n <button mat-flat-button type=\"button\" (click)=\"sendEmail()\">Send email</button>\n } @if (inv.status.toString() !== 'SENT' && inv.status.toString() !== 'PAID') {\n <button mat-flat-button (click)=\"edit()\">Edit</button>\n } @if (inv.status.toString() === 'SENT') {\n <button mat-flat-button type=\"button\" (click)=\"sendEmail()\">Resend</button>\n }\n </div>\n\n <!-- Mobile actions -->\n <div class=\"lg:hidden shrink-0\">\n <button mat-icon-button type=\"button\" [matMenuTriggerFor]=\"moreMenu\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </div>\n </div>\n</div>\n\n<!-- Body -->\n<div class=\"p-4 space-y-4\">\n <div class=\"grid grid-cols-1 lg:grid-cols-3 gap-4\">\n <!-- Left column -->\n <div class=\"grid lg:col-span-2 space-y-4\">\n <!-- Customer -->\n <div class=\"rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-4\">\n <div class=\"flex items-center justify-between\">\n <div>\n <div class=\"text-sm font-semibold\">Customer</div>\n <div class=\"text-sm text-(--rt-text-secondary)\">{{ inv.fullName }} \u2022 {{ inv.email }}</div>\n </div>\n </div>\n\n <div class=\"mt-3 grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm\">\n <div>\n <div class=\"text-xs text-(--rt-text-secondary)\">Phone</div>\n <div class=\"font-medium\">{{ inv.phone || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-(--rt-text-secondary)\">Currency</div>\n <div class=\"font-medium\">{{ inv.currency }}</div>\n </div>\n </div>\n </div>\n\n <!-- Lines -->\n\n @if (inv.status.toString() !== 'SENT' && inv.status.toString() !== 'PAID') {\n <rolatech-invoice-manage-line></rolatech-invoice-manage-line>\n } @else {\n <rolatech-invoice-lines [lines]=\"store.lines()\"></rolatech-invoice-lines>\n }\n\n <!-- Notes (optional) -->\n @if (inv.note) {\n <div class=\"rounded-xl border border-(--rt-border-color) p-4\">\n <div class=\"text-sm font-semibold\">Notes</div>\n <div class=\"mt-2 text-sm text-(--rt-text-secondary) whitespace-pre-wrap\">{{ inv.note }}</div>\n </div>\n }\n </div>\n\n <!-- Right rail -->\n <div class=\"space-y-4\">\n <div class=\"rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-4\">\n <div class=\"text-sm font-semibold\">Summary</div>\n\n @if (store.totals(); as t) {\n <div class=\"mt-3 space-y-2 text-sm\">\n <div class=\"flex justify-between\">\n <span class=\"text-(--rt-text-secondary)\">Subtotal</span>\n <span class=\"font-medium\">{{ t.subtotal | price }}</span>\n </div>\n\n <div class=\"flex justify-between\">\n <span class=\"text-(--rt-text-secondary)\">VAT</span>\n <span class=\"font-medium\">{{ t.vatTotal | price }}</span>\n </div>\n\n @if (inv.holdingDepositApplied) {\n <div class=\"flex justify-between\">\n <span class=\"text-(--rt-text-secondary)\">Credit</span>\n <span class=\"font-medium\">-{{ inv.holdingDepositApplied | price }}</span>\n </div>\n }\n\n <div class=\"pt-2 mt-2 border-t border-(--rt-border-color) flex justify-between text-base\">\n <span class=\"font-semibold\">Total</span>\n <span class=\"font-semibold\">{{ t.total | price }}</span>\n </div>\n </div>\n }\n </div>\n <div class=\"rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-4\">\n <div class=\"text-sm font-semibold\">Payment</div>\n <div class=\"mt-2 text-sm text-(--rt-text-secondary)\">\n Status:\n <span class=\"font-medium text-(--rt-text-primary)\">{{ inv.status.toString() === 'PAID' ? 'Paid': 'Unpaid' }}</span>\n </div>\n @if (inv.paidAt) {\n <div class=\"mt-1 text-sm text-(--rt-text-secondary)\">\n Paid: <span class=\"font-medium text-(--rt-text-primary)\">{{ inv.paidAt | date:'dd/MM/yyyy':'Europe/London' }}</span>\n </div>\n }\n </div>\n </div>\n </div>\n</div>\n\n<mat-menu #moreMenu=\"matMenu\" xPosition=\"after\" class=\"divide-y divide-light-900\">\n @if (inv.pdfUrl) {\n <button mat-menu-item type=\"button\" (click)=\"openPdf()\">Preview PDF</button>\n } @if (inv.status.toString() === 'ISSUED') {\n <button mat-menu-item type=\"button\" (click)=\"sendEmail()\">Send email</button>\n } @if (inv.status.toString() !== 'SENT' && inv.status.toString() !== 'PAID') {\n <button mat-menu-item type=\"button\" (click)=\"edit()\">Edit</button>\n\n }\n</mat-menu>\n} }\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MaterialModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: InvoiceLines, selector: "rolatech-invoice-lines", inputs: ["lines"] }, { kind: "component", type: InvoiceManageLine, selector: "rolatech-invoice-manage-line" }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
1256
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageDetail, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1257
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: InvoiceManageDetail, isStandalone: true, selector: "rolatech-invoice-manage-detail", usesInheritance: true, ngImport: i0, template: "@if (store.status() === 'loading') {\n<div class=\"flex justify-center py-16\">Loading invoice\u2026</div>\n} @else if (!store.invoice()) {\n<div class=\"flex justify-center py-16\">Invoice not found.</div>\n} @else { @if (store.invoice(); as inv) {\n\n<!-- Sticky header -->\n<div class=\"sticky top-0 z-10 border-b border-(--rt-border-color) bg-(--rt-background)\">\n <div class=\"px-4 py-3 flex items-start justify-between gap-4\">\n <div class=\"min-w-0\">\n <div class=\"flex items-center gap-2\">\n <h1 class=\"text-lg font-semibold truncate\">Invoice {{ inv.invoiceNumber || inv.id }}</h1>\n\n <span class=\"px-2 py-0.5 rounded-full text-xs font-semibold\" [class]=\"statusBadgeClass(inv.status)\">\n {{ inv.status }}\n </span>\n\n @if (store.dirty() ) {\n <span class=\"text-xs text-(--rt-text-secondary)\">\u2022 Unsaved changes</span>\n }\n </div>\n\n <div class=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-(--rt-text-secondary)\">\n <span class=\"truncate\"> {{ inv.fullName }} \u2022 {{ inv.email }} </span>\n <span>Created {{ inv.createdAt | date:'dd/MM/yyyy':'Europe/London' }}</span>\n @if (inv.dueAt) { <span>Due {{ inv.dueAt | date:'dd/MM/yyyy':'Europe/London' }}</span> }\n </div>\n </div>\n\n <!-- Desktop actions -->\n\n <div class=\"hidden lg:flex items-center gap-2 shrink-0\">\n @if (inv.pdfUrl) {\n <button mat-stroked-button type=\"button\" (click)=\"openPdf()\">Preview PDF</button>\n } @if (inv.status.toString() === 'ISSUED') {\n <button mat-flat-button type=\"button\" (click)=\"sendEmail()\">Send email</button>\n } @if (inv.status.toString() !== 'SENT' && inv.status.toString() !== 'PAID') {\n <button mat-flat-button (click)=\"edit()\">Edit</button>\n } @if (inv.status.toString() === 'SENT') {\n <button mat-flat-button type=\"button\" (click)=\"sendEmail()\">Resend</button>\n }\n </div>\n\n <!-- Mobile actions -->\n <div class=\"lg:hidden shrink-0\">\n <button mat-icon-button type=\"button\" [matMenuTriggerFor]=\"moreMenu\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </div>\n </div>\n</div>\n\n<!-- Body -->\n<div class=\"p-4 space-y-4\">\n <div class=\"grid grid-cols-1 lg:grid-cols-3 gap-4\">\n <!-- Left column -->\n <div class=\"grid lg:col-span-2 space-y-4\">\n <!-- Customer -->\n <div class=\"rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-4\">\n <div class=\"flex items-center justify-between\">\n <div>\n <div class=\"text-sm font-semibold\">Customer</div>\n <div class=\"text-sm text-(--rt-text-secondary)\">{{ inv.fullName }} \u2022 {{ inv.email }}</div>\n </div>\n </div>\n\n <div class=\"mt-3 grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm\">\n <div>\n <div class=\"text-xs text-(--rt-text-secondary)\">Phone</div>\n <div class=\"font-medium\">{{ inv.phone || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-(--rt-text-secondary)\">Currency</div>\n <div class=\"font-medium\">{{ inv.currency }}</div>\n </div>\n </div>\n </div>\n\n <!-- Lines -->\n\n @if (inv.status.toString() !== 'SENT' && inv.status.toString() !== 'PAID') {\n <rolatech-invoice-manage-line></rolatech-invoice-manage-line>\n } @else {\n <rolatech-invoice-lines [lines]=\"store.lines()\"></rolatech-invoice-lines>\n }\n\n <!-- Notes (optional) -->\n @if (inv.note) {\n <div class=\"rounded-xl border border-(--rt-border-color) p-4\">\n <div class=\"text-sm font-semibold\">Notes</div>\n <div class=\"mt-2 text-sm text-(--rt-text-secondary) whitespace-pre-wrap\">{{ inv.note }}</div>\n </div>\n }\n </div>\n\n <!-- Right rail -->\n <div class=\"space-y-4\">\n <div class=\"rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-4\">\n <div class=\"text-sm font-semibold\">Summary</div>\n\n @if (store.totals(); as t) {\n <div class=\"mt-3 space-y-2 text-sm\">\n <div class=\"flex justify-between\">\n <span class=\"text-(--rt-text-secondary)\">Subtotal</span>\n <span class=\"font-medium\">{{ t.subtotal | price }}</span>\n </div>\n\n <div class=\"flex justify-between\">\n <span class=\"text-(--rt-text-secondary)\">VAT</span>\n <span class=\"font-medium\">{{ t.vatTotal | price }}</span>\n </div>\n\n @if (inv.holdingDepositApplied) {\n <div class=\"flex justify-between\">\n <span class=\"text-(--rt-text-secondary)\">Credit</span>\n <span class=\"font-medium\">-{{ inv.holdingDepositApplied | price }}</span>\n </div>\n }\n\n <div class=\"pt-2 mt-2 border-t border-(--rt-border-color) flex justify-between text-base\">\n <span class=\"font-semibold\">Total</span>\n <span class=\"font-semibold\">{{ t.total | price }}</span>\n </div>\n </div>\n }\n </div>\n <div class=\"rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-4\">\n <div class=\"text-sm font-semibold\">Payment</div>\n <div class=\"mt-2 text-sm text-(--rt-text-secondary)\">\n Status:\n <span class=\"font-medium text-(--rt-text-primary)\">{{ inv.status.toString() === 'PAID' ? 'Paid': 'Unpaid' }}</span>\n </div>\n @if (inv.paidAt) {\n <div class=\"mt-1 text-sm text-(--rt-text-secondary)\">\n Paid: <span class=\"font-medium text-(--rt-text-primary)\">{{ inv.paidAt | date:'dd/MM/yyyy':'Europe/London' }}</span>\n </div>\n }\n </div>\n </div>\n </div>\n</div>\n\n<mat-menu #moreMenu=\"matMenu\" xPosition=\"after\" class=\"divide-y divide-light-900\">\n @if (inv.pdfUrl) {\n <button mat-menu-item type=\"button\" (click)=\"openPdf()\">Preview PDF</button>\n } @if (inv.status.toString() === 'ISSUED') {\n <button mat-menu-item type=\"button\" (click)=\"sendEmail()\">Send email</button>\n } @if (inv.status.toString() !== 'SENT' && inv.status.toString() !== 'PAID') {\n <button mat-menu-item type=\"button\" (click)=\"edit()\">Edit</button>\n\n }\n</mat-menu>\n} }\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MaterialModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: InvoiceLines, selector: "rolatech-invoice-lines", inputs: ["lines"] }, { kind: "component", type: InvoiceManageLine, selector: "rolatech-invoice-manage-line" }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
1259
1258
  }
1260
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageDetail, decorators: [{
1259
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageDetail, decorators: [{
1261
1260
  type: Component,
1262
1261
  args: [{ selector: 'rolatech-invoice-manage-detail', standalone: true, imports: [CommonModule, MaterialModule, MatMenuModule, InvoiceLines, InvoiceManageLine, PricePipe], template: "@if (store.status() === 'loading') {\n<div class=\"flex justify-center py-16\">Loading invoice\u2026</div>\n} @else if (!store.invoice()) {\n<div class=\"flex justify-center py-16\">Invoice not found.</div>\n} @else { @if (store.invoice(); as inv) {\n\n<!-- Sticky header -->\n<div class=\"sticky top-0 z-10 border-b border-(--rt-border-color) bg-(--rt-background)\">\n <div class=\"px-4 py-3 flex items-start justify-between gap-4\">\n <div class=\"min-w-0\">\n <div class=\"flex items-center gap-2\">\n <h1 class=\"text-lg font-semibold truncate\">Invoice {{ inv.invoiceNumber || inv.id }}</h1>\n\n <span class=\"px-2 py-0.5 rounded-full text-xs font-semibold\" [class]=\"statusBadgeClass(inv.status)\">\n {{ inv.status }}\n </span>\n\n @if (store.dirty() ) {\n <span class=\"text-xs text-(--rt-text-secondary)\">\u2022 Unsaved changes</span>\n }\n </div>\n\n <div class=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-(--rt-text-secondary)\">\n <span class=\"truncate\"> {{ inv.fullName }} \u2022 {{ inv.email }} </span>\n <span>Created {{ inv.createdAt | date:'dd/MM/yyyy':'Europe/London' }}</span>\n @if (inv.dueAt) { <span>Due {{ inv.dueAt | date:'dd/MM/yyyy':'Europe/London' }}</span> }\n </div>\n </div>\n\n <!-- Desktop actions -->\n\n <div class=\"hidden lg:flex items-center gap-2 shrink-0\">\n @if (inv.pdfUrl) {\n <button mat-stroked-button type=\"button\" (click)=\"openPdf()\">Preview PDF</button>\n } @if (inv.status.toString() === 'ISSUED') {\n <button mat-flat-button type=\"button\" (click)=\"sendEmail()\">Send email</button>\n } @if (inv.status.toString() !== 'SENT' && inv.status.toString() !== 'PAID') {\n <button mat-flat-button (click)=\"edit()\">Edit</button>\n } @if (inv.status.toString() === 'SENT') {\n <button mat-flat-button type=\"button\" (click)=\"sendEmail()\">Resend</button>\n }\n </div>\n\n <!-- Mobile actions -->\n <div class=\"lg:hidden shrink-0\">\n <button mat-icon-button type=\"button\" [matMenuTriggerFor]=\"moreMenu\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </div>\n </div>\n</div>\n\n<!-- Body -->\n<div class=\"p-4 space-y-4\">\n <div class=\"grid grid-cols-1 lg:grid-cols-3 gap-4\">\n <!-- Left column -->\n <div class=\"grid lg:col-span-2 space-y-4\">\n <!-- Customer -->\n <div class=\"rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-4\">\n <div class=\"flex items-center justify-between\">\n <div>\n <div class=\"text-sm font-semibold\">Customer</div>\n <div class=\"text-sm text-(--rt-text-secondary)\">{{ inv.fullName }} \u2022 {{ inv.email }}</div>\n </div>\n </div>\n\n <div class=\"mt-3 grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm\">\n <div>\n <div class=\"text-xs text-(--rt-text-secondary)\">Phone</div>\n <div class=\"font-medium\">{{ inv.phone || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-(--rt-text-secondary)\">Currency</div>\n <div class=\"font-medium\">{{ inv.currency }}</div>\n </div>\n </div>\n </div>\n\n <!-- Lines -->\n\n @if (inv.status.toString() !== 'SENT' && inv.status.toString() !== 'PAID') {\n <rolatech-invoice-manage-line></rolatech-invoice-manage-line>\n } @else {\n <rolatech-invoice-lines [lines]=\"store.lines()\"></rolatech-invoice-lines>\n }\n\n <!-- Notes (optional) -->\n @if (inv.note) {\n <div class=\"rounded-xl border border-(--rt-border-color) p-4\">\n <div class=\"text-sm font-semibold\">Notes</div>\n <div class=\"mt-2 text-sm text-(--rt-text-secondary) whitespace-pre-wrap\">{{ inv.note }}</div>\n </div>\n }\n </div>\n\n <!-- Right rail -->\n <div class=\"space-y-4\">\n <div class=\"rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-4\">\n <div class=\"text-sm font-semibold\">Summary</div>\n\n @if (store.totals(); as t) {\n <div class=\"mt-3 space-y-2 text-sm\">\n <div class=\"flex justify-between\">\n <span class=\"text-(--rt-text-secondary)\">Subtotal</span>\n <span class=\"font-medium\">{{ t.subtotal | price }}</span>\n </div>\n\n <div class=\"flex justify-between\">\n <span class=\"text-(--rt-text-secondary)\">VAT</span>\n <span class=\"font-medium\">{{ t.vatTotal | price }}</span>\n </div>\n\n @if (inv.holdingDepositApplied) {\n <div class=\"flex justify-between\">\n <span class=\"text-(--rt-text-secondary)\">Credit</span>\n <span class=\"font-medium\">-{{ inv.holdingDepositApplied | price }}</span>\n </div>\n }\n\n <div class=\"pt-2 mt-2 border-t border-(--rt-border-color) flex justify-between text-base\">\n <span class=\"font-semibold\">Total</span>\n <span class=\"font-semibold\">{{ t.total | price }}</span>\n </div>\n </div>\n }\n </div>\n <div class=\"rounded-xl border border-(--rt-border-color) bg-(--rt-background) p-4\">\n <div class=\"text-sm font-semibold\">Payment</div>\n <div class=\"mt-2 text-sm text-(--rt-text-secondary)\">\n Status:\n <span class=\"font-medium text-(--rt-text-primary)\">{{ inv.status.toString() === 'PAID' ? 'Paid': 'Unpaid' }}</span>\n </div>\n @if (inv.paidAt) {\n <div class=\"mt-1 text-sm text-(--rt-text-secondary)\">\n Paid: <span class=\"font-medium text-(--rt-text-primary)\">{{ inv.paidAt | date:'dd/MM/yyyy':'Europe/London' }}</span>\n </div>\n }\n </div>\n </div>\n </div>\n</div>\n\n<mat-menu #moreMenu=\"matMenu\" xPosition=\"after\" class=\"divide-y divide-light-900\">\n @if (inv.pdfUrl) {\n <button mat-menu-item type=\"button\" (click)=\"openPdf()\">Preview PDF</button>\n } @if (inv.status.toString() === 'ISSUED') {\n <button mat-menu-item type=\"button\" (click)=\"sendEmail()\">Send email</button>\n } @if (inv.status.toString() !== 'SENT' && inv.status.toString() !== 'PAID') {\n <button mat-menu-item type=\"button\" (click)=\"edit()\">Edit</button>\n\n }\n</mat-menu>\n} }\n" }]
1263
1262
  }] });
1264
1263
 
1265
1264
  class InvoiceManageDownload {
1266
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageDownload, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1267
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.1", type: InvoiceManageDownload, isStandalone: true, selector: "rolatech-invoice-manage-download", ngImport: i0, template: "<p>invoice-manage-download works!</p>\n", styles: [""] }); }
1265
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageDownload, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1266
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: InvoiceManageDownload, isStandalone: true, selector: "rolatech-invoice-manage-download", ngImport: i0, template: "<p>invoice-manage-download works!</p>\n", styles: [""] }); }
1268
1267
  }
1269
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InvoiceManageDownload, decorators: [{
1268
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: InvoiceManageDownload, decorators: [{
1270
1269
  type: Component,
1271
1270
  args: [{ selector: 'rolatech-invoice-manage-download', imports: [], template: "<p>invoice-manage-download works!</p>\n" }]
1272
1271
  }] });
@@ -1302,10 +1301,10 @@ class AgentInvoiceIndex extends BaseComponent {
1302
1301
  this.invoiceStatus = InvoiceStatus;
1303
1302
  this.select = 0;
1304
1303
  this.loading = false;
1305
- this.invoices = signal([], ...(ngDevMode ? [{ debugName: "invoices" }] : []));
1304
+ this.invoices = signal([], ...(ngDevMode ? [{ debugName: "invoices" }] : /* istanbul ignore next */ []));
1306
1305
  this.length = 100;
1307
1306
  this.pageSize = 15;
1308
- this.pageIndex = signal(0, ...(ngDevMode ? [{ debugName: "pageIndex" }] : []));
1307
+ this.pageIndex = signal(0, ...(ngDevMode ? [{ debugName: "pageIndex" }] : /* istanbul ignore next */ []));
1309
1308
  this.pageSizeOptions = [5, 10, 25, 100];
1310
1309
  this.links = [
1311
1310
  {
@@ -1339,7 +1338,7 @@ class AgentInvoiceIndex extends BaseComponent {
1339
1338
  { label: 'Issued', value: invoices.filter((item) => item.status === InvoiceStatus.ISSUED || item.status === InvoiceStatus.SENT).length, hint: 'Awaiting payment' },
1340
1339
  { label: 'Paid', value: invoices.filter((item) => item.status === InvoiceStatus.PAID).length, hint: 'Completed payments' },
1341
1340
  ];
1342
- }, ...(ngDevMode ? [{ debugName: "stats" }] : []));
1341
+ }, ...(ngDevMode ? [{ debugName: "stats" }] : /* istanbul ignore next */ []));
1343
1342
  }
1344
1343
  find() {
1345
1344
  this.router.navigate([], {
@@ -1388,9 +1387,9 @@ class AgentInvoiceIndex extends BaseComponent {
1388
1387
  }))
1389
1388
  .subscribe({
1390
1389
  next: (res) => {
1391
- this.invoices.set(res.data);
1390
+ this.invoices.set(res.data ?? []);
1392
1391
  this.meta = res.meta;
1393
- this.length = res.meta.pagination.count;
1392
+ this.length = res.meta?.pagination?.count ?? res.data?.length ?? 0;
1394
1393
  },
1395
1394
  error: () => {
1396
1395
  this.invoices.set([]);
@@ -1434,10 +1433,10 @@ class AgentInvoiceIndex extends BaseComponent {
1434
1433
  }
1435
1434
  return fallback;
1436
1435
  }
1437
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: AgentInvoiceIndex, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1438
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: AgentInvoiceIndex, isStandalone: true, selector: "rolatech-agent-invoice-index", usesInheritance: true, ngImport: i0, template: "<section class=\"invoice-index-page\">\n <section class=\"invoice-index-page__hero\">\n <div class=\"invoice-index-page__copy\">\n <span class=\"invoice-index-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-index-page__title\">{{ pageMeta.title }}</h1>\n <p class=\"invoice-index-page__description\">{{ pageMeta.description }}</p>\n </div>\n\n <div class=\"invoice-index-page__stats\">\n @for (stat of stats(); track stat.label) {\n <article class=\"invoice-index-page__stat\">\n <span class=\"invoice-index-page__stat-value\">{{ stat.value }}</span>\n <span class=\"invoice-index-page__stat-label\">{{ stat.label }}</span>\n <span class=\"invoice-index-page__stat-hint\">{{ stat.hint }}</span>\n </article>\n }\n </div>\n </section>\n\n <section class=\"invoice-index-page__filters\">\n <nav class=\"invoice-index-page__status-nav\" aria-label=\"Invoice status filters\">\n @for (item of links; track item.name; let index = $index) {\n <a\n class=\"invoice-index-page__status-link\"\n [class.invoice-index-page__status-link--active]=\"select === index\"\n routerLink=\"./\"\n [queryParams]=\"item.status ? { status: item.status } : {}\"\n >\n {{ item.name }}\n </a>\n }\n </nav>\n\n <div class=\"invoice-index-page__filter-grid\">\n <mat-form-field appearance=\"fill\">\n <mat-label>Type</mat-label>\n <mat-select name=\"type\" [(ngModel)]=\"filterOptions.type\">\n @for (type of invoiceType | keyvalue; track type.key) {\n <mat-option [value]=\"type.key\">{{ type.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Status</mat-label>\n <mat-select [compareWith]=\"statusCompareFn\" [(ngModel)]=\"filterOptions.status\">\n @for (status of invoiceStatus | keyvalue; track status.key) {\n <mat-option [value]=\"status.key\">{{ status.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <div class=\"invoice-index-page__filter-actions\">\n <button mat-flat-button (click)=\"find()\">Apply filters</button>\n <button mat-stroked-button (click)=\"resetFilter()\">Reset</button>\n </div>\n </div>\n </section>\n\n <section class=\"invoice-index-page__list\">\n @if (loading) {\n @for (dummy of [0, 1, 2, 3]; track dummy) {\n <rolatech-invoice-item-skeleton></rolatech-invoice-item-skeleton>\n }\n } @else if (invoices().length > 0) {\n @for (item of invoices(); track item.id) {\n <rolatech-invoice-item class=\"cursor-pointer\" [routerLink]=\"['./', item.id]\" [invoice]=\"item\"></rolatech-invoice-item>\n }\n } @else {\n <div class=\"invoice-index-page__empty\">\n <h3>No invoices yet</h3>\n <p>The invoices for this workspace will appear here once billing is created.</p>\n </div>\n }\n\n <mat-paginator\n #paginator\n [length]=\"length\"\n [pageSize]=\"pageSize\"\n [pageIndex]=\"pageIndex()\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onPage($event)\"\n hidePageSize\n showFirstLastButtons\n >\n </mat-paginator>\n </section>\n</section>\n", styles: [".collapsed{max-height:0;overflow:hidden;transition:max-height .5s cubic-bezier(.4,0,.2,1)}.expanded{max-height:1000px}:host{display:block;padding:1rem}.invoice-index-page{display:flex;flex-direction:column;gap:1rem}.invoice-index-page__hero,.invoice-index-page__filters,.invoice-index-page__list{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-index-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-index-page__copy{display:flex;flex-direction:column;gap:.75rem}.invoice-index-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-index-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-index-page__description{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-index-page__stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.85rem}.invoice-index-page__stat{display:flex;flex-direction:column;gap:.2rem;padding:.95rem 1rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.1rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 88%,var(--rt-brand-color) 12%)}.invoice-index-page__stat-value{color:var(--rt-text-primary);font-size:1.2rem;font-weight:700}.invoice-index-page__stat-label,.invoice-index-page__stat-hint{color:var(--rt-text-secondary);font-size:.84rem}.invoice-index-page__filters,.invoice-index-page__list{display:flex;flex-direction:column;gap:1rem;padding:1rem 1.1rem}.invoice-index-page__status-nav{display:flex;flex-wrap:wrap;gap:.65rem}.invoice-index-page__status-link{display:inline-flex;align-items:center;justify-content:center;min-height:2.75rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:9999px;padding:.55rem .95rem;color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-index-page__status-link:hover,.invoice-index-page__status-link--active{border-color:color-mix(in srgb,var(--rt-brand-color) 24%,var(--rt-border-color, rgba(15, 23, 42, .08)));background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color)}.invoice-index-page__filter-grid{display:grid;gap:.85rem}.invoice-index-page__filter-grid mat-form-field{width:100%}.invoice-index-page__filter-actions{display:flex;flex-wrap:wrap;gap:.75rem}.invoice-index-page__empty{display:flex;flex-direction:column;justify-content:center;min-height:10rem;gap:.45rem;padding:1.25rem;border:1px dashed var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.35rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 92%,var(--rt-brand-color) 8%)}.invoice-index-page__empty h3{margin:0;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-index-page__empty p{margin:0;color:var(--rt-text-secondary);line-height:1.65}@media(min-width:900px){.invoice-index-page__hero{grid-template-columns:minmax(0,1.6fr) minmax(19rem,.95fr);align-items:start}.invoice-index-page__filter-grid{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: InvoiceItem, selector: "rolatech-invoice-item", inputs: ["invoice"], outputs: ["download"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i6.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: InvoiceItemSkeleton, selector: "rolatech-invoice-item-skeleton" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }] }); }
1436
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AgentInvoiceIndex, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1437
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: AgentInvoiceIndex, isStandalone: true, selector: "rolatech-agent-invoice-index", usesInheritance: true, ngImport: i0, template: "<section class=\"invoice-index-page\">\n <section class=\"invoice-index-page__hero\">\n <div class=\"invoice-index-page__copy\">\n <span class=\"invoice-index-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-index-page__title\">{{ pageMeta.title }}</h1>\n <p class=\"invoice-index-page__description\">{{ pageMeta.description }}</p>\n </div>\n\n <div class=\"invoice-index-page__stats\">\n @for (stat of stats(); track stat.label) {\n <article class=\"invoice-index-page__stat\">\n <span class=\"invoice-index-page__stat-value\">{{ stat.value }}</span>\n <span class=\"invoice-index-page__stat-label\">{{ stat.label }}</span>\n <span class=\"invoice-index-page__stat-hint\">{{ stat.hint }}</span>\n </article>\n }\n </div>\n </section>\n\n <section class=\"invoice-index-page__filters\">\n <nav class=\"invoice-index-page__status-nav\" aria-label=\"Invoice status filters\">\n @for (item of links; track item.name; let index = $index) {\n <a\n class=\"invoice-index-page__status-link\"\n [class.invoice-index-page__status-link--active]=\"select === index\"\n routerLink=\"./\"\n [queryParams]=\"item.status ? { status: item.status } : {}\"\n >\n {{ item.name }}\n </a>\n }\n </nav>\n\n <div class=\"invoice-index-page__filter-grid\">\n <mat-form-field appearance=\"fill\">\n <mat-label>Type</mat-label>\n <mat-select name=\"type\" [(ngModel)]=\"filterOptions.type\">\n @for (type of invoiceType | keyvalue; track type.key) {\n <mat-option [value]=\"type.key\">{{ type.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Status</mat-label>\n <mat-select [compareWith]=\"statusCompareFn\" [(ngModel)]=\"filterOptions.status\">\n @for (status of invoiceStatus | keyvalue; track status.key) {\n <mat-option [value]=\"status.key\">{{ status.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <div class=\"invoice-index-page__filter-actions\">\n <button mat-flat-button (click)=\"find()\">Apply filters</button>\n <button mat-stroked-button (click)=\"resetFilter()\">Reset</button>\n </div>\n </div>\n </section>\n\n <section class=\"invoice-index-page__list\">\n @if (loading) {\n @for (dummy of [0, 1, 2, 3]; track dummy) {\n <rolatech-invoice-item-skeleton></rolatech-invoice-item-skeleton>\n }\n } @else if (invoices().length > 0) {\n @for (item of invoices(); track item.id) {\n <rolatech-invoice-item class=\"cursor-pointer\" [routerLink]=\"['./', item.id]\" [invoice]=\"item\"></rolatech-invoice-item>\n }\n } @else {\n <div class=\"invoice-index-page__empty\">\n <h3>No invoices yet</h3>\n <p>The invoices for this workspace will appear here once billing is created.</p>\n </div>\n }\n\n <mat-paginator\n #paginator\n [length]=\"length\"\n [pageSize]=\"pageSize\"\n [pageIndex]=\"pageIndex()\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onPage($event)\"\n hidePageSize\n showFirstLastButtons\n >\n </mat-paginator>\n </section>\n</section>\n", styles: [".collapsed{max-height:0;overflow:hidden;transition:max-height .5s cubic-bezier(.4,0,.2,1)}.expanded{max-height:1000px}:host{display:block;padding:1rem}.invoice-index-page{display:flex;flex-direction:column;gap:1rem}.invoice-index-page__hero,.invoice-index-page__filters,.invoice-index-page__list{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-index-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-index-page__copy{display:flex;flex-direction:column;gap:.75rem}.invoice-index-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-index-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-index-page__description{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-index-page__stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.85rem}.invoice-index-page__stat{display:flex;flex-direction:column;gap:.2rem;padding:.95rem 1rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.1rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 88%,var(--rt-brand-color) 12%)}.invoice-index-page__stat-value{color:var(--rt-text-primary);font-size:1.2rem;font-weight:700}.invoice-index-page__stat-label,.invoice-index-page__stat-hint{color:var(--rt-text-secondary);font-size:.84rem}.invoice-index-page__filters,.invoice-index-page__list{display:flex;flex-direction:column;gap:1rem;padding:1rem 1.1rem}.invoice-index-page__status-nav{display:flex;flex-wrap:wrap;gap:.65rem}.invoice-index-page__status-link{display:inline-flex;align-items:center;justify-content:center;min-height:2.75rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:9999px;padding:.55rem .95rem;color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-index-page__status-link:hover,.invoice-index-page__status-link--active{border-color:color-mix(in srgb,var(--rt-brand-color) 24%,var(--rt-border-color, rgba(15, 23, 42, .08)));background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color)}.invoice-index-page__filter-grid{display:grid;gap:.85rem}.invoice-index-page__filter-grid mat-form-field{width:100%}.invoice-index-page__filter-actions{display:flex;flex-wrap:wrap;gap:.75rem}.invoice-index-page__empty{display:flex;flex-direction:column;justify-content:center;min-height:10rem;gap:.45rem;padding:1.25rem;border:1px dashed var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.35rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 92%,var(--rt-brand-color) 8%)}.invoice-index-page__empty h3{margin:0;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-index-page__empty p{margin:0;color:var(--rt-text-secondary);line-height:1.65}@media(min-width:900px){.invoice-index-page__hero{grid-template-columns:minmax(0,1.6fr) minmax(19rem,.95fr);align-items:start}.invoice-index-page__filter-grid{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: InvoiceItem, selector: "rolatech-invoice-item", inputs: ["invoice"], outputs: ["download"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i6.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: InvoiceItemSkeleton, selector: "rolatech-invoice-item-skeleton" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }] }); }
1439
1438
  }
1440
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: AgentInvoiceIndex, decorators: [{
1439
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AgentInvoiceIndex, decorators: [{
1441
1440
  type: Component,
1442
1441
  args: [{ selector: 'rolatech-agent-invoice-index', imports: [
1443
1442
  RouterModule,
@@ -1458,8 +1457,8 @@ class AgentInvoiceDetail extends BaseComponent {
1458
1457
  this.invoiceService = inject(InvoiceService);
1459
1458
  this.paymentService = inject(PaymentService);
1460
1459
  this.pdfUrl = '';
1461
- this.loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1462
- this.invoice = signal(null, ...(ngDevMode ? [{ debugName: "invoice" }] : []));
1460
+ this.loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
1461
+ this.invoice = signal(null, ...(ngDevMode ? [{ debugName: "invoice" }] : /* istanbul ignore next */ []));
1463
1462
  this.status = InvoiceStatus;
1464
1463
  this.pageMeta = {
1465
1464
  baseLink: this.readRouteData('invoiceBaseLink', '/invoices'),
@@ -1539,10 +1538,10 @@ class AgentInvoiceDetail extends BaseComponent {
1539
1538
  }
1540
1539
  return fallback;
1541
1540
  }
1542
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: AgentInvoiceDetail, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1543
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: AgentInvoiceDetail, isStandalone: true, selector: "rolatech-agent-invoice-detail", usesInheritance: true, ngImport: i0, template: "<section class=\"invoice-detail-page\">\n @if (loading()) {\n <section class=\"invoice-detail-page__hero invoice-detail-page__hero--loading\">\n <div class=\"invoice-detail-page__hero-copy\">\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">Loading invoice...</h1>\n </div>\n </section>\n } @else if (!invoice()) {\n <section class=\"invoice-detail-page__panel\">\n <h2 class=\"invoice-detail-page__panel-title\">Invoice not found</h2>\n <p class=\"invoice-detail-page__panel-copy\">The requested invoice could not be loaded for this workspace.</p>\n </section>\n } @else if (invoice(); as invoice) {\n <section class=\"invoice-detail-page__hero\">\n <div class=\"invoice-detail-page__hero-copy\">\n <a class=\"invoice-detail-page__back\" [routerLink]=\"pageMeta.baseLink\">\u2190 {{ pageMeta.collectionTitle }}</a>\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">{{ invoice.invoiceNumber || invoice.id }}</h1>\n <p class=\"invoice-detail-page__description\">\n Invoice for {{ invoice.fullName || invoice.firstName + ' ' + invoice.lastName }} created\n {{ invoice.createdAt | date: 'mediumDate' }}.\n </p>\n </div>\n\n <div class=\"invoice-detail-page__hero-side\">\n <span [class]=\"statusToneClass(invoice.status)\">{{ status[invoice.status] }}</span>\n <div class=\"invoice-detail-page__total\">{{ invoice.total | price }}</div>\n <div class=\"invoice-detail-page__note\">\n @if (invoice.dueAt) {\n Due {{ invoice.dueAt | date: 'mediumDate' }}\n } @else {\n Payable on receipt\n }\n </div>\n\n <div class=\"invoice-detail-page__hero-actions\">\n @if (invoice.pdfUrl) {\n <button mat-stroked-button (click)=\"openPdf()\">Preview PDF</button>\n }\n <button mat-flat-button (click)=\"edit()\">Edit invoice</button>\n </div>\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user\n [firstName]=\"invoice.firstName\"\n [lastName]=\"invoice.lastName\"\n [email]=\"invoice.email\"\n [phone]=\"invoice.phone\"\n ></rolatech-invoice-user>\n\n @if (invoice.lines; as lines) {\n <rolatech-invoice-lines [lines]=\"lines\"></rolatech-invoice-lines>\n }\n </div>\n\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary\n [tax]=\"invoice.vatTotal\"\n [credit]=\"invoice.holdingDepositApplied\"\n [subtotal]=\"invoice.subtotal\"\n [total]=\"invoice.total\"\n ></rolatech-invoice-summary>\n\n <article class=\"invoice-detail-page__panel\">\n <h2 class=\"invoice-detail-page__panel-title\">Invoice note</h2>\n <p class=\"invoice-detail-page__panel-copy\">{{ invoice.note || 'No note added for this invoice.' }}</p>\n </article>\n </div>\n </section>\n }\n</section>\n", styles: [":host{display:block;padding:1rem;--rt-workspace-status-issued-surface: color-mix(in srgb, var(--rt-brand-color) 14%, transparent);--rt-workspace-status-issued-color: color-mix(in srgb, var(--rt-brand-color) 82%, var(--rt-text-primary) 18%);--rt-workspace-status-paid-surface: color-mix(in srgb, var(--rt-brand-color) 16%, var(--rt-base-background, #ffffff));--rt-workspace-status-paid-color: color-mix(in srgb, var(--rt-brand-color) 58%, var(--rt-text-primary) 42%)}.invoice-detail-page{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__hero,.invoice-detail-page__panel{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-detail-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-detail-page__hero-copy,.invoice-detail-page__hero-side,.invoice-detail-page__hero-actions,.invoice-detail-page__main,.invoice-detail-page__side{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__back{color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-detail-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-detail-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-detail-page__description,.invoice-detail-page__note,.invoice-detail-page__panel-copy{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-detail-page__status{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.45rem .82rem;font-size:.8rem;font-weight:700}.invoice-detail-page__status--neutral{background:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-brand-color)}.invoice-detail-page__status--issued{background:var(--rt-workspace-status-issued-surface);color:var(--rt-workspace-status-issued-color)}.invoice-detail-page__status--paid{background:var(--rt-workspace-status-paid-surface);color:var(--rt-workspace-status-paid-color)}.invoice-detail-page__status--void{background:color-mix(in srgb,var(--mat-sys-error, #b91c1c) 14%,transparent);color:var(--mat-sys-error, #b91c1c)}.invoice-detail-page__total{color:var(--rt-text-primary);font-size:clamp(1.8rem,2.4vw,2.3rem);font-weight:800}.invoice-detail-page__hero-actions{flex-wrap:wrap}.invoice-detail-page__content{display:grid;gap:1rem}.invoice-detail-page__panel{padding:1rem 1.1rem}.invoice-detail-page__panel-title{margin:0 0 .6rem;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}@media(min-width:1024px){.invoice-detail-page__hero{grid-template-columns:minmax(0,1.65fr) minmax(18rem,.85fr);align-items:start}.invoice-detail-page__content{grid-template-columns:minmax(0,1.65fr) minmax(20rem,.85fr);align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: InvoiceSummary, selector: "rolatech-invoice-summary", inputs: ["tax", "credit", "subtotal", "total"] }, { kind: "component", type: InvoiceLines, selector: "rolatech-invoice-lines", inputs: ["lines"] }, { kind: "component", type: InvoiceUser, selector: "rolatech-invoice-user", inputs: ["firstName", "lastName", "email", "phone"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
1541
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AgentInvoiceDetail, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1542
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: AgentInvoiceDetail, isStandalone: true, selector: "rolatech-agent-invoice-detail", usesInheritance: true, ngImport: i0, template: "<section class=\"invoice-detail-page\">\n @if (loading()) {\n <section class=\"invoice-detail-page__hero invoice-detail-page__hero--loading\">\n <div class=\"invoice-detail-page__hero-copy\">\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">Loading invoice...</h1>\n </div>\n </section>\n } @else if (!invoice()) {\n <section class=\"invoice-detail-page__panel\">\n <h2 class=\"invoice-detail-page__panel-title\">Invoice not found</h2>\n <p class=\"invoice-detail-page__panel-copy\">The requested invoice could not be loaded for this workspace.</p>\n </section>\n } @else if (invoice(); as invoice) {\n <section class=\"invoice-detail-page__hero\">\n <div class=\"invoice-detail-page__hero-copy\">\n <a class=\"invoice-detail-page__back\" [routerLink]=\"pageMeta.baseLink\">\u2190 {{ pageMeta.collectionTitle }}</a>\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">{{ invoice.invoiceNumber || invoice.id }}</h1>\n <p class=\"invoice-detail-page__description\">\n Invoice for {{ invoice.fullName || invoice.firstName + ' ' + invoice.lastName }} created\n {{ invoice.createdAt | date: 'mediumDate' }}.\n </p>\n </div>\n\n <div class=\"invoice-detail-page__hero-side\">\n <span [class]=\"statusToneClass(invoice.status)\">{{ status[invoice.status] }}</span>\n <div class=\"invoice-detail-page__total\">{{ invoice.total | price }}</div>\n <div class=\"invoice-detail-page__note\">\n @if (invoice.dueAt) {\n Due {{ invoice.dueAt | date: 'mediumDate' }}\n } @else {\n Payable on receipt\n }\n </div>\n\n <div class=\"invoice-detail-page__hero-actions\">\n @if (invoice.pdfUrl) {\n <button mat-stroked-button (click)=\"openPdf()\">Preview PDF</button>\n }\n <button mat-flat-button (click)=\"edit()\">Edit invoice</button>\n </div>\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user\n [firstName]=\"invoice.firstName\"\n [lastName]=\"invoice.lastName\"\n [email]=\"invoice.email\"\n [phone]=\"invoice.phone\"\n ></rolatech-invoice-user>\n\n @if (invoice.lines; as lines) {\n <rolatech-invoice-lines [lines]=\"lines\"></rolatech-invoice-lines>\n }\n </div>\n\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary\n [tax]=\"invoice.vatTotal\"\n [credit]=\"invoice.holdingDepositApplied\"\n [subtotal]=\"invoice.subtotal\"\n [total]=\"invoice.total\"\n ></rolatech-invoice-summary>\n\n <article class=\"invoice-detail-page__panel\">\n <h2 class=\"invoice-detail-page__panel-title\">Invoice note</h2>\n <p class=\"invoice-detail-page__panel-copy\">{{ invoice.note || 'No note added for this invoice.' }}</p>\n </article>\n </div>\n </section>\n }\n</section>\n", styles: [":host{display:block;padding:1rem;--rt-workspace-status-issued-surface: color-mix(in srgb, var(--rt-brand-color) 14%, transparent);--rt-workspace-status-issued-color: color-mix(in srgb, var(--rt-brand-color) 82%, var(--rt-text-primary) 18%);--rt-workspace-status-paid-surface: color-mix(in srgb, var(--rt-brand-color) 16%, var(--rt-base-background, #ffffff));--rt-workspace-status-paid-color: color-mix(in srgb, var(--rt-brand-color) 58%, var(--rt-text-primary) 42%)}.invoice-detail-page{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__hero,.invoice-detail-page__panel{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-detail-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-detail-page__hero-copy,.invoice-detail-page__hero-side,.invoice-detail-page__hero-actions,.invoice-detail-page__main,.invoice-detail-page__side{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__back{color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-detail-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-detail-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-detail-page__description,.invoice-detail-page__note,.invoice-detail-page__panel-copy{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-detail-page__status{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.45rem .82rem;font-size:.8rem;font-weight:700}.invoice-detail-page__status--neutral{background:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-brand-color)}.invoice-detail-page__status--issued{background:var(--rt-workspace-status-issued-surface);color:var(--rt-workspace-status-issued-color)}.invoice-detail-page__status--paid{background:var(--rt-workspace-status-paid-surface);color:var(--rt-workspace-status-paid-color)}.invoice-detail-page__status--void{background:color-mix(in srgb,var(--mat-sys-error, #b91c1c) 14%,transparent);color:var(--mat-sys-error, #b91c1c)}.invoice-detail-page__total{color:var(--rt-text-primary);font-size:clamp(1.8rem,2.4vw,2.3rem);font-weight:800}.invoice-detail-page__hero-actions{flex-wrap:wrap}.invoice-detail-page__content{display:grid;gap:1rem}.invoice-detail-page__panel{padding:1rem 1.1rem}.invoice-detail-page__panel-title{margin:0 0 .6rem;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}@media(min-width:1024px){.invoice-detail-page__hero{grid-template-columns:minmax(0,1.65fr) minmax(18rem,.85fr);align-items:start}.invoice-detail-page__content{grid-template-columns:minmax(0,1.65fr) minmax(20rem,.85fr);align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: InvoiceSummary, selector: "rolatech-invoice-summary", inputs: ["tax", "credit", "subtotal", "total"] }, { kind: "component", type: InvoiceLines, selector: "rolatech-invoice-lines", inputs: ["lines"] }, { kind: "component", type: InvoiceUser, selector: "rolatech-invoice-user", inputs: ["firstName", "lastName", "email", "phone"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
1544
1543
  }
1545
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: AgentInvoiceDetail, decorators: [{
1544
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AgentInvoiceDetail, decorators: [{
1546
1545
  type: Component,
1547
1546
  args: [{ selector: 'rolatech-agent-invoice-detail', imports: [
1548
1547
  CommonModule,
@@ -1571,12 +1570,12 @@ const agentInvoiceRoutes = [
1571
1570
  class BillingProfileFacade {
1572
1571
  constructor() {
1573
1572
  this.billingProfileService = inject(BillingProfileService);
1574
- this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1575
- this.saving = signal(false, ...(ngDevMode ? [{ debugName: "saving" }] : []));
1576
- this.profile = signal(null, ...(ngDevMode ? [{ debugName: "profile" }] : []));
1577
- this.error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
1578
- this.saveMessage = signal(null, ...(ngDevMode ? [{ debugName: "saveMessage" }] : []));
1579
- this.enabled = computed(() => this.profile()?.enabled ?? false, ...(ngDevMode ? [{ debugName: "enabled" }] : []));
1573
+ this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
1574
+ this.saving = signal(false, ...(ngDevMode ? [{ debugName: "saving" }] : /* istanbul ignore next */ []));
1575
+ this.profile = signal(null, ...(ngDevMode ? [{ debugName: "profile" }] : /* istanbul ignore next */ []));
1576
+ this.error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
1577
+ this.saveMessage = signal(null, ...(ngDevMode ? [{ debugName: "saveMessage" }] : /* istanbul ignore next */ []));
1578
+ this.enabled = computed(() => this.profile()?.enabled ?? false, ...(ngDevMode ? [{ debugName: "enabled" }] : /* istanbul ignore next */ []));
1580
1579
  }
1581
1580
  load() {
1582
1581
  this.loading.set(true);
@@ -1616,7 +1615,7 @@ class BillingProfileFacade {
1616
1615
  this.error.set(null);
1617
1616
  this.saveMessage.set(null);
1618
1617
  this.billingProfileService
1619
- .patch({ enabled })
1618
+ .patchProfile({ enabled })
1620
1619
  .pipe(finalize(() => this.saving.set(false)))
1621
1620
  .subscribe({
1622
1621
  next: (response) => {
@@ -1628,11 +1627,14 @@ class BillingProfileFacade {
1628
1627
  },
1629
1628
  });
1630
1629
  }
1631
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: BillingProfileFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1632
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: BillingProfileFacade }); }
1630
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: BillingProfileFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1631
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: BillingProfileFacade, providedIn: 'root' }); }
1633
1632
  }
1634
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: BillingProfileFacade, decorators: [{
1635
- type: Injectable
1633
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: BillingProfileFacade, decorators: [{
1634
+ type: Injectable,
1635
+ args: [{
1636
+ providedIn: 'root',
1637
+ }]
1636
1638
  }] });
1637
1639
 
1638
1640
  function createBillingProfileForm(formBuilder) {
@@ -1690,7 +1692,7 @@ class BillingProfileSettingPage {
1690
1692
  this.formBuilder = inject(FormBuilder);
1691
1693
  this.facade = inject(BillingProfileFacade);
1692
1694
  this.form = createBillingProfileForm(this.formBuilder);
1693
- this.canSubmit = computed(() => !this.facade.loading() && !this.facade.saving(), ...(ngDevMode ? [{ debugName: "canSubmit" }] : []));
1695
+ this.canSubmit = computed(() => !this.facade.loading() && !this.facade.saving(), ...(ngDevMode ? [{ debugName: "canSubmit" }] : /* istanbul ignore next */ []));
1694
1696
  effect(() => {
1695
1697
  const profile = this.facade.profile();
1696
1698
  patchBillingProfileForm(this.form, profile);
@@ -1706,10 +1708,10 @@ class BillingProfileSettingPage {
1706
1708
  toggleEnabled(enabled) {
1707
1709
  this.facade.setEnabled(enabled);
1708
1710
  }
1709
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: BillingProfileSettingPage, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1710
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: BillingProfileSettingPage, isStandalone: true, selector: "rolatech-billing-profile-setting-page", providers: [BillingProfileFacade], ngImport: i0, template: "<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n <header class=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div class=\"min-w-0\">\n <div class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Member Management</h1>\n <p class=\"text-sm text-muted-foreground\">\n Review organization members, invitation state, and current role assignments from one workspace.\n </p>\n </div>\n </div>\n </header>\n <section class=\"grid gap-4\">\n @if (facade.error()) {\n <div class=\"mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\">{{ facade.error() }}</div>\n } @if (facade.saveMessage()) {\n <div class=\"mb-4 rounded-xl border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-700\">\n {{ facade.saveMessage() }}\n </div>\n }\n\n <form [formGroup]=\"form\" (ngSubmit)=\"submit()\" class=\"space-y-6\">\n <mat-card class=\"rounded-2xl\">\n <div class=\"grid gap-4 p-4 md:grid-cols-2\">\n <div class=\"md:col-span-2 flex items-center justify-between\">\n <div>\n <div class=\"text-base font-medium\">Billing Profile Status</div>\n <div class=\"text-sm text-gray-500\">Enable this profile for invoice generation and payment instructions.</div>\n </div>\n\n <mat-slide-toggle formControlName=\"enabled\" (change)=\"toggleEnabled($event.checked)\"> Enabled </mat-slide-toggle>\n </div>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Display Name</mat-label>\n <input matInput formControlName=\"displayName\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Logo URL</mat-label>\n <input matInput formControlName=\"logoUrl\" />\n </mat-form-field>\n </div>\n </mat-card>\n\n <mat-card class=\"rounded-2xl\">\n <div class=\"p-4\">\n <h2 class=\"mb-4 text-lg font-medium\">Company Information</h2>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Company Name</mat-label>\n <input matInput formControlName=\"companyName\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Website</mat-label>\n <input matInput formControlName=\"companyWebsite\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Registration No</mat-label>\n <input matInput formControlName=\"companyRegistrationNo\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>VAT No</mat-label>\n <input matInput formControlName=\"companyVatNo\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" class=\"md:col-span-2\">\n <mat-label>Address</mat-label>\n <textarea matInput rows=\"3\" formControlName=\"companyAddressLine\"></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Company Email</mat-label>\n <input matInput formControlName=\"companyEmail\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Company Phone</mat-label>\n <input matInput formControlName=\"companyPhone\" />\n </mat-form-field>\n </div>\n </div>\n </mat-card>\n\n <mat-card class=\"rounded-2xl\">\n <div class=\"p-4\">\n <h2 class=\"mb-4 text-lg font-medium\">Bank Information</h2>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Bank Institution</mat-label>\n <input matInput formControlName=\"bankInstitution\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Account Name</mat-label>\n <input matInput formControlName=\"bankAccountName\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Sort Code</mat-label>\n <input matInput formControlName=\"bankSortCode\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Account No</mat-label>\n <input matInput formControlName=\"bankAccountNo\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>SWIFT</mat-label>\n <input matInput formControlName=\"bankSwift\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>IBAN</mat-label>\n <input matInput formControlName=\"bankIban\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" class=\"md:col-span-2\">\n <mat-label>Payment Reference</mat-label>\n <input matInput formControlName=\"bankPaymentRef\" />\n </mat-form-field>\n </div>\n </div>\n </mat-card>\n\n <mat-card class=\"rounded-2xl\">\n <div class=\"p-4\">\n <h2 class=\"mb-4 text-lg font-medium\">Invoice & Payment Content</h2>\n\n <div class=\"grid gap-4\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Invoice Footer</mat-label>\n <textarea matInput rows=\"4\" formControlName=\"invoiceFooter\"></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Payment Instructions</mat-label>\n <textarea matInput rows=\"5\" formControlName=\"paymentInstructions\"></textarea>\n </mat-form-field>\n </div>\n </div>\n </mat-card>\n\n <div class=\"flex justify-end\">\n <button mat-flat-button color=\"primary\" type=\"submit\" [disabled]=\"facade.saving() || facade.loading()\">\n {{ facade.saving() ? 'Saving...' : 'Save Billing Profile' }}\n </button>\n </div>\n </form>\n </section>\n</section>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.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: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i5$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i8.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1711
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: BillingProfileSettingPage, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1712
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: BillingProfileSettingPage, isStandalone: true, selector: "rolatech-billing-profile-setting-page", providers: [BillingProfileFacade], ngImport: i0, template: "<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n <header class=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div class=\"min-w-0\">\n <div class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Member Management</h1>\n <p class=\"text-sm text-muted-foreground\">\n Review organization members, invitation state, and current role assignments from one workspace.\n </p>\n </div>\n </div>\n </header>\n <section class=\"grid gap-4\">\n @if (facade.error()) {\n <div class=\"mb-4 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\">{{ facade.error() }}</div>\n } @if (facade.saveMessage()) {\n <div class=\"mb-4 rounded-xl border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-700\">\n {{ facade.saveMessage() }}\n </div>\n }\n\n <form [formGroup]=\"form\" (ngSubmit)=\"submit()\" class=\"space-y-6\">\n <mat-card class=\"rounded-2xl\">\n <div class=\"grid gap-4 p-4 md:grid-cols-2\">\n <div class=\"md:col-span-2 flex items-center justify-between\">\n <div>\n <div class=\"text-base font-medium\">Billing Profile Status</div>\n <div class=\"text-sm text-gray-500\">Enable this profile for invoice generation and payment instructions.</div>\n </div>\n\n <mat-slide-toggle formControlName=\"enabled\" (change)=\"toggleEnabled($event.checked)\"> Enabled </mat-slide-toggle>\n </div>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Display Name</mat-label>\n <input matInput formControlName=\"displayName\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Logo URL</mat-label>\n <input matInput formControlName=\"logoUrl\" />\n </mat-form-field>\n </div>\n </mat-card>\n\n <mat-card class=\"rounded-2xl\">\n <div class=\"p-4\">\n <h2 class=\"mb-4 text-lg font-medium\">Company Information</h2>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Company Name</mat-label>\n <input matInput formControlName=\"companyName\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Website</mat-label>\n <input matInput formControlName=\"companyWebsite\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Registration No</mat-label>\n <input matInput formControlName=\"companyRegistrationNo\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>VAT No</mat-label>\n <input matInput formControlName=\"companyVatNo\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" class=\"md:col-span-2\">\n <mat-label>Address</mat-label>\n <textarea matInput rows=\"3\" formControlName=\"companyAddressLine\"></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Company Email</mat-label>\n <input matInput formControlName=\"companyEmail\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Company Phone</mat-label>\n <input matInput formControlName=\"companyPhone\" />\n </mat-form-field>\n </div>\n </div>\n </mat-card>\n\n <mat-card class=\"rounded-2xl\">\n <div class=\"p-4\">\n <h2 class=\"mb-4 text-lg font-medium\">Bank Information</h2>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Bank Institution</mat-label>\n <input matInput formControlName=\"bankInstitution\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Account Name</mat-label>\n <input matInput formControlName=\"bankAccountName\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Sort Code</mat-label>\n <input matInput formControlName=\"bankSortCode\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Account No</mat-label>\n <input matInput formControlName=\"bankAccountNo\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>SWIFT</mat-label>\n <input matInput formControlName=\"bankSwift\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>IBAN</mat-label>\n <input matInput formControlName=\"bankIban\" />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" class=\"md:col-span-2\">\n <mat-label>Payment Reference</mat-label>\n <input matInput formControlName=\"bankPaymentRef\" />\n </mat-form-field>\n </div>\n </div>\n </mat-card>\n\n <mat-card class=\"rounded-2xl\">\n <div class=\"p-4\">\n <h2 class=\"mb-4 text-lg font-medium\">Invoice & Payment Content</h2>\n\n <div class=\"grid gap-4\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Invoice Footer</mat-label>\n <textarea matInput rows=\"4\" formControlName=\"invoiceFooter\"></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\">\n <mat-label>Payment Instructions</mat-label>\n <textarea matInput rows=\"5\" formControlName=\"paymentInstructions\"></textarea>\n </mat-form-field>\n </div>\n </div>\n </mat-card>\n\n <div class=\"flex justify-end\">\n <button mat-flat-button color=\"primary\" type=\"submit\" [disabled]=\"facade.saving() || facade.loading()\">\n {{ facade.saving() ? 'Saving...' : 'Save Billing Profile' }}\n </button>\n </div>\n </form>\n </section>\n</section>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.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: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i5$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i8.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1711
1713
  }
1712
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: BillingProfileSettingPage, decorators: [{
1714
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: BillingProfileSettingPage, decorators: [{
1713
1715
  type: Component,
1714
1716
  args: [{ selector: 'rolatech-billing-profile-setting-page', imports: [
1715
1717
  CommonModule,
@@ -1729,9 +1731,323 @@ const BILLING_PROFILE_ROUTES = [
1729
1731
  },
1730
1732
  ];
1731
1733
 
1734
+ class MarketInvoiceIndex extends BaseComponent {
1735
+ constructor() {
1736
+ super(...arguments);
1737
+ this.invoiceService = inject(InvoiceService);
1738
+ this.filterOptions = {
1739
+ type: '',
1740
+ status: '',
1741
+ };
1742
+ this.invoiceType = InvoiceType;
1743
+ this.invoiceStatus = InvoiceStatus;
1744
+ this.select = 0;
1745
+ this.loading = false;
1746
+ this.invoices = signal([], ...(ngDevMode ? [{ debugName: "invoices" }] : /* istanbul ignore next */ []));
1747
+ this.length = 100;
1748
+ this.pageSize = 15;
1749
+ this.pageIndex = signal(0, ...(ngDevMode ? [{ debugName: "pageIndex" }] : /* istanbul ignore next */ []));
1750
+ this.pageSizeOptions = [5, 10, 25, 100];
1751
+ this.links = [
1752
+ {
1753
+ name: 'All',
1754
+ status: '',
1755
+ },
1756
+ {
1757
+ name: 'Created',
1758
+ status: 'created',
1759
+ },
1760
+ {
1761
+ name: 'Issued',
1762
+ status: 'issued',
1763
+ },
1764
+ {
1765
+ name: 'Paid',
1766
+ status: 'paid',
1767
+ },
1768
+ ];
1769
+ this.pageMeta = {
1770
+ baseLink: this.readRouteData('invoiceBaseLink', '/invoices'),
1771
+ eyebrow: this.readRouteData('invoiceEyebrow', 'Agent workspace'),
1772
+ title: this.readRouteData('invoiceCollectionTitle', 'Listing invoices'),
1773
+ description: this.readRouteData('invoiceCollectionDescription', 'Monitor invoices tied to your listings, with billing status and payment movement visible at a glance.'),
1774
+ };
1775
+ this.stats = computed(() => {
1776
+ const invoices = this.invoices();
1777
+ return [
1778
+ { label: 'Invoices', value: this.length || invoices.length, hint: 'Billing records in your agent workspace' },
1779
+ {
1780
+ label: 'Created',
1781
+ value: invoices.filter((item) => item.status === InvoiceStatus.CREATED).length,
1782
+ hint: 'Prepared but not yet settled',
1783
+ },
1784
+ {
1785
+ label: 'Issued',
1786
+ value: invoices.filter((item) => item.status === InvoiceStatus.ISSUED || item.status === InvoiceStatus.SENT).length,
1787
+ hint: 'Awaiting payment',
1788
+ },
1789
+ {
1790
+ label: 'Paid',
1791
+ value: invoices.filter((item) => item.status === InvoiceStatus.PAID).length,
1792
+ hint: 'Completed payments',
1793
+ },
1794
+ ];
1795
+ }, ...(ngDevMode ? [{ debugName: "stats" }] : /* istanbul ignore next */ []));
1796
+ }
1797
+ find() {
1798
+ this.router.navigate([], {
1799
+ queryParams: {
1800
+ type: this.filterOptions.type || null,
1801
+ status: this.filterOptions.status || null,
1802
+ page: 1,
1803
+ },
1804
+ queryParamsHandling: 'merge',
1805
+ replaceUrl: true,
1806
+ });
1807
+ }
1808
+ ngOnInit() {
1809
+ const sub = this.route.queryParamMap
1810
+ .pipe(map((p) => {
1811
+ const page = p.get('page') ? Number(p.get('page')) : 1;
1812
+ this.pageIndex.set(Math.max(page - 1, 0));
1813
+ const status = p.get('status') || undefined;
1814
+ const type = p.get('type') || undefined;
1815
+ this.filterOptions = {
1816
+ type: type || '',
1817
+ status: status || '',
1818
+ };
1819
+ const filters = [];
1820
+ if (status) {
1821
+ this.select = this.links.findIndex((item) => item.status === status);
1822
+ filters.push(`status:${status.toUpperCase()}`);
1823
+ }
1824
+ else {
1825
+ this.select = 0;
1826
+ }
1827
+ if (type) {
1828
+ filters.push(`type:${type}`);
1829
+ }
1830
+ return {
1831
+ page,
1832
+ filter: filters.join(','),
1833
+ limit: p.get('limit') ? Number(p.get('limit')) : 15,
1834
+ sort: p.get('sort') || undefined,
1835
+ };
1836
+ }),
1837
+ // Cheap deep compare via JSON to avoid spam calls when nothing changed
1838
+ map((o) => JSON.stringify(o)), distinctUntilChanged(), map((s) => JSON.parse(s)), switchMap((params) => {
1839
+ this.loading = true;
1840
+ return this.invoiceService.findByManager(params).pipe(finalize(() => (this.loading = false)));
1841
+ }))
1842
+ .subscribe({
1843
+ next: (res) => {
1844
+ this.invoices.set(res.data ?? []);
1845
+ this.meta = res.meta;
1846
+ this.length = res.meta?.pagination?.count ?? res.data?.length ?? 0;
1847
+ },
1848
+ error: () => {
1849
+ this.invoices.set([]);
1850
+ this.length = 0;
1851
+ },
1852
+ });
1853
+ // // auto-unsubscribe on destroy
1854
+ this.destroyRef.onDestroy(() => sub.unsubscribe());
1855
+ }
1856
+ onPage(e) {
1857
+ this.router.navigate([], {
1858
+ queryParams: { page: e.pageIndex + 1, limit: e.pageSize },
1859
+ queryParamsHandling: 'merge',
1860
+ replaceUrl: true, // optional: avoid stacking history on every page click
1861
+ });
1862
+ }
1863
+ resetFilter() {
1864
+ this.filterOptions = {
1865
+ type: '',
1866
+ status: '',
1867
+ };
1868
+ this.router.navigate([], {
1869
+ queryParams: {
1870
+ type: null,
1871
+ status: null,
1872
+ page: 1,
1873
+ },
1874
+ queryParamsHandling: 'merge',
1875
+ replaceUrl: true,
1876
+ });
1877
+ }
1878
+ statusCompareFn(t1, t2) {
1879
+ return t1 === t2;
1880
+ }
1881
+ readRouteData(key, fallback) {
1882
+ for (const snapshot of [...this.route.snapshot.pathFromRoot].reverse()) {
1883
+ const value = snapshot.data?.[key];
1884
+ if (typeof value === 'string' && value.length > 0) {
1885
+ return value;
1886
+ }
1887
+ }
1888
+ return fallback;
1889
+ }
1890
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarketInvoiceIndex, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1891
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MarketInvoiceIndex, isStandalone: true, selector: "rolatech-agent-invoice-index", usesInheritance: true, ngImport: i0, template: "<section class=\"invoice-index-page\">\n <section class=\"invoice-index-page__hero\">\n <div class=\"invoice-index-page__copy\">\n <span class=\"invoice-index-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-index-page__title\">{{ pageMeta.title }}</h1>\n <p class=\"invoice-index-page__description\">{{ pageMeta.description }}</p>\n </div>\n\n <div class=\"invoice-index-page__stats\">\n @for (stat of stats(); track stat.label) {\n <article class=\"invoice-index-page__stat\">\n <span class=\"invoice-index-page__stat-value\">{{ stat.value }}</span>\n <span class=\"invoice-index-page__stat-label\">{{ stat.label }}</span>\n <span class=\"invoice-index-page__stat-hint\">{{ stat.hint }}</span>\n </article>\n }\n </div>\n </section>\n\n <section class=\"invoice-index-page__filters\">\n <nav class=\"invoice-index-page__status-nav\" aria-label=\"Invoice status filters\">\n @for (item of links; track item.name; let index = $index) {\n <a\n class=\"invoice-index-page__status-link\"\n [class.invoice-index-page__status-link--active]=\"select === index\"\n routerLink=\"./\"\n [queryParams]=\"item.status ? { status: item.status } : {}\"\n >\n {{ item.name }}\n </a>\n }\n </nav>\n\n <div class=\"invoice-index-page__filter-grid\">\n <mat-form-field appearance=\"fill\">\n <mat-label>Type</mat-label>\n <mat-select name=\"type\" [(ngModel)]=\"filterOptions.type\">\n @for (type of invoiceType | keyvalue; track type.key) {\n <mat-option [value]=\"type.key\">{{ type.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Status</mat-label>\n <mat-select [compareWith]=\"statusCompareFn\" [(ngModel)]=\"filterOptions.status\">\n @for (status of invoiceStatus | keyvalue; track status.key) {\n <mat-option [value]=\"status.key\">{{ status.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <div class=\"invoice-index-page__filter-actions\">\n <button mat-flat-button (click)=\"find()\">Apply filters</button>\n <button mat-stroked-button (click)=\"resetFilter()\">Reset</button>\n </div>\n </div>\n </section>\n\n <section class=\"invoice-index-page__list\">\n @if (loading) { @for (dummy of [0, 1, 2, 3]; track dummy) {\n <rolatech-invoice-item-skeleton></rolatech-invoice-item-skeleton>\n } } @else if (invoices().length > 0) { @for (item of invoices(); track item.id) {\n <rolatech-invoice-item class=\"cursor-pointer\" [routerLink]=\"['./', item.id]\" [invoice]=\"item\"></rolatech-invoice-item>\n } } @else {\n <div class=\"invoice-index-page__empty\">\n <h3>No invoices yet</h3>\n <p>The invoices for this workspace will appear here once billing is created.</p>\n </div>\n }\n\n <mat-paginator\n #paginator\n [length]=\"length\"\n [pageSize]=\"pageSize\"\n [pageIndex]=\"pageIndex()\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onPage($event)\"\n hidePageSize\n showFirstLastButtons\n >\n </mat-paginator>\n </section>\n</section>\n", styles: [".collapsed{max-height:0;overflow:hidden;transition:max-height .5s cubic-bezier(.4,0,.2,1)}.expanded{max-height:1000px}:host{display:block;padding:1rem}.invoice-index-page{display:flex;flex-direction:column;gap:1rem}.invoice-index-page__hero,.invoice-index-page__filters,.invoice-index-page__list{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-index-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-index-page__copy{display:flex;flex-direction:column;gap:.75rem}.invoice-index-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-index-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-index-page__description{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-index-page__stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.85rem}.invoice-index-page__stat{display:flex;flex-direction:column;gap:.2rem;padding:.95rem 1rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.1rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 88%,var(--rt-brand-color) 12%)}.invoice-index-page__stat-value{color:var(--rt-text-primary);font-size:1.2rem;font-weight:700}.invoice-index-page__stat-label,.invoice-index-page__stat-hint{color:var(--rt-text-secondary);font-size:.84rem}.invoice-index-page__filters,.invoice-index-page__list{display:flex;flex-direction:column;gap:1rem;padding:1rem 1.1rem}.invoice-index-page__status-nav{display:flex;flex-wrap:wrap;gap:.65rem}.invoice-index-page__status-link{display:inline-flex;align-items:center;justify-content:center;min-height:2.75rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:9999px;padding:.55rem .95rem;color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-index-page__status-link:hover,.invoice-index-page__status-link--active{border-color:color-mix(in srgb,var(--rt-brand-color) 24%,var(--rt-border-color, rgba(15, 23, 42, .08)));background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color)}.invoice-index-page__filter-grid{display:grid;gap:.85rem}.invoice-index-page__filter-grid mat-form-field{width:100%}.invoice-index-page__filter-actions{display:flex;flex-wrap:wrap;gap:.75rem}.invoice-index-page__empty{display:flex;flex-direction:column;justify-content:center;min-height:10rem;gap:.45rem;padding:1.25rem;border:1px dashed var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.35rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 92%,var(--rt-brand-color) 8%)}.invoice-index-page__empty h3{margin:0;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-index-page__empty p{margin:0;color:var(--rt-text-secondary);line-height:1.65}@media(min-width:900px){.invoice-index-page__hero{grid-template-columns:minmax(0,1.6fr) minmax(19rem,.95fr);align-items:start}.invoice-index-page__filter-grid{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: InvoiceItem, selector: "rolatech-invoice-item", inputs: ["invoice"], outputs: ["download"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i6.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: InvoiceItemSkeleton, selector: "rolatech-invoice-item-skeleton" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }] }); }
1892
+ }
1893
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarketInvoiceIndex, decorators: [{
1894
+ type: Component,
1895
+ args: [{ selector: 'rolatech-agent-invoice-index', imports: [
1896
+ RouterModule,
1897
+ InvoiceItem,
1898
+ MatButtonModule,
1899
+ FormsModule,
1900
+ MatFormFieldModule,
1901
+ MatSelectModule,
1902
+ KeyValuePipe,
1903
+ MatPaginatorModule,
1904
+ InvoiceItemSkeleton,
1905
+ ], template: "<section class=\"invoice-index-page\">\n <section class=\"invoice-index-page__hero\">\n <div class=\"invoice-index-page__copy\">\n <span class=\"invoice-index-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-index-page__title\">{{ pageMeta.title }}</h1>\n <p class=\"invoice-index-page__description\">{{ pageMeta.description }}</p>\n </div>\n\n <div class=\"invoice-index-page__stats\">\n @for (stat of stats(); track stat.label) {\n <article class=\"invoice-index-page__stat\">\n <span class=\"invoice-index-page__stat-value\">{{ stat.value }}</span>\n <span class=\"invoice-index-page__stat-label\">{{ stat.label }}</span>\n <span class=\"invoice-index-page__stat-hint\">{{ stat.hint }}</span>\n </article>\n }\n </div>\n </section>\n\n <section class=\"invoice-index-page__filters\">\n <nav class=\"invoice-index-page__status-nav\" aria-label=\"Invoice status filters\">\n @for (item of links; track item.name; let index = $index) {\n <a\n class=\"invoice-index-page__status-link\"\n [class.invoice-index-page__status-link--active]=\"select === index\"\n routerLink=\"./\"\n [queryParams]=\"item.status ? { status: item.status } : {}\"\n >\n {{ item.name }}\n </a>\n }\n </nav>\n\n <div class=\"invoice-index-page__filter-grid\">\n <mat-form-field appearance=\"fill\">\n <mat-label>Type</mat-label>\n <mat-select name=\"type\" [(ngModel)]=\"filterOptions.type\">\n @for (type of invoiceType | keyvalue; track type.key) {\n <mat-option [value]=\"type.key\">{{ type.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>Status</mat-label>\n <mat-select [compareWith]=\"statusCompareFn\" [(ngModel)]=\"filterOptions.status\">\n @for (status of invoiceStatus | keyvalue; track status.key) {\n <mat-option [value]=\"status.key\">{{ status.value }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <div class=\"invoice-index-page__filter-actions\">\n <button mat-flat-button (click)=\"find()\">Apply filters</button>\n <button mat-stroked-button (click)=\"resetFilter()\">Reset</button>\n </div>\n </div>\n </section>\n\n <section class=\"invoice-index-page__list\">\n @if (loading) { @for (dummy of [0, 1, 2, 3]; track dummy) {\n <rolatech-invoice-item-skeleton></rolatech-invoice-item-skeleton>\n } } @else if (invoices().length > 0) { @for (item of invoices(); track item.id) {\n <rolatech-invoice-item class=\"cursor-pointer\" [routerLink]=\"['./', item.id]\" [invoice]=\"item\"></rolatech-invoice-item>\n } } @else {\n <div class=\"invoice-index-page__empty\">\n <h3>No invoices yet</h3>\n <p>The invoices for this workspace will appear here once billing is created.</p>\n </div>\n }\n\n <mat-paginator\n #paginator\n [length]=\"length\"\n [pageSize]=\"pageSize\"\n [pageIndex]=\"pageIndex()\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onPage($event)\"\n hidePageSize\n showFirstLastButtons\n >\n </mat-paginator>\n </section>\n</section>\n", styles: [".collapsed{max-height:0;overflow:hidden;transition:max-height .5s cubic-bezier(.4,0,.2,1)}.expanded{max-height:1000px}:host{display:block;padding:1rem}.invoice-index-page{display:flex;flex-direction:column;gap:1rem}.invoice-index-page__hero,.invoice-index-page__filters,.invoice-index-page__list{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-index-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-index-page__copy{display:flex;flex-direction:column;gap:.75rem}.invoice-index-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-index-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-index-page__description{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-index-page__stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.85rem}.invoice-index-page__stat{display:flex;flex-direction:column;gap:.2rem;padding:.95rem 1rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.1rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 88%,var(--rt-brand-color) 12%)}.invoice-index-page__stat-value{color:var(--rt-text-primary);font-size:1.2rem;font-weight:700}.invoice-index-page__stat-label,.invoice-index-page__stat-hint{color:var(--rt-text-secondary);font-size:.84rem}.invoice-index-page__filters,.invoice-index-page__list{display:flex;flex-direction:column;gap:1rem;padding:1rem 1.1rem}.invoice-index-page__status-nav{display:flex;flex-wrap:wrap;gap:.65rem}.invoice-index-page__status-link{display:inline-flex;align-items:center;justify-content:center;min-height:2.75rem;border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:9999px;padding:.55rem .95rem;color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-index-page__status-link:hover,.invoice-index-page__status-link--active{border-color:color-mix(in srgb,var(--rt-brand-color) 24%,var(--rt-border-color, rgba(15, 23, 42, .08)));background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color)}.invoice-index-page__filter-grid{display:grid;gap:.85rem}.invoice-index-page__filter-grid mat-form-field{width:100%}.invoice-index-page__filter-actions{display:flex;flex-wrap:wrap;gap:.75rem}.invoice-index-page__empty{display:flex;flex-direction:column;justify-content:center;min-height:10rem;gap:.45rem;padding:1.25rem;border:1px dashed var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.35rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 92%,var(--rt-brand-color) 8%)}.invoice-index-page__empty h3{margin:0;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-index-page__empty p{margin:0;color:var(--rt-text-secondary);line-height:1.65}@media(min-width:900px){.invoice-index-page__hero{grid-template-columns:minmax(0,1.6fr) minmax(19rem,.95fr);align-items:start}.invoice-index-page__filter-grid{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"] }]
1906
+ }] });
1907
+
1908
+ class MarketInvoiceDetail extends BaseComponent {
1909
+ constructor() {
1910
+ super(...arguments);
1911
+ this.invoiceService = inject(InvoiceService);
1912
+ this.paymentService = inject(PaymentService);
1913
+ this.invoice = signal(null, ...(ngDevMode ? [{ debugName: "invoice" }] : /* istanbul ignore next */ []));
1914
+ this.status = InvoiceStatus;
1915
+ this.paying = false;
1916
+ this.loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
1917
+ this.pageMeta = {
1918
+ baseLink: this.readRouteData('invoiceBaseLink', '/invoices'),
1919
+ collectionTitle: this.readRouteData('invoiceCollectionTitle', 'Invoices'),
1920
+ eyebrow: this.readRouteData('invoiceEyebrow', 'Billing workspace'),
1921
+ };
1922
+ this.breadcrumbs = computed(() => [
1923
+ { label: 'Invoices', link: '/properties/invoices' },
1924
+ { label: 'Invoice detail' },
1925
+ ], ...(ngDevMode ? [{ debugName: "breadcrumbs" }] : /* istanbul ignore next */ []));
1926
+ }
1927
+ ngOnInit() {
1928
+ this.route.params.subscribe((params) => {
1929
+ const id = params['id'];
1930
+ this.get(id);
1931
+ });
1932
+ this.route.queryParams.subscribe(async (params) => {
1933
+ const sessionId = params['session_id'];
1934
+ if (sessionId) {
1935
+ // this.invoiceService.checkOfferPaymentStatus(this.id, sessionId).subscribe({
1936
+ // next: (res) => {
1937
+ // if (res.status === 'paid') {
1938
+ // this.invoice.update((state) => {
1939
+ // if (!state) return state;
1940
+ // state.status = InvoiceStatus.PAID;
1941
+ // return state;
1942
+ // });
1943
+ // }
1944
+ // },
1945
+ // });
1946
+ }
1947
+ });
1948
+ }
1949
+ get(id) {
1950
+ this.loading.set(true);
1951
+ this.invoiceService.getInvoice(id).subscribe({
1952
+ next: (res) => {
1953
+ this.invoice.set(res.data);
1954
+ this.loading.set(false);
1955
+ },
1956
+ error: () => {
1957
+ this.loading.set(false);
1958
+ },
1959
+ });
1960
+ }
1961
+ pay() {
1962
+ this.paying = true;
1963
+ const data = {
1964
+ businessType: 'INVOICE',
1965
+ businessId: this.id,
1966
+ provider: 'STRIPE',
1967
+ method: 'STRIPE_CHECKOUT',
1968
+ };
1969
+ this.paymentService
1970
+ .createPaymentIntent(data)
1971
+ .pipe(switchMap((res) => {
1972
+ const intent = {
1973
+ intentId: res.data.id,
1974
+ provider: 'STRIPE',
1975
+ method: 'STRIPE_CHECKOUT',
1976
+ successUrl: window.location.href + '?session_id={CHECKOUT_SESSION_ID}',
1977
+ cancelUrl: window.location.href,
1978
+ };
1979
+ return this.paymentService.createPayment(intent);
1980
+ }))
1981
+ .subscribe({
1982
+ next: (res) => {
1983
+ this.paying = false;
1984
+ const { checkoutUrl } = res.data;
1985
+ window.open(checkoutUrl, '_blank');
1986
+ },
1987
+ error: (error) => {
1988
+ this.paying = false;
1989
+ this.snackBarService.open(error.message);
1990
+ },
1991
+ });
1992
+ }
1993
+ statusToneClass(status) {
1994
+ switch (status) {
1995
+ case InvoiceStatus.PAID:
1996
+ return 'invoice-detail-page__status invoice-detail-page__status--paid';
1997
+ case InvoiceStatus.ISSUED:
1998
+ case InvoiceStatus.SENT:
1999
+ case InvoiceStatus.PARTIALLY_PAID:
2000
+ return 'invoice-detail-page__status invoice-detail-page__status--issued';
2001
+ case InvoiceStatus.VOID:
2002
+ return 'invoice-detail-page__status invoice-detail-page__status--void';
2003
+ default:
2004
+ return 'invoice-detail-page__status invoice-detail-page__status--neutral';
2005
+ }
2006
+ }
2007
+ readRouteData(key, fallback) {
2008
+ for (const snapshot of [...this.route.snapshot.pathFromRoot].reverse()) {
2009
+ const value = snapshot.data?.[key];
2010
+ if (typeof value === 'string' && value.length > 0) {
2011
+ return value;
2012
+ }
2013
+ }
2014
+ return fallback;
2015
+ }
2016
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarketInvoiceDetail, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2017
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MarketInvoiceDetail, isStandalone: true, selector: "rolatech-market-invoice-detail", usesInheritance: true, ngImport: i0, template: "<section class=\"invoice-detail-page\">\n <rolatech-breadcrumb [items]=\"breadcrumbs()\"></rolatech-breadcrumb>\n @if (loading()) {\n <section class=\"invoice-detail-page__hero invoice-detail-page__hero--loading\">\n <div class=\"invoice-detail-page__hero-copy\">\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">Loading invoice...</h1>\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user-skeleton></rolatech-invoice-user-skeleton>\n <rolatech-invoice-lines-skeleton></rolatech-invoice-lines-skeleton>\n </div>\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary-skeleton></rolatech-invoice-summary-skeleton>\n </div>\n </section>\n } @else if (invoice(); as invoice) {\n <section class=\"invoice-detail-page__hero\">\n <div class=\"invoice-detail-page__hero-copy\">\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">Invoice detail</h1>\n <h1 class=\"invoice-detail-page__title\"></h1>\n <p class=\"invoice-detail-page__description\">#{{ invoice.invoiceNumber || invoice.id }}</p>\n <p class=\"invoice-detail-page__description\">\n Invoice for {{ invoice.fullName || invoice.firstName + ' ' + invoice.lastName }} created {{ invoice.createdAt | date:\n 'mediumDate' }}.\n </p>\n </div>\n\n <div class=\"invoice-detail-page__hero-side\">\n <span [class]=\"statusToneClass(invoice.status)\">{{ status[invoice.status] }}</span>\n <div class=\"invoice-detail-page__total\">{{ invoice.total | price }}</div>\n <div class=\"invoice-detail-page__note\">\n @if (invoice.dueAt) { Due {{ invoice.dueAt | date: 'mediumDate' }} } @else { Payable on receipt }\n </div>\n\n @if (invoice.status.toString() === 'ISSUED' || invoice.status.toString() === 'SENT') {\n <button mat-flat-button [disabled]=\"paying\" class=\"invoice-detail-page__cta\" (click)=\"pay()\">\n {{ paying ? 'Processing payment...' : 'Pay invoice' }}\n </button>\n }\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user\n [firstName]=\"invoice.firstName\"\n [lastName]=\"invoice.lastName\"\n [email]=\"invoice.email\"\n [phone]=\"invoice.phone\"\n ></rolatech-invoice-user>\n\n @if (invoice.lines; as lines) {\n <rolatech-invoice-lines [lines]=\"lines\"></rolatech-invoice-lines>\n }\n </div>\n\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary\n [tax]=\"invoice.vatTotal\"\n [credit]=\"invoice.holdingDepositApplied\"\n [subtotal]=\"invoice.subtotal\"\n [total]=\"invoice.total\"\n ></rolatech-invoice-summary>\n\n <article class=\"invoice-detail-page__panel\">\n <h2 class=\"invoice-detail-page__panel-title\">Invoice note</h2>\n <p class=\"invoice-detail-page__panel-copy\">{{ invoice.note || 'No note added for this invoice.' }}</p>\n\n @if (invoice.status.toString() === 'CREATED' || invoice.status.toString() === 'PAID') {\n <div class=\"invoice-detail-page__panel-row\">\n <span>Payment method</span>\n <strong>Stripe</strong>\n </div>\n }\n </article>\n </div>\n </section>\n }\n</section>\n", styles: [":host{display:block;padding:1rem;--rt-workspace-status-issued-surface: color-mix(in srgb, var(--rt-brand-color) 14%, transparent);--rt-workspace-status-issued-color: color-mix(in srgb, var(--rt-brand-color) 82%, var(--rt-text-primary) 18%);--rt-workspace-status-paid-surface: color-mix(in srgb, var(--rt-brand-color) 16%, var(--rt-base-background, #ffffff));--rt-workspace-status-paid-color: color-mix(in srgb, var(--rt-brand-color) 58%, var(--rt-text-primary) 42%)}.invoice-detail-page{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__hero,.invoice-detail-page__panel{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-detail-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-detail-page__hero-copy,.invoice-detail-page__hero-side,.invoice-detail-page__main,.invoice-detail-page__side{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__back{color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-detail-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-detail-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-detail-page__description,.invoice-detail-page__note,.invoice-detail-page__panel-copy{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-detail-page__status{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.45rem .82rem;font-size:.8rem;font-weight:700}.invoice-detail-page__status--neutral{background:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-brand-color)}.invoice-detail-page__status--issued{background:var(--rt-workspace-status-issued-surface);color:var(--rt-workspace-status-issued-color)}.invoice-detail-page__status--paid{background:var(--rt-workspace-status-paid-surface);color:var(--rt-workspace-status-paid-color)}.invoice-detail-page__status--void{background:color-mix(in srgb,var(--mat-sys-error, #b91c1c) 14%,transparent);color:var(--mat-sys-error, #b91c1c)}.invoice-detail-page__total{color:var(--rt-text-primary);font-size:clamp(1.8rem,2.4vw,2.3rem);font-weight:800}.invoice-detail-page__cta{min-height:3rem;border-radius:9999px}.invoice-detail-page__content{display:grid;gap:1rem}.invoice-detail-page__panel{padding:1rem 1.1rem}.invoice-detail-page__panel-title{margin:0 0 .6rem;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-detail-page__panel-row{display:flex;justify-content:space-between;gap:1rem;margin-top:1rem;color:var(--rt-text-secondary)}.invoice-detail-page__panel-row strong{color:var(--rt-text-primary)}@media(min-width:1024px){.invoice-detail-page__hero{grid-template-columns:minmax(0,1.65fr) minmax(18rem,.85fr);align-items:start}.invoice-detail-page__content{grid-template-columns:minmax(0,1.65fr) minmax(20rem,.85fr);align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: InvoiceUser, selector: "rolatech-invoice-user", inputs: ["firstName", "lastName", "email", "phone"] }, { kind: "component", type: InvoiceLines, selector: "rolatech-invoice-lines", inputs: ["lines"] }, { kind: "component", type: InvoiceSummary, selector: "rolatech-invoice-summary", inputs: ["tax", "credit", "subtotal", "total"] }, { kind: "component", type: InvoiceUserSkeleton, selector: "rolatech-invoice-user-skeleton" }, { kind: "component", type: InvoiceSummarySkeleton, selector: "rolatech-invoice-summary-skeleton" }, { kind: "component", type: InvoiceLinesSkeleton, selector: "rolatech-invoice-lines-skeleton" }, { kind: "component", type: Breadcrumb, selector: "rolatech-breadcrumb", inputs: ["items"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: PricePipe, name: "price" }] }); }
2018
+ }
2019
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarketInvoiceDetail, decorators: [{
2020
+ type: Component,
2021
+ args: [{ selector: 'rolatech-market-invoice-detail', imports: [
2022
+ CommonModule,
2023
+ RouterModule,
2024
+ MatButtonModule,
2025
+ MatIconModule,
2026
+ InvoiceUser,
2027
+ InvoiceLines,
2028
+ InvoiceSummary,
2029
+ InvoiceUserSkeleton,
2030
+ InvoiceSummarySkeleton,
2031
+ InvoiceLinesSkeleton,
2032
+ PricePipe,
2033
+ Breadcrumb,
2034
+ ], template: "<section class=\"invoice-detail-page\">\n <rolatech-breadcrumb [items]=\"breadcrumbs()\"></rolatech-breadcrumb>\n @if (loading()) {\n <section class=\"invoice-detail-page__hero invoice-detail-page__hero--loading\">\n <div class=\"invoice-detail-page__hero-copy\">\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">Loading invoice...</h1>\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user-skeleton></rolatech-invoice-user-skeleton>\n <rolatech-invoice-lines-skeleton></rolatech-invoice-lines-skeleton>\n </div>\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary-skeleton></rolatech-invoice-summary-skeleton>\n </div>\n </section>\n } @else if (invoice(); as invoice) {\n <section class=\"invoice-detail-page__hero\">\n <div class=\"invoice-detail-page__hero-copy\">\n <span class=\"invoice-detail-page__eyebrow\">{{ pageMeta.eyebrow }}</span>\n <h1 class=\"invoice-detail-page__title\">Invoice detail</h1>\n <h1 class=\"invoice-detail-page__title\"></h1>\n <p class=\"invoice-detail-page__description\">#{{ invoice.invoiceNumber || invoice.id }}</p>\n <p class=\"invoice-detail-page__description\">\n Invoice for {{ invoice.fullName || invoice.firstName + ' ' + invoice.lastName }} created {{ invoice.createdAt | date:\n 'mediumDate' }}.\n </p>\n </div>\n\n <div class=\"invoice-detail-page__hero-side\">\n <span [class]=\"statusToneClass(invoice.status)\">{{ status[invoice.status] }}</span>\n <div class=\"invoice-detail-page__total\">{{ invoice.total | price }}</div>\n <div class=\"invoice-detail-page__note\">\n @if (invoice.dueAt) { Due {{ invoice.dueAt | date: 'mediumDate' }} } @else { Payable on receipt }\n </div>\n\n @if (invoice.status.toString() === 'ISSUED' || invoice.status.toString() === 'SENT') {\n <button mat-flat-button [disabled]=\"paying\" class=\"invoice-detail-page__cta\" (click)=\"pay()\">\n {{ paying ? 'Processing payment...' : 'Pay invoice' }}\n </button>\n }\n </div>\n </section>\n\n <section class=\"invoice-detail-page__content\">\n <div class=\"invoice-detail-page__main\">\n <rolatech-invoice-user\n [firstName]=\"invoice.firstName\"\n [lastName]=\"invoice.lastName\"\n [email]=\"invoice.email\"\n [phone]=\"invoice.phone\"\n ></rolatech-invoice-user>\n\n @if (invoice.lines; as lines) {\n <rolatech-invoice-lines [lines]=\"lines\"></rolatech-invoice-lines>\n }\n </div>\n\n <div class=\"invoice-detail-page__side\">\n <rolatech-invoice-summary\n [tax]=\"invoice.vatTotal\"\n [credit]=\"invoice.holdingDepositApplied\"\n [subtotal]=\"invoice.subtotal\"\n [total]=\"invoice.total\"\n ></rolatech-invoice-summary>\n\n <article class=\"invoice-detail-page__panel\">\n <h2 class=\"invoice-detail-page__panel-title\">Invoice note</h2>\n <p class=\"invoice-detail-page__panel-copy\">{{ invoice.note || 'No note added for this invoice.' }}</p>\n\n @if (invoice.status.toString() === 'CREATED' || invoice.status.toString() === 'PAID') {\n <div class=\"invoice-detail-page__panel-row\">\n <span>Payment method</span>\n <strong>Stripe</strong>\n </div>\n }\n </article>\n </div>\n </section>\n }\n</section>\n", styles: [":host{display:block;padding:1rem;--rt-workspace-status-issued-surface: color-mix(in srgb, var(--rt-brand-color) 14%, transparent);--rt-workspace-status-issued-color: color-mix(in srgb, var(--rt-brand-color) 82%, var(--rt-text-primary) 18%);--rt-workspace-status-paid-surface: color-mix(in srgb, var(--rt-brand-color) 16%, var(--rt-base-background, #ffffff));--rt-workspace-status-paid-color: color-mix(in srgb, var(--rt-brand-color) 58%, var(--rt-text-primary) 42%)}.invoice-detail-page{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__hero,.invoice-detail-page__panel{border:1px solid var(--rt-border-color, rgba(15, 23, 42, .08));border-radius:1.5rem;background:color-mix(in srgb,var(--rt-raised-background, #ffffff) 96%,transparent);box-shadow:0 20px 48px -42px color-mix(in srgb,var(--rt-text-primary) 22%,transparent)}.invoice-detail-page__hero{display:grid;gap:1rem;padding:1.25rem;background:radial-gradient(circle at top left,color-mix(in srgb,var(--rt-brand-color) 14%,transparent),transparent 48%),linear-gradient(135deg,color-mix(in srgb,var(--rt-raised-background, #ffffff) 94%,transparent),color-mix(in srgb,var(--rt-base-background, #ffffff) 88%,var(--rt-brand-color) 12%)),var(--rt-base-background, #ffffff)}.invoice-detail-page__hero-copy,.invoice-detail-page__hero-side,.invoice-detail-page__main,.invoice-detail-page__side{display:flex;flex-direction:column;gap:1rem}.invoice-detail-page__back{color:var(--rt-text-secondary);font-weight:600;text-decoration:none}.invoice-detail-page__eyebrow{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.38rem .72rem;background:color-mix(in srgb,var(--rt-brand-color) 12%,transparent);color:var(--rt-brand-color);font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.invoice-detail-page__title{margin:0;color:var(--rt-text-primary);font-size:clamp(1.8rem,2.8vw,2.7rem);line-height:1.05;font-weight:800}.invoice-detail-page__description,.invoice-detail-page__note,.invoice-detail-page__panel-copy{margin:0;color:var(--rt-text-secondary);line-height:1.7}.invoice-detail-page__status{display:inline-flex;align-self:flex-start;border-radius:9999px;padding:.45rem .82rem;font-size:.8rem;font-weight:700}.invoice-detail-page__status--neutral{background:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-brand-color)}.invoice-detail-page__status--issued{background:var(--rt-workspace-status-issued-surface);color:var(--rt-workspace-status-issued-color)}.invoice-detail-page__status--paid{background:var(--rt-workspace-status-paid-surface);color:var(--rt-workspace-status-paid-color)}.invoice-detail-page__status--void{background:color-mix(in srgb,var(--mat-sys-error, #b91c1c) 14%,transparent);color:var(--mat-sys-error, #b91c1c)}.invoice-detail-page__total{color:var(--rt-text-primary);font-size:clamp(1.8rem,2.4vw,2.3rem);font-weight:800}.invoice-detail-page__cta{min-height:3rem;border-radius:9999px}.invoice-detail-page__content{display:grid;gap:1rem}.invoice-detail-page__panel{padding:1rem 1.1rem}.invoice-detail-page__panel-title{margin:0 0 .6rem;color:var(--rt-text-primary);font-size:1.05rem;font-weight:700}.invoice-detail-page__panel-row{display:flex;justify-content:space-between;gap:1rem;margin-top:1rem;color:var(--rt-text-secondary)}.invoice-detail-page__panel-row strong{color:var(--rt-text-primary)}@media(min-width:1024px){.invoice-detail-page__hero{grid-template-columns:minmax(0,1.65fr) minmax(18rem,.85fr);align-items:start}.invoice-detail-page__content{grid-template-columns:minmax(0,1.65fr) minmax(20rem,.85fr);align-items:start}}@media(min-width:768px){:host{padding:1.25rem}}\n"] }]
2035
+ }] });
2036
+
2037
+ const marketInvoiceRoutes = [
2038
+ {
2039
+ path: '',
2040
+ component: MarketInvoiceIndex,
2041
+ },
2042
+ {
2043
+ path: ':id',
2044
+ component: MarketInvoiceDetail,
2045
+ },
2046
+ ];
2047
+
1732
2048
  /**
1733
2049
  * Generated bundle index. Do not edit.
1734
2050
  */
1735
2051
 
1736
- export { BILLING_PROFILE_ROUTES, BillingProfileFacade, agentInvoiceRoutes, billingRoutes, invoiceManageRoutes, invoiceRoutes };
2052
+ export { BILLING_PROFILE_ROUTES, BillingProfileFacade, agentInvoiceRoutes, billingRoutes, invoiceManageRoutes, invoiceRoutes, marketInvoiceRoutes };
1737
2053
  //# sourceMappingURL=rolatech-angular-billing.mjs.map