@metrifox/angular-sdk 0.0.2-beta.1 → 0.0.2-beta.3

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.
Files changed (23) hide show
  1. package/README.md +310 -320
  2. package/dist/README.md +310 -320
  3. package/dist/fesm2022/index.mjs +1568 -1320
  4. package/dist/lib/metrifox.service.d.ts +5 -5
  5. package/dist/lib/types/enum.d.ts +4 -2
  6. package/dist/lib/types/interface.d.ts +5 -0
  7. package/dist/modules/customer-portal/components/billing-history.component.d.ts +3 -2
  8. package/dist/modules/customer-portal/components/credit/credit-balance-section.component.d.ts +12 -10
  9. package/dist/modules/customer-portal/components/customer-portal.component.d.ts +15 -10
  10. package/dist/modules/customer-portal/components/entitlements/entitlement-summary.component.d.ts +15 -0
  11. package/dist/modules/customer-portal/components/entitlements/entitlement-usage.component.d.ts +35 -0
  12. package/dist/modules/customer-portal/components/entitlements/entitlements-section.component.d.ts +5 -21
  13. package/dist/modules/customer-portal/components/invoice-preview.component.d.ts +8 -7
  14. package/dist/modules/customer-portal/components/payment.component.d.ts +4 -3
  15. package/dist/modules/customer-portal/components/plan/plans-section.component.d.ts +28 -26
  16. package/dist/modules/customer-portal/components/subscription/subscription-details.component.d.ts +12 -0
  17. package/dist/modules/customer-portal/components/subscription/subscription-items.component.d.ts +27 -0
  18. package/dist/modules/customer-portal/components/subscription/subscription-section.component.d.ts +5 -25
  19. package/dist/modules/pricing-table/components/pricing-table.component.d.ts +13 -7
  20. package/dist/modules/pricing-table/utils/defaults.d.ts +2 -0
  21. package/dist/public-api.d.ts +10 -10
  22. package/dist/styles.css +1 -1
  23. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, Injectable, EventEmitter, inject, Output, Input, ChangeDetectionStrategy, Component, computed, NgModule } from '@angular/core';
2
+ import { signal, Injectable, EventEmitter, Output, Input, ChangeDetectionStrategy, Component, inject, computed, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/common/http';
4
4
  import { HttpHeaders, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
5
5
  import { BehaviorSubject, throwError, Subject, takeUntil, forkJoin } from 'rxjs';
@@ -175,6 +175,9 @@ function customerPortalThemeToCssVars(theme) {
175
175
  // Plan Button
176
176
  s(vars, '--pt-button-bg', theme.plans?.planButton?.background);
177
177
  s(vars, '--pt-button-text', theme.plans?.planButton?.textColor);
178
+ s(vars, '--pt-button-secondary-bg', theme.plans?.planButton?.secondaryBackground);
179
+ s(vars, '--pt-button-secondary-text', theme.plans?.planButton?.secondaryTextColor);
180
+ s(vars, '--pt-button-link', theme.plans?.planButton?.textButtonColor);
178
181
  // Plan Toggle
179
182
  s(vars, '--pt-interval-bg', theme.plans?.planToggle?.background);
180
183
  s(vars, '--pt-interval-active-bg', theme.plans?.planToggle?.activeBackground);
@@ -269,8 +272,8 @@ function getGradient(theme) {
269
272
  const gradientColor = theme.plans?.currentPlanCard?.gradientColor;
270
273
  return {
271
274
  gradient: {
272
- 100: `linear-gradient(180deg, ${gradientColor} 4.81%, rgba(222, 247, 100, 0) 42.31%)`,
273
- },
275
+ 100: `linear-gradient(180deg, ${gradientColor} 4.81%, rgba(222, 247, 100, 0) 42.31%)`
276
+ }
274
277
  };
275
278
  }
276
279
  /**
@@ -326,7 +329,7 @@ class MetrifoxService {
326
329
  const fullConfig = {
327
330
  ...config,
328
331
  baseUrl: config.baseUrl || DEFAULT_BASE_URL,
329
- webAppUrl: config.webAppUrl || DEFAULT_WEB_APP_URL,
332
+ webAppUrl: config.webAppUrl || DEFAULT_WEB_APP_URL
330
333
  };
331
334
  MetrifoxService._config.set(fullConfig);
332
335
  MetrifoxService._initialized.set(true);
@@ -397,7 +400,7 @@ class MetrifoxService {
397
400
  const clientKey = MetrifoxService.getClientKey();
398
401
  return new HttpHeaders({
399
402
  'x-client-key': clientKey,
400
- 'Content-Type': 'application/json',
403
+ 'Content-Type': 'application/json'
401
404
  });
402
405
  }
403
406
  /**
@@ -442,7 +445,7 @@ class MetrifoxService {
442
445
  return this.http
443
446
  .get(url, {
444
447
  headers: this.getHeaders(),
445
- params: params,
448
+ params: params
446
449
  })
447
450
  .pipe(map((response) => response.data), catchError(this.handleError));
448
451
  }
@@ -537,7 +540,7 @@ class MetrifoxService {
537
540
  const url = `${MetrifoxService.getBaseUrl()}/sdk/subscriptions/schedule-cancellation`;
538
541
  return this.http
539
542
  .post(url, { subscription_id: subscriptionId, ...options }, {
540
- headers: this.getHeaders(),
543
+ headers: this.getHeaders()
541
544
  })
542
545
  .pipe(map((response) => response.data), catchError(this.handleError));
543
546
  }
@@ -612,8 +615,8 @@ class MetrifoxService {
612
615
  params: {
613
616
  offering_key: params.offeringKey,
614
617
  ...(params.billingInterval && { billing_interval: params.billingInterval }),
615
- ...(params.customerKey && { customer_key: params.customerKey }),
616
- },
618
+ ...(params.customerKey && { customer_key: params.customerKey })
619
+ }
617
620
  })
618
621
  .pipe(map((response) => response.data.checkout_url), catchError(this.handleError));
619
622
  }
@@ -621,7 +624,7 @@ class MetrifoxService {
621
624
  * Build checkout URL manually
622
625
  */
623
626
  buildCheckoutUrl(checkoutUsername, offeringKey, options) {
624
- let url = `${MetrifoxService.getWebAppUrl()}/${checkoutUsername}/checkout/${offeringKey}`;
627
+ const url = `${MetrifoxService.getWebAppUrl()}/${checkoutUsername}/checkout/${offeringKey}`;
625
628
  const params = new URLSearchParams();
626
629
  if (options?.billingPeriod) {
627
630
  params.set('billing_period', options.billingPeriod);
@@ -644,7 +647,7 @@ class MetrifoxService {
644
647
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: MetrifoxService, decorators: [{
645
648
  type: Injectable,
646
649
  args: [{
647
- providedIn: 'root',
650
+ providedIn: 'root'
648
651
  }]
649
652
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
650
653
  /**
@@ -656,20 +659,20 @@ function metrifoxInit(config) {
656
659
  }
657
660
 
658
661
  const ICONS$1 = {
659
- money: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M17 21.25H7c-3.65 0-5.75-2.1-5.75-5.75v-7c0-3.65 2.1-5.75 5.75-5.75h10c3.65 0 5.75 2.1 5.75 5.75v7c0 3.65-2.1 5.75-5.75 5.75Zm-10-17c-2.86 0-4.25 1.39-4.25 4.25v7c0 2.86 1.39 4.25 4.25 4.25h10c2.86 0 4.25-1.39 4.25-4.25v-7c0-2.86-1.39-4.25-4.25-4.25H7Z"></path><path d="M12 15.75c-2.07 0-3.75-1.68-3.75-3.75 0-2.07 1.68-3.75 3.75-3.75 2.07 0 3.75 1.68 3.75 3.75 0 2.07-1.68 3.75-3.75 3.75Zm0-6c-1.24 0-2.25 1.01-2.25 2.25s1.01 2.25 2.25 2.25 2.25-1.01 2.25-2.25S13.24 9.75 12 9.75ZM5.5 15.25c-.41 0-.75-.34-.75-.75v-5c0-.41.34-.75.75-.75s.75.34.75.75v5c0 .41-.34.75-.75.75ZM18.5 15.25c-.41 0-.75-.34-.75-.75v-5c0-.41.34-.75.75-.75s.75.34.75.75v5c0 .41-.34.75-.75.75Z"></path></svg>`,
660
- cardReceive: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 8.5H14.5"/><path d="M6 16.5H8"/><path d="M10.5 16.5H14.5"/><path d="M22 12.03V16.11C22 19.62 21.11 20.5 17.56 20.5H6.44C2.89 20.5 2 19.62 2 16.11V7.89C2 4.38 2.89 3.5 6.44 3.5H14.5"/><path d="M20 3.5V9.5L22 7.5"/><path d="M20 9.5L18 7.5"/></svg>`,
661
- settings: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>`,
662
- settingsAlt: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>`,
663
- closeCircle: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2Zm3.36 12.3c.29.29.29.77 0 1.06-.15.15-.34.22-.53.22s-.38-.07-.53-.22l-2.3-2.3-2.3 2.3c-.15.15-.34.22-.53.22s-.38-.07-.53-.22a.754.754 0 0 1 0-1.06l2.3-2.3-2.3-2.3a.754.754 0 0 1 0-1.06c.29-.29.77-.29 1.06 0l2.3 2.3 2.3-2.3c.29-.29.77-.29 1.06 0 .29.29.29.77 0 1.06l-2.3 2.3 2.3 2.3Z"/></svg>`,
664
- walletEmpty: `<svg xmlns="http://www.w3.org/2000/svg" width="84" height="84" viewBox="0 0 24 24" fill="none" stroke="#9CA3AF" stroke-width="1"><path d="M18.04 13.55c-.42.41-.66 1-.6 1.63.09 1.08 1.08 1.87 2.16 1.87h1.9v1.19c0 2.07-1.69 3.76-3.76 3.76H6.26c-2.07 0-3.76-1.69-3.76-3.76v-6.73c0-2.07 1.69-3.76 3.76-3.76h11.48c2.07 0 3.76 1.69 3.76 3.76v1.44h-2.02c-.56 0-1.07.22-1.44.6Z"/><path d="M2.5 12.41V7.84c0-1.19.73-2.25 1.84-2.67l7.94-3a1.9 1.9 0 0 1 2.57 1.78v3.8"/><path d="M22.56 13.97v2.06c0 .55-.44 1-1 1.02h-1.96c-1.08 0-2.07-.79-2.16-1.87-.06-.63.18-1.22.6-1.63.37-.38.88-.6 1.44-.6h2.08c.56.02 1 .47 1 1.02Z"/><path d="M7 12h7"/></svg>`,
665
- noteEmpty: `<svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" viewBox="0 0 24 24" fill="none" stroke="#E5E5E5" stroke-width="1"><path d="M8 2v3M16 2v3M3.5 9.09h17M21 8.5V17c0 3-1.5 5-5 5H8c-3.5 0-5-2-5-5V8.5c0-3 1.5-5 5-5h8c3.5 0 5 2 5 5Z"/><path d="M15.695 13.7h.009M15.695 16.7h.009M11.995 13.7h.01M11.995 16.7h.01M8.294 13.7h.01M8.294 16.7h.01"/></svg>`,
666
- receipt: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M22 6V8.42C22 10 21 11 19.42 11H16V4.01C16 2.9 16.91 2 18.02 2C19.11 2.01 20.11 2.45 20.83 3.17C21.55 3.9 22 4.9 22 6Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 7V21C2 21.83 2.94 22.3 3.6 21.8L5.31 20.52C5.71 20.22 6.27 20.26 6.63 20.62L8.29 22.29C8.68 22.68 9.32 22.68 9.71 22.29L11.39 20.61C11.74 20.26 12.3 20.22 12.69 20.52L14.4 21.8C15.06 22.29 16 21.82 16 21V4C16 2.9 16.9 2 18 2H7H6C3 2 2 3.79 2 6V7Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M9 13.01H12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M9 9.01H12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M5.99609 13H6.00508" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M5.99609 9H6.00508" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
667
- radar: `<svg width="16" height="16" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.99967 3.33333C5.11301 2.5 6.49967 2 7.99967 2C11.6797 2 14.6663 4.98667 14.6663 8.66667C14.6663 12.3467 11.6797 15.3333 7.99967 15.3333C4.31967 15.3333 1.33301 12.3467 1.33301 8.66667C1.33301 7.46 1.653 6.32666 2.21967 5.34666L7.99967 8.66667" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
668
- arrowDown: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg>`,
669
- arrowDownRight: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7l10 10M17 7v10H7"/></svg>`,
670
- subtitle: `<svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M9.99967 15.1663H5.99967C2.37967 15.1663 0.833008 13.6197 0.833008 9.99967V5.99967C0.833008 2.37967 2.37967 0.833008 5.99967 0.833008H9.99967C13.6197 0.833008 15.1663 2.37967 15.1663 5.99967V9.99967C15.1663 13.6197 13.6197 15.1663 9.99967 15.1663ZM5.99967 1.83301C2.92634 1.83301 1.83301 2.92634 1.83301 5.99967V9.99967C1.83301 13.073 2.92634 14.1663 5.99967 14.1663H9.99967C13.073 14.1663 14.1663 13.073 14.1663 9.99967V5.99967C14.1663 2.92634 13.073 1.83301 9.99967 1.83301H5.99967Z"/><path d="M11.6669 11.8867H10.4336C10.1603 11.8867 9.93359 11.6601 9.93359 11.3867C9.93359 11.1134 10.1603 10.8867 10.4336 10.8867H11.6669C11.9403 10.8867 12.1669 11.1134 12.1669 11.3867C12.1669 11.6601 11.9403 11.8867 11.6669 11.8867Z"/><path d="M8.64634 11.8867H4.33301C4.05967 11.8867 3.83301 11.6601 3.83301 11.3867C3.83301 11.1134 4.05967 10.8867 4.33301 10.8867H8.64634C8.91967 10.8867 9.14634 11.1134 9.14634 11.3867C9.14634 11.6601 8.92634 11.8867 8.64634 11.8867Z"/><path d="M11.6671 9.37988H7.98047C7.70714 9.37988 7.48047 9.15322 7.48047 8.87988C7.48047 8.60655 7.70714 8.37988 7.98047 8.37988H11.6671C11.9405 8.37988 12.1671 8.60655 12.1671 8.87988C12.1671 9.15322 11.9405 9.37988 11.6671 9.37988Z"/><path d="M6.17967 9.37988H4.33301C4.05967 9.37988 3.83301 9.15322 3.83301 8.87988C3.83301 8.60655 4.05967 8.37988 4.33301 8.37988H6.17967C6.45301 8.37988 6.67967 8.60655 6.67967 8.87988C6.67967 9.15322 6.45301 9.37988 6.17967 9.37988Z"/></svg>`,
671
- subtitleLarge: `<svg width="40" height="40" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M9.99967 15.1663H5.99967C2.37967 15.1663 0.833008 13.6197 0.833008 9.99967V5.99967C0.833008 2.37967 2.37967 0.833008 5.99967 0.833008H9.99967C13.6197 0.833008 15.1663 2.37967 15.1663 5.99967V9.99967C15.1663 13.6197 13.6197 15.1663 9.99967 15.1663ZM5.99967 1.83301C2.92634 1.83301 1.83301 2.92634 1.83301 5.99967V9.99967C1.83301 13.073 2.92634 14.1663 5.99967 14.1663H9.99967C13.073 14.1663 14.1663 13.073 14.1663 9.99967V5.99967C14.1663 2.92634 13.073 1.83301 9.99967 1.83301H5.99967Z"/><path d="M11.6669 11.8867H10.4336C10.1603 11.8867 9.93359 11.6601 9.93359 11.3867C9.93359 11.1134 10.1603 10.8867 10.4336 10.8867H11.6669C11.9403 10.8867 12.1669 11.1134 12.1669 11.3867C12.1669 11.6601 11.9403 11.8867 11.6669 11.8867Z"/><path d="M8.64634 11.8867H4.33301C4.05967 11.8867 3.83301 11.6601 3.83301 11.3867C3.83301 11.1134 4.05967 10.8867 4.33301 10.8867H8.64634C8.91967 10.8867 9.14634 11.1134 9.14634 11.3867C9.14634 11.6601 8.92634 11.8867 8.64634 11.8867Z"/><path d="M11.6671 9.37988H7.98047C7.70714 9.37988 7.48047 9.15322 7.48047 8.87988C7.48047 8.60655 7.70714 8.37988 7.98047 8.37988H11.6671C11.9405 8.37988 12.1671 8.60655 12.1671 8.87988C12.1671 9.15322 11.9405 9.37988 11.6671 9.37988Z"/><path d="M6.17967 9.37988H4.33301C4.05967 9.37988 3.83301 9.15322 3.83301 8.87988C3.83301 8.60655 4.05967 8.37988 4.33301 8.37988H6.17967C6.45301 8.37988 6.67967 8.60655 6.67967 8.87988C6.67967 9.15322 6.45301 9.37988 6.17967 9.37988Z"/></svg>`,
672
- check: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`,
662
+ money: '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M17 21.25H7c-3.65 0-5.75-2.1-5.75-5.75v-7c0-3.65 2.1-5.75 5.75-5.75h10c3.65 0 5.75 2.1 5.75 5.75v7c0 3.65-2.1 5.75-5.75 5.75Zm-10-17c-2.86 0-4.25 1.39-4.25 4.25v7c0 2.86 1.39 4.25 4.25 4.25h10c2.86 0 4.25-1.39 4.25-4.25v-7c0-2.86-1.39-4.25-4.25-4.25H7Z"></path><path d="M12 15.75c-2.07 0-3.75-1.68-3.75-3.75 0-2.07 1.68-3.75 3.75-3.75 2.07 0 3.75 1.68 3.75 3.75 0 2.07-1.68 3.75-3.75 3.75Zm0-6c-1.24 0-2.25 1.01-2.25 2.25s1.01 2.25 2.25 2.25 2.25-1.01 2.25-2.25S13.24 9.75 12 9.75ZM5.5 15.25c-.41 0-.75-.34-.75-.75v-5c0-.41.34-.75.75-.75s.75.34.75.75v5c0 .41-.34.75-.75.75ZM18.5 15.25c-.41 0-.75-.34-.75-.75v-5c0-.41.34-.75.75-.75s.75.34.75.75v5c0 .41-.34.75-.75.75Z"></path></svg>',
663
+ cardReceive: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 8.5H14.5"/><path d="M6 16.5H8"/><path d="M10.5 16.5H14.5"/><path d="M22 12.03V16.11C22 19.62 21.11 20.5 17.56 20.5H6.44C2.89 20.5 2 19.62 2 16.11V7.89C2 4.38 2.89 3.5 6.44 3.5H14.5"/><path d="M20 3.5V9.5L22 7.5"/><path d="M20 9.5L18 7.5"/></svg>',
664
+ settings: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',
665
+ settingsAlt: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>',
666
+ closeCircle: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2Zm3.36 12.3c.29.29.29.77 0 1.06-.15.15-.34.22-.53.22s-.38-.07-.53-.22l-2.3-2.3-2.3 2.3c-.15.15-.34.22-.53.22s-.38-.07-.53-.22a.754.754 0 0 1 0-1.06l2.3-2.3-2.3-2.3a.754.754 0 0 1 0-1.06c.29-.29.77-.29 1.06 0l2.3 2.3 2.3-2.3c.29-.29.77-.29 1.06 0 .29.29.29.77 0 1.06l-2.3 2.3 2.3 2.3Z"/></svg>',
667
+ walletEmpty: '<svg xmlns="http://www.w3.org/2000/svg" width="84" height="84" viewBox="0 0 24 24" fill="none" stroke="#9CA3AF" stroke-width="1"><path d="M18.04 13.55c-.42.41-.66 1-.6 1.63.09 1.08 1.08 1.87 2.16 1.87h1.9v1.19c0 2.07-1.69 3.76-3.76 3.76H6.26c-2.07 0-3.76-1.69-3.76-3.76v-6.73c0-2.07 1.69-3.76 3.76-3.76h11.48c2.07 0 3.76 1.69 3.76 3.76v1.44h-2.02c-.56 0-1.07.22-1.44.6Z"/><path d="M2.5 12.41V7.84c0-1.19.73-2.25 1.84-2.67l7.94-3a1.9 1.9 0 0 1 2.57 1.78v3.8"/><path d="M22.56 13.97v2.06c0 .55-.44 1-1 1.02h-1.96c-1.08 0-2.07-.79-2.16-1.87-.06-.63.18-1.22.6-1.63.37-.38.88-.6 1.44-.6h2.08c.56.02 1 .47 1 1.02Z"/><path d="M7 12h7"/></svg>',
668
+ noteEmpty: '<svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" viewBox="0 0 24 24" fill="none" stroke="#E5E5E5" stroke-width="1"><path d="M8 2v3M16 2v3M3.5 9.09h17M21 8.5V17c0 3-1.5 5-5 5H8c-3.5 0-5-2-5-5V8.5c0-3 1.5-5 5-5h8c3.5 0 5 2 5 5Z"/><path d="M15.695 13.7h.009M15.695 16.7h.009M11.995 13.7h.01M11.995 16.7h.01M8.294 13.7h.01M8.294 16.7h.01"/></svg>',
669
+ receipt: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M22 6V8.42C22 10 21 11 19.42 11H16V4.01C16 2.9 16.91 2 18.02 2C19.11 2.01 20.11 2.45 20.83 3.17C21.55 3.9 22 4.9 22 6Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 7V21C2 21.83 2.94 22.3 3.6 21.8L5.31 20.52C5.71 20.22 6.27 20.26 6.63 20.62L8.29 22.29C8.68 22.68 9.32 22.68 9.71 22.29L11.39 20.61C11.74 20.26 12.3 20.22 12.69 20.52L14.4 21.8C15.06 22.29 16 21.82 16 21V4C16 2.9 16.9 2 18 2H7H6C3 2 2 3.79 2 6V7Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M9 13.01H12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M9 9.01H12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M5.99609 13H6.00508" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M5.99609 9H6.00508" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
670
+ radar: '<svg width="16" height="16" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.99967 3.33333C5.11301 2.5 6.49967 2 7.99967 2C11.6797 2 14.6663 4.98667 14.6663 8.66667C14.6663 12.3467 11.6797 15.3333 7.99967 15.3333C4.31967 15.3333 1.33301 12.3467 1.33301 8.66667C1.33301 7.46 1.653 6.32666 2.21967 5.34666L7.99967 8.66667" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
671
+ arrowDown: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg>',
672
+ arrowDownRight: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7l10 10M17 7v10H7"/></svg>',
673
+ subtitle: '<svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M9.99967 15.1663H5.99967C2.37967 15.1663 0.833008 13.6197 0.833008 9.99967V5.99967C0.833008 2.37967 2.37967 0.833008 5.99967 0.833008H9.99967C13.6197 0.833008 15.1663 2.37967 15.1663 5.99967V9.99967C15.1663 13.6197 13.6197 15.1663 9.99967 15.1663ZM5.99967 1.83301C2.92634 1.83301 1.83301 2.92634 1.83301 5.99967V9.99967C1.83301 13.073 2.92634 14.1663 5.99967 14.1663H9.99967C13.073 14.1663 14.1663 13.073 14.1663 9.99967V5.99967C14.1663 2.92634 13.073 1.83301 9.99967 1.83301H5.99967Z"/><path d="M11.6669 11.8867H10.4336C10.1603 11.8867 9.93359 11.6601 9.93359 11.3867C9.93359 11.1134 10.1603 10.8867 10.4336 10.8867H11.6669C11.9403 10.8867 12.1669 11.1134 12.1669 11.3867C12.1669 11.6601 11.9403 11.8867 11.6669 11.8867Z"/><path d="M8.64634 11.8867H4.33301C4.05967 11.8867 3.83301 11.6601 3.83301 11.3867C3.83301 11.1134 4.05967 10.8867 4.33301 10.8867H8.64634C8.91967 10.8867 9.14634 11.1134 9.14634 11.3867C9.14634 11.6601 8.92634 11.8867 8.64634 11.8867Z"/><path d="M11.6671 9.37988H7.98047C7.70714 9.37988 7.48047 9.15322 7.48047 8.87988C7.48047 8.60655 7.70714 8.37988 7.98047 8.37988H11.6671C11.9405 8.37988 12.1671 8.60655 12.1671 8.87988C12.1671 9.15322 11.9405 9.37988 11.6671 9.37988Z"/><path d="M6.17967 9.37988H4.33301C4.05967 9.37988 3.83301 9.15322 3.83301 8.87988C3.83301 8.60655 4.05967 8.37988 4.33301 8.37988H6.17967C6.45301 8.37988 6.67967 8.60655 6.67967 8.87988C6.67967 9.15322 6.45301 9.37988 6.17967 9.37988Z"/></svg>',
674
+ subtitleLarge: '<svg width="40" height="40" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M9.99967 15.1663H5.99967C2.37967 15.1663 0.833008 13.6197 0.833008 9.99967V5.99967C0.833008 2.37967 2.37967 0.833008 5.99967 0.833008H9.99967C13.6197 0.833008 15.1663 2.37967 15.1663 5.99967V9.99967C15.1663 13.6197 13.6197 15.1663 9.99967 15.1663ZM5.99967 1.83301C2.92634 1.83301 1.83301 2.92634 1.83301 5.99967V9.99967C1.83301 13.073 2.92634 14.1663 5.99967 14.1663H9.99967C13.073 14.1663 14.1663 13.073 14.1663 9.99967V5.99967C14.1663 2.92634 13.073 1.83301 9.99967 1.83301H5.99967Z"/><path d="M11.6669 11.8867H10.4336C10.1603 11.8867 9.93359 11.6601 9.93359 11.3867C9.93359 11.1134 10.1603 10.8867 10.4336 10.8867H11.6669C11.9403 10.8867 12.1669 11.1134 12.1669 11.3867C12.1669 11.6601 11.9403 11.8867 11.6669 11.8867Z"/><path d="M8.64634 11.8867H4.33301C4.05967 11.8867 3.83301 11.6601 3.83301 11.3867C3.83301 11.1134 4.05967 10.8867 4.33301 10.8867H8.64634C8.91967 10.8867 9.14634 11.1134 9.14634 11.3867C9.14634 11.6601 8.92634 11.8867 8.64634 11.8867Z"/><path d="M11.6671 9.37988H7.98047C7.70714 9.37988 7.48047 9.15322 7.48047 8.87988C7.48047 8.60655 7.70714 8.37988 7.98047 8.37988H11.6671C11.9405 8.37988 12.1671 8.60655 12.1671 8.87988C12.1671 9.15322 11.9405 9.37988 11.6671 9.37988Z"/><path d="M6.17967 9.37988H4.33301C4.05967 9.37988 3.83301 9.15322 3.83301 8.87988C3.83301 8.60655 4.05967 8.37988 4.33301 8.37988H6.17967C6.45301 8.37988 6.67967 8.60655 6.67967 8.87988C6.67967 9.15322 6.45301 9.37988 6.17967 9.37988Z"/></svg>',
675
+ check: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>'
673
676
  };
674
677
 
675
678
  const iconCache = new Map();
@@ -688,30 +691,30 @@ const defaultCustomerPortalTheme = {
688
691
  backgroundColor: '#ffffff',
689
692
  borderRadius: '16px',
690
693
  fontFamily: 'inherit',
691
- containerPadding: '24px',
694
+ containerPadding: '24px'
692
695
  },
693
696
  tabs: {
694
697
  tabBackground: '#ffffff',
695
698
  tabBorderColor: '#E4E4E7',
696
699
  activeTabBackground: '#3D3D3D',
697
700
  activeTabTextColor: '#ffffff',
698
- inactiveTabTextColor: '#71717A',
701
+ inactiveTabTextColor: '#71717A'
699
702
  },
700
703
  sections: {
701
704
  background: '#ffffff',
702
- padding: '0px',
705
+ padding: '16px',
703
706
  borderColor: 'transparent',
704
707
  borderRadius: '8px',
705
708
  emptyTextColor: '#A1A1AA',
706
709
  usage: {
707
710
  barColor: '#006FEE',
708
- trackColor: '#E4E4E7',
711
+ trackColor: '#E4E4E7'
709
712
  },
710
713
  content: {
711
714
  background: '#F4F4F5',
712
715
  padding: '24px',
713
716
  borderColor: '#E4E4E7',
714
- borderRadius: '8px',
717
+ borderRadius: '8px'
715
718
  },
716
719
  summaryBalance: {
717
720
  background: '#ffffff',
@@ -720,23 +723,23 @@ const defaultCustomerPortalTheme = {
720
723
  borderRadius: '8px',
721
724
  label: { fontSize: '13px', fontWeight: '500', color: '#71717A' },
722
725
  value: { fontSize: '20px', fontWeight: '700', color: '#52525B' },
723
- unit: { fontSize: '13px', fontWeight: '500', color: '#52525B' },
726
+ unit: { fontSize: '13px', fontWeight: '500', color: '#52525B' }
724
727
  },
725
728
  header: { fontSize: '16px', fontWeight: '600', color: '#52525B' },
726
729
  label: { fontSize: '13px', fontWeight: '500', color: '#71717A' },
727
- value: { fontSize: '16px', fontWeight: '500', color: '#52525B' },
730
+ value: { fontSize: '14px', fontWeight: '500', color: '#52525B' }
728
731
  },
729
732
  buttons: {
730
733
  primary: {
731
734
  backgroundColor: '#3D3D3D',
732
735
  border: { color: '#52525B', width: '1px', radius: '8px' },
733
- typography: { fontSize: '14px', fontWeight: '500', color: '#ffffff' },
736
+ typography: { fontSize: '14px', fontWeight: '500', color: '#ffffff' }
734
737
  },
735
738
  secondary: {
736
739
  backgroundColor: '#E4E4E7',
737
740
  border: { color: '#E4E4E7', width: '1px', radius: '8px' },
738
- typography: { fontSize: '13px', fontWeight: '500', color: '#3F3F46' },
739
- },
741
+ typography: { fontSize: '13px', fontWeight: '500', color: '#3F3F46' }
742
+ }
740
743
  },
741
744
  lineItems: {
742
745
  parentRow: {
@@ -744,17 +747,17 @@ const defaultCustomerPortalTheme = {
744
747
  borderColor: '#E4E4E7',
745
748
  typography: {
746
749
  label: { color: '#111827' },
747
- quantity: { color: '#71717A' },
748
- },
750
+ quantity: { color: '#71717A' }
751
+ }
749
752
  },
750
753
  childRow: {
751
754
  background: '#ffffff',
752
755
  borderColor: '#E4E4E7',
753
756
  typography: {
754
757
  label: { color: '#111827' },
755
- quantity: { color: '#71717A' },
756
- },
757
- },
758
+ quantity: { color: '#71717A' }
759
+ }
760
+ }
758
761
  },
759
762
  tables: {
760
763
  headerBackground: '#E4E4E7',
@@ -766,11 +769,11 @@ const defaultCustomerPortalTheme = {
766
769
  cellPadding: '1rem 0.75rem',
767
770
  expandIconColor: '#71717A',
768
771
  typography: {
769
- fontSize: '16px',
770
- fontWeight: '500',
771
- headerFontSize: '16px',
772
- headerFontWeight: '600',
773
- },
772
+ fontSize: '14px',
773
+ fontWeight: '400',
774
+ headerFontSize: '14px',
775
+ headerFontWeight: '500'
776
+ }
774
777
  },
775
778
  modals: {
776
779
  overlayColor: 'rgba(0, 0, 0, 0.4)',
@@ -787,14 +790,14 @@ const defaultCustomerPortalTheme = {
787
790
  backgroundColor: 'transparent',
788
791
  textColor: '#3F3F46',
789
792
  borderColor: '#E4E4E7',
790
- borderWidth: '1px',
791
- },
792
- },
793
+ borderWidth: '1px'
794
+ }
795
+ }
793
796
  },
794
797
  plans: {
795
798
  currentPlanCard: {
796
799
  header: { background: '#E4E4E7', textColor: '#111827' },
797
- gradientColor: '#E4E4E7',
800
+ gradientColor: '#E4E4E7'
798
801
  },
799
802
  planCards: {
800
803
  background: '#ffffff',
@@ -806,19 +809,25 @@ const defaultCustomerPortalTheme = {
806
809
  primaryTextColor: '#71717A',
807
810
  secondaryTextColor: '#A1A1AA',
808
811
  background: 'transparent',
809
- borderColor: 'transparent',
810
- },
812
+ borderColor: 'transparent'
813
+ }
811
814
  },
812
815
  planFeatures: { textColor: '#3F3F46', iconColor: '#0BB02F' },
813
- planButton: { background: '#3D3D3D', textColor: '#ffffff' },
816
+ planButton: {
817
+ background: '#3D3D3D',
818
+ textColor: '#ffffff',
819
+ secondaryBackground: '#E4E4E7',
820
+ secondaryTextColor: '#3F3F46',
821
+ textButtonColor: '#2563eb'
822
+ },
814
823
  planToggle: {
815
824
  background: '#E4E4E7',
816
825
  activeBackground: '#1f2937',
817
826
  activeText: '#ffffff',
818
- inactiveText: '#71717A',
827
+ inactiveText: '#71717A'
819
828
  },
820
- planTags: { freeTrialBackground: '#dbeafe', freeTrialText: '#1e40af' },
821
- },
829
+ planTags: { freeTrialBackground: '#dbeafe', freeTrialText: '#1e40af' }
830
+ }
822
831
  };
823
832
 
824
833
  function formatDate(dateString) {
@@ -874,7 +883,7 @@ function formatPriceAmount(amount) {
874
883
  function getResetIntervalLabel(interval) {
875
884
  const map = {
876
885
  daily: 'per day', weekly: 'per week', monthly: 'per month',
877
- quarterly: 'per quarter', yearly: 'per year', biannually: 'per 6 months',
886
+ quarterly: 'per quarter', yearly: 'per year', biannually: 'per 6 months'
878
887
  };
879
888
  return map[interval?.toLowerCase()] || interval;
880
889
  }
@@ -911,22 +920,342 @@ const DEFAULT_SECTION_LABELS = {
911
920
  entitlementUsage: 'Entitlements',
912
921
  paymentOverview: 'Payment',
913
922
  billingHistory: 'Billing history',
914
- plan: 'Plans',
923
+ plan: 'Plans'
915
924
  };
916
925
  function getSectionLabel(sectionsConfig, key) {
917
926
  const config = sectionsConfig?.find((s) => s.key === key);
918
927
  return config?.label || DEFAULT_SECTION_LABELS[key] || key;
919
928
  }
920
929
 
921
- class SubscriptionSectionComponent {
922
- subscription;
923
- sectionsConfig;
924
- customerKey = '';
925
- tenantCheckoutUsername = '';
930
+ class SubscriptionDetailsComponent {
931
+ sub;
926
932
  invoicePreview = new EventEmitter();
927
- managePlan = new EventEmitter();
933
+ _formatDate(d) {
934
+ return formatDate(d);
935
+ }
936
+ _formatCurrency(amount, currency) {
937
+ return formatCurrency(amount, currency);
938
+ }
939
+ _formatStatus(status) {
940
+ return formatStatus(status);
941
+ }
942
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: SubscriptionDetailsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
943
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: SubscriptionDetailsComponent, isStandalone: true, selector: "cp-subscription-details", inputs: { sub: "sub" }, outputs: { invoicePreview: "invoicePreview" }, ngImport: i0, template: `
944
+ <!-- Plan details content box -->
945
+ <div data-testid="subscription-content-box"
946
+ class="bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)]"
947
+ [style.padding]="'var(--cp-section-content-padding)'">
948
+ <div class="flex justify-between flex-wrap gap-6">
949
+ <div>
950
+ <span class="text-[var(--cp-section-label-color)]"
951
+ [style.fontSize]="'var(--cp-section-label-size)'"
952
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Current plan</span>
953
+ <div class="text-[var(--cp-section-value-color)] mt-2"
954
+ [style.fontSize]="'var(--cp-section-value-size)'"
955
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
956
+ {{ sub.plan_name || '-' }}
957
+ </div>
958
+ </div>
959
+ <div>
960
+ <span class="text-[var(--cp-section-label-color)]"
961
+ [style.fontSize]="'var(--cp-section-label-size)'"
962
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Status</span>
963
+ <div class="text-[var(--cp-section-value-color)] mt-2"
964
+ [style.fontSize]="'var(--cp-section-value-size)'"
965
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
966
+ {{ _formatStatus(sub.status) }}
967
+ </div>
968
+ </div>
969
+ <div>
970
+ <span class="text-[var(--cp-section-label-color)]"
971
+ [style.fontSize]="'var(--cp-section-label-size)'"
972
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Start date</span>
973
+ <div class="text-[var(--cp-section-value-color)] mt-2"
974
+ [style.fontSize]="'var(--cp-section-value-size)'"
975
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
976
+ {{ _formatDate(sub.starts_at) || '-' }}
977
+ </div>
978
+ </div>
979
+ @if (sub.status === 'active') {
980
+ <div>
981
+ <span class="text-[var(--cp-section-label-color)]"
982
+ [style.fontSize]="'var(--cp-section-label-size)'"
983
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Current billing period</span>
984
+ <div class="text-[var(--cp-section-value-color)] mt-2"
985
+ [style.fontSize]="'var(--cp-section-value-size)'"
986
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
987
+ @if (sub.current_billing_period_start && sub.current_billing_period_end) {
988
+ <div class="font-medium">{{ _formatDate(sub.current_billing_period_start) }} - {{ _formatDate(sub.current_billing_period_end) }}</div>
989
+ <div class="mt-1 text-sm opacity-80">(Auto-renew)</div>
990
+ } @else {
991
+ <span>-</span>
992
+ }
993
+ </div>
994
+ </div>
995
+ }
996
+ @if (sub.status === 'trialing' && sub.trial_end_date) {
997
+ <div>
998
+ <span class="text-[var(--cp-section-label-color)]"
999
+ [style.fontSize]="'var(--cp-section-label-size)'"
1000
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Trial end date</span>
1001
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1002
+ [style.fontSize]="'var(--cp-section-value-size)'"
1003
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1004
+ {{ _formatDate(sub.trial_end_date) }}
1005
+ </div>
1006
+ </div>
1007
+ <div>
1008
+ <span class="text-[var(--cp-section-label-color)]"
1009
+ [style.fontSize]="'var(--cp-section-label-size)'"
1010
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Trial period</span>
1011
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1012
+ [style.fontSize]="'var(--cp-section-value-size)'"
1013
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1014
+ {{ _formatDate(sub.starts_at) }} - {{ _formatDate(sub.trial_end_date) }}
1015
+ </div>
1016
+ </div>
1017
+ }
1018
+ @if (sub.status === 'active') {
1019
+ <div>
1020
+ <span class="text-[var(--cp-section-label-color)]"
1021
+ [style.fontSize]="'var(--cp-section-label-size)'"
1022
+ [style.fontWeight]="'var(--cp-section-label-weight)'">End date</span>
1023
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1024
+ [style.fontSize]="'var(--cp-section-value-size)'"
1025
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1026
+ {{ sub.ends_at ? _formatDate(sub.ends_at) : '-' }}
1027
+ </div>
1028
+ </div>
1029
+ }
1030
+ </div>
1031
+ </div>
1032
+
1033
+ <!-- Preview invoice link -->
1034
+ @if (sub.upcoming_invoice) {
1035
+ <div class="flex justify-end mt-2">
1036
+ <button type="button"
1037
+ class="text-[var(--cp-link-color,#3b82f6)] underline p-0 text-sm bg-transparent border-none cursor-pointer"
1038
+ (click)="$event.stopPropagation(); invoicePreview.emit(sub.upcoming_invoice!)">
1039
+ Preview invoice
1040
+ </button>
1041
+ </div>
1042
+ }
1043
+
1044
+ <!-- Billing details content box (active only) -->
1045
+ @if (sub.status === 'active') {
1046
+ <div data-testid="subscription-content-box"
1047
+ class="bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] mt-2"
1048
+ [style.padding]="'var(--cp-section-content-padding)'">
1049
+ <div class="flex justify-between flex-wrap gap-6">
1050
+ <div>
1051
+ <span class="text-[var(--cp-section-label-color)]"
1052
+ [style.fontSize]="'var(--cp-section-label-size)'"
1053
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Next billing date</span>
1054
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1055
+ [style.fontSize]="'var(--cp-section-value-size)'"
1056
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1057
+ {{ sub.renews_at ? _formatDate(sub.renews_at) : '-' }}
1058
+ </div>
1059
+ </div>
1060
+ <div>
1061
+ <span class="text-[var(--cp-section-label-color)]"
1062
+ [style.fontSize]="'var(--cp-section-label-size)'"
1063
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Invoice due</span>
1064
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1065
+ [style.fontSize]="'var(--cp-section-value-size)'"
1066
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1067
+ {{ sub.renews_at ? _formatDate(sub.renews_at) : '-' }}
1068
+ </div>
1069
+ </div>
1070
+ <div>
1071
+ <span class="text-[var(--cp-section-label-color)]"
1072
+ [style.fontSize]="'var(--cp-section-label-size)'"
1073
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Next estimated bill</span>
1074
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1075
+ [style.fontSize]="'var(--cp-section-value-size)'"
1076
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1077
+ @if (sub.next_billing_amount) {
1078
+ <div class="font-medium">{{ _formatCurrency(sub.next_billing_amount, sub.currency_code) }}</div>
1079
+ <div class="text-sm opacity-80 mt-0.5">(Monthly)</div>
1080
+ } @else {
1081
+ <span>-</span>
1082
+ }
1083
+ </div>
1084
+ </div>
1085
+ </div>
1086
+ </div>
1087
+ }
1088
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1089
+ }
1090
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: SubscriptionDetailsComponent, decorators: [{
1091
+ type: Component,
1092
+ args: [{
1093
+ selector: 'cp-subscription-details',
1094
+ standalone: true,
1095
+ imports: [CommonModule],
1096
+ changeDetection: ChangeDetectionStrategy.OnPush,
1097
+ template: `
1098
+ <!-- Plan details content box -->
1099
+ <div data-testid="subscription-content-box"
1100
+ class="bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)]"
1101
+ [style.padding]="'var(--cp-section-content-padding)'">
1102
+ <div class="flex justify-between flex-wrap gap-6">
1103
+ <div>
1104
+ <span class="text-[var(--cp-section-label-color)]"
1105
+ [style.fontSize]="'var(--cp-section-label-size)'"
1106
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Current plan</span>
1107
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1108
+ [style.fontSize]="'var(--cp-section-value-size)'"
1109
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1110
+ {{ sub.plan_name || '-' }}
1111
+ </div>
1112
+ </div>
1113
+ <div>
1114
+ <span class="text-[var(--cp-section-label-color)]"
1115
+ [style.fontSize]="'var(--cp-section-label-size)'"
1116
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Status</span>
1117
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1118
+ [style.fontSize]="'var(--cp-section-value-size)'"
1119
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1120
+ {{ _formatStatus(sub.status) }}
1121
+ </div>
1122
+ </div>
1123
+ <div>
1124
+ <span class="text-[var(--cp-section-label-color)]"
1125
+ [style.fontSize]="'var(--cp-section-label-size)'"
1126
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Start date</span>
1127
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1128
+ [style.fontSize]="'var(--cp-section-value-size)'"
1129
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1130
+ {{ _formatDate(sub.starts_at) || '-' }}
1131
+ </div>
1132
+ </div>
1133
+ @if (sub.status === 'active') {
1134
+ <div>
1135
+ <span class="text-[var(--cp-section-label-color)]"
1136
+ [style.fontSize]="'var(--cp-section-label-size)'"
1137
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Current billing period</span>
1138
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1139
+ [style.fontSize]="'var(--cp-section-value-size)'"
1140
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1141
+ @if (sub.current_billing_period_start && sub.current_billing_period_end) {
1142
+ <div class="font-medium">{{ _formatDate(sub.current_billing_period_start) }} - {{ _formatDate(sub.current_billing_period_end) }}</div>
1143
+ <div class="mt-1 text-sm opacity-80">(Auto-renew)</div>
1144
+ } @else {
1145
+ <span>-</span>
1146
+ }
1147
+ </div>
1148
+ </div>
1149
+ }
1150
+ @if (sub.status === 'trialing' && sub.trial_end_date) {
1151
+ <div>
1152
+ <span class="text-[var(--cp-section-label-color)]"
1153
+ [style.fontSize]="'var(--cp-section-label-size)'"
1154
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Trial end date</span>
1155
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1156
+ [style.fontSize]="'var(--cp-section-value-size)'"
1157
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1158
+ {{ _formatDate(sub.trial_end_date) }}
1159
+ </div>
1160
+ </div>
1161
+ <div>
1162
+ <span class="text-[var(--cp-section-label-color)]"
1163
+ [style.fontSize]="'var(--cp-section-label-size)'"
1164
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Trial period</span>
1165
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1166
+ [style.fontSize]="'var(--cp-section-value-size)'"
1167
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1168
+ {{ _formatDate(sub.starts_at) }} - {{ _formatDate(sub.trial_end_date) }}
1169
+ </div>
1170
+ </div>
1171
+ }
1172
+ @if (sub.status === 'active') {
1173
+ <div>
1174
+ <span class="text-[var(--cp-section-label-color)]"
1175
+ [style.fontSize]="'var(--cp-section-label-size)'"
1176
+ [style.fontWeight]="'var(--cp-section-label-weight)'">End date</span>
1177
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1178
+ [style.fontSize]="'var(--cp-section-value-size)'"
1179
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1180
+ {{ sub.ends_at ? _formatDate(sub.ends_at) : '-' }}
1181
+ </div>
1182
+ </div>
1183
+ }
1184
+ </div>
1185
+ </div>
1186
+
1187
+ <!-- Preview invoice link -->
1188
+ @if (sub.upcoming_invoice) {
1189
+ <div class="flex justify-end mt-2">
1190
+ <button type="button"
1191
+ class="text-[var(--cp-link-color,#3b82f6)] underline p-0 text-sm bg-transparent border-none cursor-pointer"
1192
+ (click)="$event.stopPropagation(); invoicePreview.emit(sub.upcoming_invoice!)">
1193
+ Preview invoice
1194
+ </button>
1195
+ </div>
1196
+ }
1197
+
1198
+ <!-- Billing details content box (active only) -->
1199
+ @if (sub.status === 'active') {
1200
+ <div data-testid="subscription-content-box"
1201
+ class="bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] mt-2"
1202
+ [style.padding]="'var(--cp-section-content-padding)'">
1203
+ <div class="flex justify-between flex-wrap gap-6">
1204
+ <div>
1205
+ <span class="text-[var(--cp-section-label-color)]"
1206
+ [style.fontSize]="'var(--cp-section-label-size)'"
1207
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Next billing date</span>
1208
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1209
+ [style.fontSize]="'var(--cp-section-value-size)'"
1210
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1211
+ {{ sub.renews_at ? _formatDate(sub.renews_at) : '-' }}
1212
+ </div>
1213
+ </div>
1214
+ <div>
1215
+ <span class="text-[var(--cp-section-label-color)]"
1216
+ [style.fontSize]="'var(--cp-section-label-size)'"
1217
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Invoice due</span>
1218
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1219
+ [style.fontSize]="'var(--cp-section-value-size)'"
1220
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1221
+ {{ sub.renews_at ? _formatDate(sub.renews_at) : '-' }}
1222
+ </div>
1223
+ </div>
1224
+ <div>
1225
+ <span class="text-[var(--cp-section-label-color)]"
1226
+ [style.fontSize]="'var(--cp-section-label-size)'"
1227
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Next estimated bill</span>
1228
+ <div class="text-[var(--cp-section-value-color)] mt-2"
1229
+ [style.fontSize]="'var(--cp-section-value-size)'"
1230
+ [style.fontWeight]="'var(--cp-section-value-weight)'">
1231
+ @if (sub.next_billing_amount) {
1232
+ <div class="font-medium">{{ _formatCurrency(sub.next_billing_amount, sub.currency_code) }}</div>
1233
+ <div class="text-sm opacity-80 mt-0.5">(Monthly)</div>
1234
+ } @else {
1235
+ <span>-</span>
1236
+ }
1237
+ </div>
1238
+ </div>
1239
+ </div>
1240
+ </div>
1241
+ }
1242
+ `
1243
+ }]
1244
+ }], propDecorators: { sub: [{
1245
+ type: Input,
1246
+ args: [{ required: true }]
1247
+ }], invoicePreview: [{
1248
+ type: Output
1249
+ }] } });
1250
+
1251
+ class SubscriptionItemsComponent {
928
1252
  expandedAddons = new Set();
929
- sanitizer = inject(DomSanitizer);
1253
+ items = [];
1254
+ canUpdateQuantities = false;
1255
+ tenantCheckoutUsername = '';
1256
+ customerKey = '';
1257
+ subscriptionId = '';
1258
+ offeringKey = '';
930
1259
  toggleAddon(key) {
931
1260
  if (this.expandedAddons.has(key)) {
932
1261
  this.expandedAddons.delete(key);
@@ -938,32 +1267,27 @@ class SubscriptionSectionComponent {
938
1267
  isAddonExpanded(key) {
939
1268
  return this.expandedAddons.has(key);
940
1269
  }
941
- openUpdateItems(subscription) {
942
- if (!this.tenantCheckoutUsername || !subscription?.subscription?.id || !subscription?.subscription?.offering_key)
1270
+ openUpdateItems() {
1271
+ if (!this.tenantCheckoutUsername || !this.subscriptionId || !this.offeringKey)
943
1272
  return;
944
- const updateQtyUrl = `${window.location.origin}/${this.tenantCheckoutUsername}/${subscription.subscription.offering_key}/subscriptions/${subscription.subscription.id}?customer=${this.customerKey}`;
1273
+ const updateQtyUrl = `${window.location.origin}/${this.tenantCheckoutUsername}/${this.offeringKey}/subscriptions/${this.subscriptionId}?customer=${this.customerKey}`;
945
1274
  window.open(updateQtyUrl, '_blank', 'noopener,noreferrer');
946
1275
  }
947
- handleManagePlan() {
948
- this.managePlan.emit(this.subscription);
949
- }
950
1276
  handleAddAddon() {
951
- const offeringKey = this.subscription?.subscription?.offering_key;
952
- const subscriptionId = this.subscription?.subscription?.id;
953
- if (!this.tenantCheckoutUsername || !offeringKey || !subscriptionId)
1277
+ if (!this.tenantCheckoutUsername || !this.offeringKey || !this.subscriptionId)
954
1278
  return;
955
1279
  const webAppUrl = 'https://app.metrifox.com';
956
- const url = `${webAppUrl}/${this.tenantCheckoutUsername}/${offeringKey}/addons?subscription=${subscriptionId}&manage=addon_add`;
1280
+ const url = `${webAppUrl}/${this.tenantCheckoutUsername}/${this.offeringKey}/addons?subscription=${this.subscriptionId}&manage=addon_add`;
957
1281
  window.open(url, '_blank', 'noopener,noreferrer');
958
1282
  }
959
- getPlanLineItems(items) {
960
- return (items || []).filter((item) => !item.is_addon);
1283
+ getPlanLineItems() {
1284
+ return (this.items || []).filter((item) => !item.is_addon);
961
1285
  }
962
- getAddonLineItems(items) {
963
- return (items || []).filter((item) => item.is_addon);
1286
+ getAddonLineItems() {
1287
+ return (this.items || []).filter((item) => item.is_addon);
964
1288
  }
965
- getGroupedAddonItems(items) {
966
- const addonItems = this.getAddonLineItems(items);
1289
+ getGroupedAddonItems() {
1290
+ const addonItems = this.getAddonLineItems();
967
1291
  const groups = new Map();
968
1292
  for (const item of addonItems) {
969
1293
  const key = item.offering_key || item.name || item.price_option_id;
@@ -977,666 +1301,427 @@ class SubscriptionSectionComponent {
977
1301
  return { key, name: baseItem?.name || key, baseItem, children };
978
1302
  });
979
1303
  }
980
- getStatusBgClass(status) {
981
- switch (status?.toLowerCase()) {
982
- case 'active': return 'bg-green-500';
983
- case 'trialing': return 'bg-blue-500';
984
- case 'canceled':
985
- case 'canceling': return 'bg-red-500';
986
- case 'past_due':
987
- case 'unpaid': return 'bg-yellow-500';
988
- case 'paused': return 'bg-gray-500';
989
- default: return 'bg-gray-500';
990
- }
991
- }
992
- _formatDate(d) {
993
- return formatDate(d);
994
- }
995
- _formatCurrency(amount, currency) {
996
- return formatCurrency(amount, currency);
997
- }
998
- _formatStatus(status) {
999
- return formatStatus(status);
1000
- }
1001
1304
  _capitalize(str) {
1002
1305
  return capitalize(str || '');
1003
1306
  }
1004
- _isSectionHidden(key) {
1005
- return isSectionHidden(this.sectionsConfig, key);
1006
- }
1007
- _getSectionLabel(key) {
1008
- return getSectionLabel(this.sectionsConfig, key);
1009
- }
1010
- _getIcon(name) {
1011
- return getIcon(this.sanitizer, name);
1307
+ _formatCurrency(amount, currency) {
1308
+ return formatCurrency(amount, currency);
1012
1309
  }
1013
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: SubscriptionSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1014
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: SubscriptionSectionComponent, isStandalone: true, selector: "cp-subscription-section", inputs: { subscription: "subscription", sectionsConfig: "sectionsConfig", customerKey: "customerKey", tenantCheckoutUsername: "tenantCheckoutUsername" }, outputs: { invoicePreview: "invoicePreview", managePlan: "managePlan" }, ngImport: i0, template: `
1015
- @if (!_isSectionHidden('subscription') && subscription?.subscription) {
1016
- <div class="w-full"
1017
- [style.padding]="'var(--cp-section-padding)'"
1018
- [style.backgroundColor]="'var(--cp-section-bg)'"
1019
- [style.borderColor]="'var(--cp-section-border)'"
1020
- [style.borderRadius]="'var(--cp-section-radius)'"
1021
- [style.borderWidth]="'1px'"
1022
- [style.borderStyle]="'solid'">
1023
- <!-- Header: title + Manage plan -->
1024
- <div class="flex justify-between items-center mb-4">
1310
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: SubscriptionItemsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1311
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: SubscriptionItemsComponent, isStandalone: true, selector: "cp-subscription-items", inputs: { items: "items", canUpdateQuantities: "canUpdateQuantities", tenantCheckoutUsername: "tenantCheckoutUsername", customerKey: "customerKey", subscriptionId: "subscriptionId", offeringKey: "offeringKey" }, ngImport: i0, template: `
1312
+ @if (items?.length) {
1313
+ <div class="mt-8">
1314
+ <div class="flex items-center justify-between mb-4">
1025
1315
  <span class="text-[var(--cp-section-header-color)]"
1026
1316
  [style.fontSize]="'var(--cp-section-header-size)'"
1027
1317
  [style.fontWeight]="'var(--cp-section-header-weight)'">
1028
- {{ _getSectionLabel('subscription') }}
1318
+ Subscription items
1029
1319
  </span>
1030
- @if (subscription.subscription.status !== 'canceled') {
1320
+ @if (canUpdateQuantities) {
1031
1321
  <button type="button"
1032
- class="bg-[var(--cp-btn-primary-bg)] text-[var(--cp-btn-primary-text)] border-[var(--cp-btn-primary-border)] rounded-[var(--cp-btn-primary-radius)] px-5 py-2"
1033
- [style.fontSize]="'var(--cp-btn-primary-size)'"
1034
- [style.fontWeight]="'var(--cp-btn-primary-weight)'"
1035
- [style.borderWidth]="'var(--cp-btn-primary-border-width, 1px)'"
1036
- [style.borderStyle]="'solid'"
1037
- (click)="handleManagePlan()">
1038
- Manage plan
1322
+ class="text-[var(--cp-link-color,#3b82f6)] underline p-0 font-medium bg-transparent border-none cursor-pointer"
1323
+ (click)="$event.stopPropagation(); openUpdateItems()">
1324
+ Manage item quantities
1039
1325
  </button>
1040
1326
  }
1041
1327
  </div>
1042
1328
 
1043
- <!-- Plan details content box -->
1044
- <div data-testid="subscription-content-box"
1045
- class="bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)]"
1329
+ <div data-testid="subscription-items-container"
1330
+ class="rounded-[var(--cp-section-content-radius)] overflow-hidden bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)]"
1046
1331
  [style.padding]="'var(--cp-section-content-padding)'">
1047
- <div class="flex justify-between flex-wrap gap-6">
1048
- <div>
1049
- <span class="text-[var(--cp-section-label-color)]"
1050
- [style.fontSize]="'var(--cp-section-label-size)'"
1051
- [style.fontWeight]="'var(--cp-section-label-weight)'">Current plan</span>
1052
- <div class="text-[var(--cp-section-value-color)] mt-2"
1053
- [style.fontSize]="'var(--cp-section-value-size)'"
1054
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1055
- {{ subscription.subscription.plan_name || '-' }}
1056
- </div>
1057
- </div>
1058
- <div>
1059
- <span class="text-[var(--cp-section-label-color)]"
1060
- [style.fontSize]="'var(--cp-section-label-size)'"
1061
- [style.fontWeight]="'var(--cp-section-label-weight)'">Status</span>
1062
- <div class="text-[var(--cp-section-value-color)] mt-2"
1063
- [style.fontSize]="'var(--cp-section-value-size)'"
1064
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1065
- {{ _formatStatus(subscription.subscription.status) }}
1066
- </div>
1067
- </div>
1068
- <div>
1332
+
1333
+ <!-- Plan items -->
1334
+ @if (getPlanLineItems().length > 0) {
1335
+ <div class="mb-3 mt-4">
1069
1336
  <span class="text-[var(--cp-section-label-color)]"
1070
1337
  [style.fontSize]="'var(--cp-section-label-size)'"
1071
- [style.fontWeight]="'var(--cp-section-label-weight)'">Start date</span>
1072
- <div class="text-[var(--cp-section-value-color)] mt-2"
1073
- [style.fontSize]="'var(--cp-section-value-size)'"
1074
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1075
- {{ _formatDate(subscription.subscription.starts_at) || '-' }}
1076
- </div>
1338
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Plan</span>
1077
1339
  </div>
1078
- @if (subscription.subscription.status === 'active') {
1079
- <div>
1080
- <span class="text-[var(--cp-section-label-color)]"
1081
- [style.fontSize]="'var(--cp-section-label-size)'"
1082
- [style.fontWeight]="'var(--cp-section-label-weight)'">Current billing period</span>
1083
- <div class="text-[var(--cp-section-value-color)] mt-2"
1084
- [style.fontSize]="'var(--cp-section-value-size)'"
1085
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1086
- @if (subscription.subscription.current_billing_period_start && subscription.subscription.current_billing_period_end) {
1087
- <div class="font-medium">{{ _formatDate(subscription.subscription.current_billing_period_start) }} - {{ _formatDate(subscription.subscription.current_billing_period_end) }}</div>
1088
- <div class="mt-1 text-sm opacity-80">(Auto-renew)</div>
1089
- } @else {
1090
- <span>-</span>
1091
- }
1092
- </div>
1093
- </div>
1094
- }
1095
- @if (subscription.subscription.status === 'trialing' && subscription.subscription.trial_end_date) {
1096
- <div>
1097
- <span class="text-[var(--cp-section-label-color)]"
1098
- [style.fontSize]="'var(--cp-section-label-size)'"
1099
- [style.fontWeight]="'var(--cp-section-label-weight)'">Trial end date</span>
1100
- <div class="text-[var(--cp-section-value-color)] mt-2"
1101
- [style.fontSize]="'var(--cp-section-value-size)'"
1102
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1103
- {{ _formatDate(subscription.subscription.trial_end_date) }}
1104
- </div>
1105
- </div>
1106
- <div>
1107
- <span class="text-[var(--cp-section-label-color)]"
1108
- [style.fontSize]="'var(--cp-section-label-size)'"
1109
- [style.fontWeight]="'var(--cp-section-label-weight)'">Trial period</span>
1110
- <div class="text-[var(--cp-section-value-color)] mt-2"
1111
- [style.fontSize]="'var(--cp-section-value-size)'"
1112
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1113
- {{ _formatDate(subscription.subscription.starts_at) }} - {{ _formatDate(subscription.subscription.trial_end_date) }}
1114
- </div>
1115
- </div>
1116
- }
1117
- @if (subscription.subscription.status === 'active') {
1118
- <div>
1119
- <span class="text-[var(--cp-section-label-color)]"
1120
- [style.fontSize]="'var(--cp-section-label-size)'"
1121
- [style.fontWeight]="'var(--cp-section-label-weight)'">End date</span>
1122
- <div class="text-[var(--cp-section-value-color)] mt-2"
1123
- [style.fontSize]="'var(--cp-section-value-size)'"
1124
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1125
- {{ subscription.subscription.ends_at ? _formatDate(subscription.subscription.ends_at) : '-' }}
1340
+ <div class="space-y-2">
1341
+ @for (item of getPlanLineItems(); track item.price_option_id) {
1342
+ <div class="bg-[var(--cp-subscription-item-bg,white)] border border-[var(--cp-subscription-item-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3 flex items-center justify-between">
1343
+ <div class="flex items-center gap-2">
1344
+ <span class="text-[var(--cp-subscription-item-text)]"
1345
+ [style.fontSize]="'var(--cp-section-value-size)'"
1346
+ [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1347
+ {{ _capitalize(item.name) }}
1348
+ </span>
1349
+ @if (item.quantity > 0 && item.source_type !== 'plan') {
1350
+ <span class="text-[var(--cp-subscription-item-quantity,#6b7280)] opacity-75">&bull;</span>
1351
+ <span class="text-[var(--cp-subscription-item-quantity,#6b7280)] font-normal text-sm">
1352
+ {{ item.quantity }} {{ item.name?.toLowerCase() }}
1353
+ </span>
1354
+ }
1355
+ </div>
1356
+ <span class="text-[var(--cp-subscription-item-text)]"
1357
+ [style.fontSize]="'var(--cp-section-value-size)'"
1358
+ [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1359
+ {{ _formatCurrency(item.total_amount || item.unit_price, item.currency_code) }}
1360
+ </span>
1126
1361
  </div>
1127
- </div>
1128
- }
1129
- </div>
1130
- </div>
1131
-
1132
- <!-- Preview invoice link -->
1133
- @if (subscription.subscription.upcoming_invoice) {
1134
- <div class="flex justify-end mt-2">
1135
- <button type="button"
1136
- class="text-[var(--cp-link-color,#3b82f6)] underline p-0 text-sm bg-transparent border-none cursor-pointer"
1137
- (click)="$event.stopPropagation(); invoicePreview.emit(subscription.subscription.upcoming_invoice)">
1138
- Preview invoice
1139
- </button>
1140
- </div>
1141
- }
1362
+ }
1363
+ </div>
1364
+ }
1142
1365
 
1143
- <!-- Billing details content box (active only) -->
1144
- @if (subscription.subscription.status === 'active') {
1145
- <div data-testid="subscription-content-box"
1146
- class="bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] mt-2"
1147
- [style.padding]="'var(--cp-section-content-padding)'">
1148
- <div class="flex justify-between flex-wrap gap-6">
1149
- <div>
1150
- <span class="text-[var(--cp-section-label-color)]"
1151
- [style.fontSize]="'var(--cp-section-label-size)'"
1152
- [style.fontWeight]="'var(--cp-section-label-weight)'">Next billing date</span>
1153
- <div class="text-[var(--cp-section-value-color)] mt-2"
1154
- [style.fontSize]="'var(--cp-section-value-size)'"
1155
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1156
- {{ subscription.subscription.renews_at ? _formatDate(subscription.subscription.renews_at) : '-' }}
1157
- </div>
1158
- </div>
1159
- <div>
1160
- <span class="text-[var(--cp-section-label-color)]"
1161
- [style.fontSize]="'var(--cp-section-label-size)'"
1162
- [style.fontWeight]="'var(--cp-section-label-weight)'">Invoice due</span>
1163
- <div class="text-[var(--cp-section-value-color)] mt-2"
1164
- [style.fontSize]="'var(--cp-section-value-size)'"
1165
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1166
- {{ subscription.subscription.renews_at ? _formatDate(subscription.subscription.renews_at) : '-' }}
1167
- </div>
1168
- </div>
1169
- <div>
1366
+ <!-- Add-on items -->
1367
+ @if (getAddonLineItems().length > 0) {
1368
+ <div class="mt-4">
1369
+ <div class="relative z-[100] flex items-center justify-between mb-3 mt-4">
1170
1370
  <span class="text-[var(--cp-section-label-color)]"
1171
1371
  [style.fontSize]="'var(--cp-section-label-size)'"
1172
- [style.fontWeight]="'var(--cp-section-label-weight)'">Next estimated bill</span>
1173
- <div class="text-[var(--cp-section-value-color)] mt-2"
1174
- [style.fontSize]="'var(--cp-section-value-size)'"
1175
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1176
- @if (subscription.subscription.next_billing_amount) {
1177
- <div class="font-medium">{{ _formatCurrency(subscription.subscription.next_billing_amount, subscription.subscription.currency_code) }}</div>
1178
- <div class="text-sm opacity-80 mt-0.5">(Monthly)</div>
1179
- } @else {
1180
- <span>-</span>
1181
- }
1182
- </div>
1183
- </div>
1184
- </div>
1185
- </div>
1186
- }
1187
-
1188
- <!-- Subscription Line Items -->
1189
- @if (subscription.subscription.subscription_items?.length) {
1190
- <div class="mt-8">
1191
- <div class="flex items-center justify-between mb-4">
1192
- <span class="text-[var(--cp-section-header-color)]"
1193
- [style.fontSize]="'var(--cp-section-header-size)'"
1194
- [style.fontWeight]="'var(--cp-section-header-weight)'">
1195
- Subscription items
1196
- </span>
1197
- @if (subscription.subscription.can_update_quantities) {
1372
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Add-ons</span>
1198
1373
  <button type="button"
1199
- class="text-[var(--cp-link-color,#3b82f6)] underline p-0 font-medium bg-transparent border-none cursor-pointer"
1200
- (click)="$event.stopPropagation(); openUpdateItems(subscription)">
1201
- Manage item quantities
1374
+ class="bg-[var(--cp-btn-secondary-bg)] text-[var(--cp-btn-secondary-text)] border-[var(--cp-btn-secondary-border)] rounded-[var(--cp-btn-secondary-radius)] px-5 py-2"
1375
+ [style.fontSize]="'var(--cp-btn-secondary-size)'"
1376
+ [style.fontWeight]="'var(--cp-btn-secondary-weight)'"
1377
+ [style.borderWidth]="'var(--cp-btn-secondary-border-width, 1px)'"
1378
+ [style.borderStyle]="'solid'"
1379
+ (click)="handleAddAddon()">
1380
+ Manage add-on
1202
1381
  </button>
1203
- }
1204
- </div>
1205
-
1206
- <div data-testid="subscription-items-container"
1207
- class="rounded-[var(--cp-section-content-radius)] overflow-hidden bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)]"
1208
- [style.padding]="'var(--cp-section-content-padding)'">
1209
-
1210
- <!-- Plan items -->
1211
- @if (getPlanLineItems(subscription.subscription.subscription_items).length > 0) {
1212
- <div class="mb-3 mt-4">
1213
- <span class="text-[var(--cp-section-label-color)]"
1214
- [style.fontSize]="'var(--cp-section-label-size)'"
1215
- [style.fontWeight]="'var(--cp-section-label-weight)'">Plan</span>
1216
- </div>
1217
- <div class="space-y-2">
1218
- @for (item of getPlanLineItems(subscription.subscription.subscription_items); track item.price_option_id) {
1219
- <div class="bg-[var(--cp-subscription-item-bg,white)] border border-[var(--cp-subscription-item-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3 flex items-center justify-between">
1220
- <div class="flex items-center gap-2">
1221
- <span class="text-[var(--cp-subscription-item-text)]"
1222
- [style.fontSize]="'var(--cp-section-value-size)'"
1223
- [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1224
- {{ _capitalize(item.name) }}
1225
- </span>
1226
- @if (item.quantity > 0 && item.source_type !== 'plan') {
1227
- <span class="text-[var(--cp-subscription-item-quantity,#6b7280)] opacity-75">&bull;</span>
1228
- <span class="text-[var(--cp-subscription-item-quantity,#6b7280)] font-normal text-sm">
1229
- {{ item.quantity }} {{ item.name?.toLowerCase() }}
1230
- </span>
1231
- }
1232
- </div>
1382
+ </div>
1383
+ <div class="space-y-2">
1384
+ @for (group of getGroupedAddonItems(); track group.key) {
1385
+ <div class="bg-[var(--cp-subscription-item-bg,white)] border border-[var(--cp-subscription-item-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3">
1386
+ <div class="flex justify-between items-center gap-2 w-full"
1387
+ [class.cursor-pointer]="group.children.length > 0"
1388
+ (click)="group.children.length > 0 && toggleAddon(group.key)">
1233
1389
  <span class="text-[var(--cp-subscription-item-text)]"
1234
1390
  [style.fontSize]="'var(--cp-section-value-size)'"
1235
- [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1236
- {{ _formatCurrency(item.total_amount || item.unit_price, item.currency_code) }}
1391
+ [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1392
+ {{ _capitalize(group.name) }}
1237
1393
  </span>
1238
- </div>
1239
- }
1240
- </div>
1241
- }
1242
-
1243
- <!-- Add-on items -->
1244
- @if (getAddonLineItems(subscription.subscription.subscription_items).length > 0) {
1245
- <div class="mt-4">
1246
- <div class="relative z-[100] flex items-center justify-between mb-3 mt-4">
1247
- <span class="text-[var(--cp-section-label-color)]"
1248
- [style.fontSize]="'var(--cp-section-label-size)'"
1249
- [style.fontWeight]="'var(--cp-section-label-weight)'">Add-ons</span>
1250
- <button type="button"
1251
- class="bg-[var(--cp-btn-secondary-bg)] text-[var(--cp-btn-secondary-text)] border-[var(--cp-btn-secondary-border)] rounded-[var(--cp-btn-secondary-radius)] px-5 py-2"
1252
- [style.fontSize]="'var(--cp-btn-secondary-size)'"
1253
- [style.fontWeight]="'var(--cp-btn-secondary-weight)'"
1254
- [style.borderWidth]="'var(--cp-btn-secondary-border-width, 1px)'"
1255
- [style.borderStyle]="'solid'"
1256
- (click)="handleAddAddon()">
1257
- Manage add-on
1258
- </button>
1259
- </div>
1260
- <div class="space-y-2">
1261
- @for (group of getGroupedAddonItems(subscription.subscription.subscription_items); track group.key) {
1262
- <div class="bg-[var(--cp-subscription-item-bg,white)] border border-[var(--cp-subscription-item-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3">
1263
- <div class="flex justify-between items-center gap-2 w-full"
1264
- [class.cursor-pointer]="group.children.length > 0"
1265
- (click)="group.children.length > 0 && toggleAddon(group.key)">
1394
+ <div class="flex justify-end items-center">
1395
+ @if (group.baseItem) {
1266
1396
  <span class="text-[var(--cp-subscription-item-text)]"
1267
1397
  [style.fontSize]="'var(--cp-section-value-size)'"
1268
- [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1269
- {{ _capitalize(group.name) }}
1398
+ [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1399
+ {{ _formatCurrency(group.baseItem.total_amount || group.baseItem.unit_price, group.baseItem.currency_code) }}
1270
1400
  </span>
1271
- <div class="flex justify-end items-center">
1272
- @if (group.baseItem) {
1273
- <span class="text-[var(--cp-subscription-item-text)]"
1401
+ }
1402
+ @if (group.children.length > 0) {
1403
+ <span class="ml-2 inline-flex transition-transform duration-200"
1404
+ [class.rotate-180]="isAddonExpanded(group.key)"
1405
+ [style.color]="'var(--cp-table-expand-icon-color, #71717a)'">
1406
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg>
1407
+ </span>
1408
+ }
1409
+ </div>
1410
+ </div>
1411
+ @if (isAddonExpanded(group.key) && group.children.length > 0) {
1412
+ <div class="bg-[var(--cp-section-content-bg,#F4F4F5)] space-y-2 p-4 mt-3 rounded-[var(--cp-section-content-radius)]">
1413
+ @for (child of group.children; track child.price_option_id || child.id) {
1414
+ <div class="bg-[var(--cp-subscription-child-bg,white)] border border-[var(--cp-subscription-child-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3 flex items-center justify-between">
1415
+ <div class="flex items-center gap-2">
1416
+ <span class="text-[var(--cp-subscription-child-text)]"
1274
1417
  [style.fontSize]="'var(--cp-section-value-size)'"
1275
- [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1276
- {{ _formatCurrency(group.baseItem.total_amount || group.baseItem.unit_price, group.baseItem.currency_code) }}
1418
+ [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1419
+ {{ _capitalize(child.name) }}
1277
1420
  </span>
1278
- }
1279
- @if (group.children.length > 0) {
1280
- <span class="ml-2 inline-flex transition-transform duration-200"
1281
- [class.rotate-180]="isAddonExpanded(group.key)"
1282
- [innerHTML]="_getIcon('arrowDown')"></span>
1283
- }
1284
- </div>
1285
- </div>
1286
- @if (isAddonExpanded(group.key) && group.children.length > 0) {
1287
- <div class="bg-[var(--cp-section-content-bg,#F4F4F5)] space-y-2 p-4 mt-3 rounded-[var(--cp-section-content-radius)]">
1288
- @for (child of group.children; track child.price_option_id || child.id) {
1289
- <div class="bg-[var(--cp-subscription-child-bg,white)] border border-[var(--cp-subscription-child-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3 flex items-center justify-between">
1290
- <div class="flex items-center gap-2">
1291
- <span class="text-[var(--cp-subscription-child-text)]"
1292
- [style.fontSize]="'var(--cp-section-value-size)'"
1293
- [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1294
- {{ _capitalize(child.name) }}
1295
- </span>
1296
- @if (child.quantity > 0) {
1297
- <span class="text-[var(--cp-subscription-child-quantity,#6b7280)] opacity-75">&bull;</span>
1298
- <span class="text-[var(--cp-subscription-child-quantity,#6b7280)] font-normal text-sm">
1299
- {{ child.quantity }} {{ child.name?.toLowerCase() }}
1300
- </span>
1301
- }
1302
- </div>
1303
- <span class="text-[var(--cp-subscription-child-text)]"
1304
- [style.fontSize]="'var(--cp-section-value-size)'"
1305
- [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1306
- {{ _formatCurrency(child.total_amount || child.unit_price, child.currency_code) }}
1421
+ @if (child.quantity > 0) {
1422
+ <span class="text-[var(--cp-subscription-child-quantity,#6b7280)] opacity-75">&bull;</span>
1423
+ <span class="text-[var(--cp-subscription-child-quantity,#6b7280)] font-normal text-sm">
1424
+ {{ child.quantity }} {{ child.name?.toLowerCase() }}
1307
1425
  </span>
1308
- </div>
1309
- }
1426
+ }
1427
+ </div>
1428
+ <span class="text-[var(--cp-subscription-child-text)]"
1429
+ [style.fontSize]="'var(--cp-section-value-size)'"
1430
+ [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1431
+ {{ _formatCurrency(child.total_amount || child.unit_price, child.currency_code) }}
1432
+ </span>
1310
1433
  </div>
1311
1434
  }
1312
1435
  </div>
1313
1436
  }
1314
1437
  </div>
1315
- </div>
1316
- }
1438
+ }
1439
+ </div>
1317
1440
  </div>
1318
- </div>
1319
- }
1441
+ }
1442
+ </div>
1320
1443
  </div>
1321
1444
  }
1322
1445
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1323
1446
  }
1324
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: SubscriptionSectionComponent, decorators: [{
1447
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: SubscriptionItemsComponent, decorators: [{
1325
1448
  type: Component,
1326
1449
  args: [{
1327
- selector: 'cp-subscription-section',
1450
+ selector: 'cp-subscription-items',
1328
1451
  standalone: true,
1329
1452
  imports: [CommonModule],
1330
1453
  changeDetection: ChangeDetectionStrategy.OnPush,
1331
1454
  template: `
1332
- @if (!_isSectionHidden('subscription') && subscription?.subscription) {
1333
- <div class="w-full"
1334
- [style.padding]="'var(--cp-section-padding)'"
1335
- [style.backgroundColor]="'var(--cp-section-bg)'"
1336
- [style.borderColor]="'var(--cp-section-border)'"
1337
- [style.borderRadius]="'var(--cp-section-radius)'"
1338
- [style.borderWidth]="'1px'"
1339
- [style.borderStyle]="'solid'">
1340
- <!-- Header: title + Manage plan -->
1341
- <div class="flex justify-between items-center mb-4">
1455
+ @if (items?.length) {
1456
+ <div class="mt-8">
1457
+ <div class="flex items-center justify-between mb-4">
1342
1458
  <span class="text-[var(--cp-section-header-color)]"
1343
1459
  [style.fontSize]="'var(--cp-section-header-size)'"
1344
1460
  [style.fontWeight]="'var(--cp-section-header-weight)'">
1345
- {{ _getSectionLabel('subscription') }}
1461
+ Subscription items
1346
1462
  </span>
1347
- @if (subscription.subscription.status !== 'canceled') {
1463
+ @if (canUpdateQuantities) {
1348
1464
  <button type="button"
1349
- class="bg-[var(--cp-btn-primary-bg)] text-[var(--cp-btn-primary-text)] border-[var(--cp-btn-primary-border)] rounded-[var(--cp-btn-primary-radius)] px-5 py-2"
1350
- [style.fontSize]="'var(--cp-btn-primary-size)'"
1351
- [style.fontWeight]="'var(--cp-btn-primary-weight)'"
1352
- [style.borderWidth]="'var(--cp-btn-primary-border-width, 1px)'"
1353
- [style.borderStyle]="'solid'"
1354
- (click)="handleManagePlan()">
1355
- Manage plan
1465
+ class="text-[var(--cp-link-color,#3b82f6)] underline p-0 font-medium bg-transparent border-none cursor-pointer"
1466
+ (click)="$event.stopPropagation(); openUpdateItems()">
1467
+ Manage item quantities
1356
1468
  </button>
1357
1469
  }
1358
1470
  </div>
1359
1471
 
1360
- <!-- Plan details content box -->
1361
- <div data-testid="subscription-content-box"
1362
- class="bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)]"
1472
+ <div data-testid="subscription-items-container"
1473
+ class="rounded-[var(--cp-section-content-radius)] overflow-hidden bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)]"
1363
1474
  [style.padding]="'var(--cp-section-content-padding)'">
1364
- <div class="flex justify-between flex-wrap gap-6">
1365
- <div>
1366
- <span class="text-[var(--cp-section-label-color)]"
1367
- [style.fontSize]="'var(--cp-section-label-size)'"
1368
- [style.fontWeight]="'var(--cp-section-label-weight)'">Current plan</span>
1369
- <div class="text-[var(--cp-section-value-color)] mt-2"
1370
- [style.fontSize]="'var(--cp-section-value-size)'"
1371
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1372
- {{ subscription.subscription.plan_name || '-' }}
1373
- </div>
1374
- </div>
1375
- <div>
1376
- <span class="text-[var(--cp-section-label-color)]"
1377
- [style.fontSize]="'var(--cp-section-label-size)'"
1378
- [style.fontWeight]="'var(--cp-section-label-weight)'">Status</span>
1379
- <div class="text-[var(--cp-section-value-color)] mt-2"
1380
- [style.fontSize]="'var(--cp-section-value-size)'"
1381
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1382
- {{ _formatStatus(subscription.subscription.status) }}
1383
- </div>
1384
- </div>
1385
- <div>
1475
+
1476
+ <!-- Plan items -->
1477
+ @if (getPlanLineItems().length > 0) {
1478
+ <div class="mb-3 mt-4">
1386
1479
  <span class="text-[var(--cp-section-label-color)]"
1387
1480
  [style.fontSize]="'var(--cp-section-label-size)'"
1388
- [style.fontWeight]="'var(--cp-section-label-weight)'">Start date</span>
1389
- <div class="text-[var(--cp-section-value-color)] mt-2"
1390
- [style.fontSize]="'var(--cp-section-value-size)'"
1391
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1392
- {{ _formatDate(subscription.subscription.starts_at) || '-' }}
1393
- </div>
1481
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Plan</span>
1394
1482
  </div>
1395
- @if (subscription.subscription.status === 'active') {
1396
- <div>
1397
- <span class="text-[var(--cp-section-label-color)]"
1398
- [style.fontSize]="'var(--cp-section-label-size)'"
1399
- [style.fontWeight]="'var(--cp-section-label-weight)'">Current billing period</span>
1400
- <div class="text-[var(--cp-section-value-color)] mt-2"
1401
- [style.fontSize]="'var(--cp-section-value-size)'"
1402
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1403
- @if (subscription.subscription.current_billing_period_start && subscription.subscription.current_billing_period_end) {
1404
- <div class="font-medium">{{ _formatDate(subscription.subscription.current_billing_period_start) }} - {{ _formatDate(subscription.subscription.current_billing_period_end) }}</div>
1405
- <div class="mt-1 text-sm opacity-80">(Auto-renew)</div>
1406
- } @else {
1407
- <span>-</span>
1408
- }
1409
- </div>
1410
- </div>
1411
- }
1412
- @if (subscription.subscription.status === 'trialing' && subscription.subscription.trial_end_date) {
1413
- <div>
1414
- <span class="text-[var(--cp-section-label-color)]"
1415
- [style.fontSize]="'var(--cp-section-label-size)'"
1416
- [style.fontWeight]="'var(--cp-section-label-weight)'">Trial end date</span>
1417
- <div class="text-[var(--cp-section-value-color)] mt-2"
1418
- [style.fontSize]="'var(--cp-section-value-size)'"
1419
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1420
- {{ _formatDate(subscription.subscription.trial_end_date) }}
1421
- </div>
1422
- </div>
1423
- <div>
1424
- <span class="text-[var(--cp-section-label-color)]"
1425
- [style.fontSize]="'var(--cp-section-label-size)'"
1426
- [style.fontWeight]="'var(--cp-section-label-weight)'">Trial period</span>
1427
- <div class="text-[var(--cp-section-value-color)] mt-2"
1428
- [style.fontSize]="'var(--cp-section-value-size)'"
1429
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1430
- {{ _formatDate(subscription.subscription.starts_at) }} - {{ _formatDate(subscription.subscription.trial_end_date) }}
1431
- </div>
1432
- </div>
1433
- }
1434
- @if (subscription.subscription.status === 'active') {
1435
- <div>
1436
- <span class="text-[var(--cp-section-label-color)]"
1437
- [style.fontSize]="'var(--cp-section-label-size)'"
1438
- [style.fontWeight]="'var(--cp-section-label-weight)'">End date</span>
1439
- <div class="text-[var(--cp-section-value-color)] mt-2"
1440
- [style.fontSize]="'var(--cp-section-value-size)'"
1441
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1442
- {{ subscription.subscription.ends_at ? _formatDate(subscription.subscription.ends_at) : '-' }}
1483
+ <div class="space-y-2">
1484
+ @for (item of getPlanLineItems(); track item.price_option_id) {
1485
+ <div class="bg-[var(--cp-subscription-item-bg,white)] border border-[var(--cp-subscription-item-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3 flex items-center justify-between">
1486
+ <div class="flex items-center gap-2">
1487
+ <span class="text-[var(--cp-subscription-item-text)]"
1488
+ [style.fontSize]="'var(--cp-section-value-size)'"
1489
+ [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1490
+ {{ _capitalize(item.name) }}
1491
+ </span>
1492
+ @if (item.quantity > 0 && item.source_type !== 'plan') {
1493
+ <span class="text-[var(--cp-subscription-item-quantity,#6b7280)] opacity-75">&bull;</span>
1494
+ <span class="text-[var(--cp-subscription-item-quantity,#6b7280)] font-normal text-sm">
1495
+ {{ item.quantity }} {{ item.name?.toLowerCase() }}
1496
+ </span>
1497
+ }
1498
+ </div>
1499
+ <span class="text-[var(--cp-subscription-item-text)]"
1500
+ [style.fontSize]="'var(--cp-section-value-size)'"
1501
+ [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1502
+ {{ _formatCurrency(item.total_amount || item.unit_price, item.currency_code) }}
1503
+ </span>
1443
1504
  </div>
1444
- </div>
1445
- }
1446
- </div>
1447
- </div>
1448
-
1449
- <!-- Preview invoice link -->
1450
- @if (subscription.subscription.upcoming_invoice) {
1451
- <div class="flex justify-end mt-2">
1452
- <button type="button"
1453
- class="text-[var(--cp-link-color,#3b82f6)] underline p-0 text-sm bg-transparent border-none cursor-pointer"
1454
- (click)="$event.stopPropagation(); invoicePreview.emit(subscription.subscription.upcoming_invoice)">
1455
- Preview invoice
1456
- </button>
1457
- </div>
1458
- }
1505
+ }
1506
+ </div>
1507
+ }
1459
1508
 
1460
- <!-- Billing details content box (active only) -->
1461
- @if (subscription.subscription.status === 'active') {
1462
- <div data-testid="subscription-content-box"
1463
- class="bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] mt-2"
1464
- [style.padding]="'var(--cp-section-content-padding)'">
1465
- <div class="flex justify-between flex-wrap gap-6">
1466
- <div>
1467
- <span class="text-[var(--cp-section-label-color)]"
1468
- [style.fontSize]="'var(--cp-section-label-size)'"
1469
- [style.fontWeight]="'var(--cp-section-label-weight)'">Next billing date</span>
1470
- <div class="text-[var(--cp-section-value-color)] mt-2"
1471
- [style.fontSize]="'var(--cp-section-value-size)'"
1472
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1473
- {{ subscription.subscription.renews_at ? _formatDate(subscription.subscription.renews_at) : '-' }}
1474
- </div>
1475
- </div>
1476
- <div>
1477
- <span class="text-[var(--cp-section-label-color)]"
1478
- [style.fontSize]="'var(--cp-section-label-size)'"
1479
- [style.fontWeight]="'var(--cp-section-label-weight)'">Invoice due</span>
1480
- <div class="text-[var(--cp-section-value-color)] mt-2"
1481
- [style.fontSize]="'var(--cp-section-value-size)'"
1482
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1483
- {{ subscription.subscription.renews_at ? _formatDate(subscription.subscription.renews_at) : '-' }}
1484
- </div>
1485
- </div>
1486
- <div>
1509
+ <!-- Add-on items -->
1510
+ @if (getAddonLineItems().length > 0) {
1511
+ <div class="mt-4">
1512
+ <div class="relative z-[100] flex items-center justify-between mb-3 mt-4">
1487
1513
  <span class="text-[var(--cp-section-label-color)]"
1488
1514
  [style.fontSize]="'var(--cp-section-label-size)'"
1489
- [style.fontWeight]="'var(--cp-section-label-weight)'">Next estimated bill</span>
1490
- <div class="text-[var(--cp-section-value-color)] mt-2"
1491
- [style.fontSize]="'var(--cp-section-value-size)'"
1492
- [style.fontWeight]="'var(--cp-section-value-weight)'">
1493
- @if (subscription.subscription.next_billing_amount) {
1494
- <div class="font-medium">{{ _formatCurrency(subscription.subscription.next_billing_amount, subscription.subscription.currency_code) }}</div>
1495
- <div class="text-sm opacity-80 mt-0.5">(Monthly)</div>
1496
- } @else {
1497
- <span>-</span>
1498
- }
1499
- </div>
1500
- </div>
1501
- </div>
1502
- </div>
1503
- }
1504
-
1505
- <!-- Subscription Line Items -->
1506
- @if (subscription.subscription.subscription_items?.length) {
1507
- <div class="mt-8">
1508
- <div class="flex items-center justify-between mb-4">
1509
- <span class="text-[var(--cp-section-header-color)]"
1510
- [style.fontSize]="'var(--cp-section-header-size)'"
1511
- [style.fontWeight]="'var(--cp-section-header-weight)'">
1512
- Subscription items
1513
- </span>
1514
- @if (subscription.subscription.can_update_quantities) {
1515
+ [style.fontWeight]="'var(--cp-section-label-weight)'">Add-ons</span>
1515
1516
  <button type="button"
1516
- class="text-[var(--cp-link-color,#3b82f6)] underline p-0 font-medium bg-transparent border-none cursor-pointer"
1517
- (click)="$event.stopPropagation(); openUpdateItems(subscription)">
1518
- Manage item quantities
1517
+ class="bg-[var(--cp-btn-secondary-bg)] text-[var(--cp-btn-secondary-text)] border-[var(--cp-btn-secondary-border)] rounded-[var(--cp-btn-secondary-radius)] px-5 py-2"
1518
+ [style.fontSize]="'var(--cp-btn-secondary-size)'"
1519
+ [style.fontWeight]="'var(--cp-btn-secondary-weight)'"
1520
+ [style.borderWidth]="'var(--cp-btn-secondary-border-width, 1px)'"
1521
+ [style.borderStyle]="'solid'"
1522
+ (click)="handleAddAddon()">
1523
+ Manage add-on
1519
1524
  </button>
1520
- }
1521
- </div>
1522
-
1523
- <div data-testid="subscription-items-container"
1524
- class="rounded-[var(--cp-section-content-radius)] overflow-hidden bg-[var(--cp-section-content-bg,#F4F4F5)] border border-[var(--cp-section-content-border,#e4e4e7)]"
1525
- [style.padding]="'var(--cp-section-content-padding)'">
1526
-
1527
- <!-- Plan items -->
1528
- @if (getPlanLineItems(subscription.subscription.subscription_items).length > 0) {
1529
- <div class="mb-3 mt-4">
1530
- <span class="text-[var(--cp-section-label-color)]"
1531
- [style.fontSize]="'var(--cp-section-label-size)'"
1532
- [style.fontWeight]="'var(--cp-section-label-weight)'">Plan</span>
1533
- </div>
1534
- <div class="space-y-2">
1535
- @for (item of getPlanLineItems(subscription.subscription.subscription_items); track item.price_option_id) {
1536
- <div class="bg-[var(--cp-subscription-item-bg,white)] border border-[var(--cp-subscription-item-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3 flex items-center justify-between">
1537
- <div class="flex items-center gap-2">
1538
- <span class="text-[var(--cp-subscription-item-text)]"
1539
- [style.fontSize]="'var(--cp-section-value-size)'"
1540
- [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1541
- {{ _capitalize(item.name) }}
1542
- </span>
1543
- @if (item.quantity > 0 && item.source_type !== 'plan') {
1544
- <span class="text-[var(--cp-subscription-item-quantity,#6b7280)] opacity-75">&bull;</span>
1545
- <span class="text-[var(--cp-subscription-item-quantity,#6b7280)] font-normal text-sm">
1546
- {{ item.quantity }} {{ item.name?.toLowerCase() }}
1547
- </span>
1548
- }
1549
- </div>
1525
+ </div>
1526
+ <div class="space-y-2">
1527
+ @for (group of getGroupedAddonItems(); track group.key) {
1528
+ <div class="bg-[var(--cp-subscription-item-bg,white)] border border-[var(--cp-subscription-item-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3">
1529
+ <div class="flex justify-between items-center gap-2 w-full"
1530
+ [class.cursor-pointer]="group.children.length > 0"
1531
+ (click)="group.children.length > 0 && toggleAddon(group.key)">
1550
1532
  <span class="text-[var(--cp-subscription-item-text)]"
1551
1533
  [style.fontSize]="'var(--cp-section-value-size)'"
1552
- [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1553
- {{ _formatCurrency(item.total_amount || item.unit_price, item.currency_code) }}
1534
+ [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1535
+ {{ _capitalize(group.name) }}
1554
1536
  </span>
1555
- </div>
1556
- }
1557
- </div>
1558
- }
1559
-
1560
- <!-- Add-on items -->
1561
- @if (getAddonLineItems(subscription.subscription.subscription_items).length > 0) {
1562
- <div class="mt-4">
1563
- <div class="relative z-[100] flex items-center justify-between mb-3 mt-4">
1564
- <span class="text-[var(--cp-section-label-color)]"
1565
- [style.fontSize]="'var(--cp-section-label-size)'"
1566
- [style.fontWeight]="'var(--cp-section-label-weight)'">Add-ons</span>
1567
- <button type="button"
1568
- class="bg-[var(--cp-btn-secondary-bg)] text-[var(--cp-btn-secondary-text)] border-[var(--cp-btn-secondary-border)] rounded-[var(--cp-btn-secondary-radius)] px-5 py-2"
1569
- [style.fontSize]="'var(--cp-btn-secondary-size)'"
1570
- [style.fontWeight]="'var(--cp-btn-secondary-weight)'"
1571
- [style.borderWidth]="'var(--cp-btn-secondary-border-width, 1px)'"
1572
- [style.borderStyle]="'solid'"
1573
- (click)="handleAddAddon()">
1574
- Manage add-on
1575
- </button>
1576
- </div>
1577
- <div class="space-y-2">
1578
- @for (group of getGroupedAddonItems(subscription.subscription.subscription_items); track group.key) {
1579
- <div class="bg-[var(--cp-subscription-item-bg,white)] border border-[var(--cp-subscription-item-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3">
1580
- <div class="flex justify-between items-center gap-2 w-full"
1581
- [class.cursor-pointer]="group.children.length > 0"
1582
- (click)="group.children.length > 0 && toggleAddon(group.key)">
1537
+ <div class="flex justify-end items-center">
1538
+ @if (group.baseItem) {
1583
1539
  <span class="text-[var(--cp-subscription-item-text)]"
1584
1540
  [style.fontSize]="'var(--cp-section-value-size)'"
1585
- [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1586
- {{ _capitalize(group.name) }}
1541
+ [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1542
+ {{ _formatCurrency(group.baseItem.total_amount || group.baseItem.unit_price, group.baseItem.currency_code) }}
1543
+ </span>
1544
+ }
1545
+ @if (group.children.length > 0) {
1546
+ <span class="ml-2 inline-flex transition-transform duration-200"
1547
+ [class.rotate-180]="isAddonExpanded(group.key)"
1548
+ [style.color]="'var(--cp-table-expand-icon-color, #71717a)'">
1549
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg>
1587
1550
  </span>
1588
- <div class="flex justify-end items-center">
1589
- @if (group.baseItem) {
1590
- <span class="text-[var(--cp-subscription-item-text)]"
1551
+ }
1552
+ </div>
1553
+ </div>
1554
+ @if (isAddonExpanded(group.key) && group.children.length > 0) {
1555
+ <div class="bg-[var(--cp-section-content-bg,#F4F4F5)] space-y-2 p-4 mt-3 rounded-[var(--cp-section-content-radius)]">
1556
+ @for (child of group.children; track child.price_option_id || child.id) {
1557
+ <div class="bg-[var(--cp-subscription-child-bg,white)] border border-[var(--cp-subscription-child-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3 flex items-center justify-between">
1558
+ <div class="flex items-center gap-2">
1559
+ <span class="text-[var(--cp-subscription-child-text)]"
1591
1560
  [style.fontSize]="'var(--cp-section-value-size)'"
1592
- [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1593
- {{ _formatCurrency(group.baseItem.total_amount || group.baseItem.unit_price, group.baseItem.currency_code) }}
1594
- </span>
1595
- }
1596
- @if (group.children.length > 0) {
1597
- <span class="ml-2 inline-flex transition-transform duration-200"
1598
- [class.rotate-180]="isAddonExpanded(group.key)"
1599
- [innerHTML]="_getIcon('arrowDown')"></span>
1600
- }
1601
- </div>
1602
- </div>
1603
- @if (isAddonExpanded(group.key) && group.children.length > 0) {
1604
- <div class="bg-[var(--cp-section-content-bg,#F4F4F5)] space-y-2 p-4 mt-3 rounded-[var(--cp-section-content-radius)]">
1605
- @for (child of group.children; track child.price_option_id || child.id) {
1606
- <div class="bg-[var(--cp-subscription-child-bg,white)] border border-[var(--cp-subscription-child-border,#e4e4e7)] rounded-[var(--cp-section-content-radius)] px-4 py-3 flex items-center justify-between">
1607
- <div class="flex items-center gap-2">
1608
- <span class="text-[var(--cp-subscription-child-text)]"
1609
- [style.fontSize]="'var(--cp-section-value-size)'"
1610
- [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1611
- {{ _capitalize(child.name) }}
1612
- </span>
1613
- @if (child.quantity > 0) {
1614
- <span class="text-[var(--cp-subscription-child-quantity,#6b7280)] opacity-75">&bull;</span>
1615
- <span class="text-[var(--cp-subscription-child-quantity,#6b7280)] font-normal text-sm">
1616
- {{ child.quantity }} {{ child.name?.toLowerCase() }}
1617
- </span>
1618
- }
1619
- </div>
1620
- <span class="text-[var(--cp-subscription-child-text)]"
1621
- [style.fontSize]="'var(--cp-section-value-size)'"
1622
- [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1623
- {{ _formatCurrency(child.total_amount || child.unit_price, child.currency_code) }}
1561
+ [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1562
+ {{ _capitalize(child.name) }}
1563
+ </span>
1564
+ @if (child.quantity > 0) {
1565
+ <span class="text-[var(--cp-subscription-child-quantity,#6b7280)] opacity-75">&bull;</span>
1566
+ <span class="text-[var(--cp-subscription-child-quantity,#6b7280)] font-normal text-sm">
1567
+ {{ child.quantity }} {{ child.name?.toLowerCase() }}
1624
1568
  </span>
1625
- </div>
1626
- }
1569
+ }
1570
+ </div>
1571
+ <span class="text-[var(--cp-subscription-child-text)]"
1572
+ [style.fontSize]="'var(--cp-section-value-size)'"
1573
+ [style.fontWeight]="'var(--cp-section-value-weight, 500)'">
1574
+ {{ _formatCurrency(child.total_amount || child.unit_price, child.currency_code) }}
1575
+ </span>
1627
1576
  </div>
1628
1577
  }
1629
1578
  </div>
1630
1579
  }
1631
1580
  </div>
1632
- </div>
1633
- }
1581
+ }
1582
+ </div>
1634
1583
  </div>
1635
- </div>
1584
+ }
1585
+ </div>
1586
+ </div>
1587
+ }
1588
+ `
1589
+ }]
1590
+ }], propDecorators: { items: [{
1591
+ type: Input
1592
+ }], canUpdateQuantities: [{
1593
+ type: Input
1594
+ }], tenantCheckoutUsername: [{
1595
+ type: Input
1596
+ }], customerKey: [{
1597
+ type: Input
1598
+ }], subscriptionId: [{
1599
+ type: Input
1600
+ }], offeringKey: [{
1601
+ type: Input
1602
+ }] } });
1603
+
1604
+ class SubscriptionSectionComponent {
1605
+ subscription;
1606
+ sectionsConfig;
1607
+ customerKey = '';
1608
+ tenantCheckoutUsername = '';
1609
+ invoicePreview = new EventEmitter();
1610
+ managePlan = new EventEmitter();
1611
+ handleManagePlan() {
1612
+ if (this.subscription) {
1613
+ this.managePlan.emit(this.subscription);
1636
1614
  }
1615
+ }
1616
+ _isSectionHidden(key) {
1617
+ return isSectionHidden(this.sectionsConfig, key);
1618
+ }
1619
+ _getSectionLabel(key) {
1620
+ return getSectionLabel(this.sectionsConfig, key);
1621
+ }
1622
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: SubscriptionSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1623
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: SubscriptionSectionComponent, isStandalone: true, selector: "cp-subscription-section", inputs: { subscription: "subscription", sectionsConfig: "sectionsConfig", customerKey: "customerKey", tenantCheckoutUsername: "tenantCheckoutUsername" }, outputs: { invoicePreview: "invoicePreview", managePlan: "managePlan" }, ngImport: i0, template: `
1624
+ @if (!_isSectionHidden('subscription') && subscription?.subscription) {
1625
+ <div class="w-full"
1626
+ [style.padding]="'var(--cp-section-padding)'"
1627
+ [style.backgroundColor]="'var(--cp-section-bg)'"
1628
+ [style.borderColor]="'var(--cp-section-border)'"
1629
+ [style.borderRadius]="'var(--cp-section-radius)'"
1630
+ [style.borderWidth]="'1px'"
1631
+ [style.borderStyle]="'solid'">
1632
+ <!-- Header: title + Manage plan -->
1633
+ <div class="flex justify-between items-center mb-4">
1634
+ <span class="text-[var(--cp-section-header-color)]"
1635
+ [style.fontSize]="'var(--cp-section-header-size)'"
1636
+ [style.fontWeight]="'var(--cp-section-header-weight)'">
1637
+ {{ _getSectionLabel('subscription') }}
1638
+ </span>
1639
+ @if (subscription.subscription.status !== 'canceled') {
1640
+ <button type="button"
1641
+ class="bg-[var(--cp-btn-primary-bg)] text-[var(--cp-btn-primary-text)] border-[var(--cp-btn-primary-border)] rounded-[var(--cp-btn-primary-radius)] px-5 py-2"
1642
+ [style.fontSize]="'var(--cp-btn-primary-size)'"
1643
+ [style.fontWeight]="'var(--cp-btn-primary-weight)'"
1644
+ [style.borderWidth]="'var(--cp-btn-primary-border-width, 1px)'"
1645
+ [style.borderStyle]="'solid'"
1646
+ (click)="handleManagePlan()">
1647
+ Manage plan
1648
+ </button>
1649
+ }
1650
+ </div>
1651
+
1652
+ <!-- Subscription Details (plan info + billing) -->
1653
+ <cp-subscription-details
1654
+ [sub]="subscription.subscription"
1655
+ (invoicePreview)="invoicePreview.emit($event)">
1656
+ </cp-subscription-details>
1657
+
1658
+ <!-- Subscription Line Items -->
1659
+ <cp-subscription-items
1660
+ [items]="subscription.subscription.subscription_items || []"
1661
+ [canUpdateQuantities]="!!subscription.subscription.can_update_quantities"
1662
+ [tenantCheckoutUsername]="tenantCheckoutUsername"
1663
+ [customerKey]="customerKey"
1664
+ [subscriptionId]="subscription.subscription.id || ''"
1665
+ [offeringKey]="subscription.subscription.offering_key || ''">
1666
+ </cp-subscription-items>
1667
+ </div>
1668
+ }
1669
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: SubscriptionDetailsComponent, selector: "cp-subscription-details", inputs: ["sub"], outputs: ["invoicePreview"] }, { kind: "component", type: SubscriptionItemsComponent, selector: "cp-subscription-items", inputs: ["items", "canUpdateQuantities", "tenantCheckoutUsername", "customerKey", "subscriptionId", "offeringKey"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1670
+ }
1671
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: SubscriptionSectionComponent, decorators: [{
1672
+ type: Component,
1673
+ args: [{
1674
+ selector: 'cp-subscription-section',
1675
+ standalone: true,
1676
+ imports: [CommonModule, SubscriptionDetailsComponent, SubscriptionItemsComponent],
1677
+ changeDetection: ChangeDetectionStrategy.OnPush,
1678
+ template: `
1679
+ @if (!_isSectionHidden('subscription') && subscription?.subscription) {
1680
+ <div class="w-full"
1681
+ [style.padding]="'var(--cp-section-padding)'"
1682
+ [style.backgroundColor]="'var(--cp-section-bg)'"
1683
+ [style.borderColor]="'var(--cp-section-border)'"
1684
+ [style.borderRadius]="'var(--cp-section-radius)'"
1685
+ [style.borderWidth]="'1px'"
1686
+ [style.borderStyle]="'solid'">
1687
+ <!-- Header: title + Manage plan -->
1688
+ <div class="flex justify-between items-center mb-4">
1689
+ <span class="text-[var(--cp-section-header-color)]"
1690
+ [style.fontSize]="'var(--cp-section-header-size)'"
1691
+ [style.fontWeight]="'var(--cp-section-header-weight)'">
1692
+ {{ _getSectionLabel('subscription') }}
1693
+ </span>
1694
+ @if (subscription.subscription.status !== 'canceled') {
1695
+ <button type="button"
1696
+ class="bg-[var(--cp-btn-primary-bg)] text-[var(--cp-btn-primary-text)] border-[var(--cp-btn-primary-border)] rounded-[var(--cp-btn-primary-radius)] px-5 py-2"
1697
+ [style.fontSize]="'var(--cp-btn-primary-size)'"
1698
+ [style.fontWeight]="'var(--cp-btn-primary-weight)'"
1699
+ [style.borderWidth]="'var(--cp-btn-primary-border-width, 1px)'"
1700
+ [style.borderStyle]="'solid'"
1701
+ (click)="handleManagePlan()">
1702
+ Manage plan
1703
+ </button>
1704
+ }
1705
+ </div>
1706
+
1707
+ <!-- Subscription Details (plan info + billing) -->
1708
+ <cp-subscription-details
1709
+ [sub]="subscription.subscription"
1710
+ (invoicePreview)="invoicePreview.emit($event)">
1711
+ </cp-subscription-details>
1712
+
1713
+ <!-- Subscription Line Items -->
1714
+ <cp-subscription-items
1715
+ [items]="subscription.subscription.subscription_items || []"
1716
+ [canUpdateQuantities]="!!subscription.subscription.can_update_quantities"
1717
+ [tenantCheckoutUsername]="tenantCheckoutUsername"
1718
+ [customerKey]="customerKey"
1719
+ [subscriptionId]="subscription.subscription.id || ''"
1720
+ [offeringKey]="subscription.subscription.offering_key || ''">
1721
+ </cp-subscription-items>
1637
1722
  </div>
1638
1723
  }
1639
- `,
1724
+ `
1640
1725
  }]
1641
1726
  }], propDecorators: { subscription: [{
1642
1727
  type: Input
@@ -1666,7 +1751,7 @@ class CreditBalanceSectionComponent {
1666
1751
  walletTabs = [
1667
1752
  { key: 'active', label: 'Active' },
1668
1753
  { key: 'expired', label: 'Expired' },
1669
- { key: 'overage', label: 'Overage' },
1754
+ { key: 'overage', label: 'Overage' }
1670
1755
  ];
1671
1756
  showCreditTransactions = signal(false);
1672
1757
  selectedAllocation = signal(null);
@@ -1725,7 +1810,7 @@ class CreditBalanceSectionComponent {
1725
1810
  year: 'numeric',
1726
1811
  hour: 'numeric',
1727
1812
  minute: '2-digit',
1728
- hour12: true,
1813
+ hour12: true
1729
1814
  })
1730
1815
  .replace(',', '');
1731
1816
  }
@@ -1747,7 +1832,7 @@ class CreditBalanceSectionComponent {
1747
1832
  return date.toLocaleDateString('en-US', {
1748
1833
  month: 'numeric',
1749
1834
  day: 'numeric',
1750
- year: 'numeric',
1835
+ year: 'numeric'
1751
1836
  });
1752
1837
  }
1753
1838
  getAllocationBalance(allocation) {
@@ -1769,13 +1854,13 @@ class CreditBalanceSectionComponent {
1769
1854
  .pipe(takeUntil(this.destroy$))
1770
1855
  .subscribe({
1771
1856
  next: (data) => {
1772
- this.creditTransactions.set(data?.transactions || []);
1857
+ this.creditTransactions.set(data || []);
1773
1858
  this.creditTransactionsLoading.set(false);
1774
1859
  },
1775
1860
  error: () => {
1776
1861
  this.creditTransactions.set([]);
1777
1862
  this.creditTransactionsLoading.set(false);
1778
- },
1863
+ }
1779
1864
  });
1780
1865
  }
1781
1866
  closeCreditTransactions() {
@@ -1801,13 +1886,16 @@ class CreditBalanceSectionComponent {
1801
1886
  getWalletSettingsValidationErrors() {
1802
1887
  const errors = [];
1803
1888
  if (this.lowBalanceEnabled) {
1804
- if (!this.walletSettingThreshold?.trim())
1889
+ if (!this.walletSettingThreshold?.trim()) {
1805
1890
  errors.push('Set a low balance threshold is required');
1891
+ }
1806
1892
  if (this.walletSettingBehaviour === 'auto_top_up') {
1807
- if (!this.walletSettingTargetBalance?.trim())
1893
+ if (!this.walletSettingTargetBalance?.trim()) {
1808
1894
  errors.push('Bring wallet balance back up to is required for auto top-up');
1809
- if (!this.walletSettingMonthlyLimit?.trim())
1895
+ }
1896
+ if (!this.walletSettingMonthlyLimit?.trim()) {
1810
1897
  errors.push('Limit the amount of automatic top up per month is required for auto top-up');
1898
+ }
1811
1899
  }
1812
1900
  }
1813
1901
  return errors;
@@ -1844,7 +1932,7 @@ class CreditBalanceSectionComponent {
1844
1932
  error: (err) => {
1845
1933
  this.walletSettingsError.set(err?.message || 'Failed to delete settings');
1846
1934
  this.walletSettingsSaving.set(false);
1847
- },
1935
+ }
1848
1936
  });
1849
1937
  }
1850
1938
  else {
@@ -1861,8 +1949,8 @@ class CreditBalanceSectionComponent {
1861
1949
  threshold_amount: Number(this.walletSettingThreshold) || 0,
1862
1950
  ...(this.walletSettingBehaviour === 'auto_top_up' && {
1863
1951
  target_balance: Number(this.walletSettingTargetBalance) || 0,
1864
- monthly_top_up_count_limit: Number(this.walletSettingMonthlyLimit) || 0,
1865
- }),
1952
+ monthly_top_up_count_limit: Number(this.walletSettingMonthlyLimit) || 0
1953
+ })
1866
1954
  };
1867
1955
  this.walletSettingsSaving.set(true);
1868
1956
  const editId = this.walletSettingEditId();
@@ -1878,7 +1966,7 @@ class CreditBalanceSectionComponent {
1878
1966
  error: (err) => {
1879
1967
  this.walletSettingsError.set(err?.message || 'Failed to save settings');
1880
1968
  this.walletSettingsSaving.set(false);
1881
- },
1969
+ }
1882
1970
  });
1883
1971
  }
1884
1972
  onWalletSelectChange(event) {
@@ -1916,7 +2004,7 @@ class CreditBalanceSectionComponent {
1916
2004
  error: (err) => {
1917
2005
  this.walletSettingsError.set(err?.message || 'Failed to load wallet settings');
1918
2006
  this.walletSettingsLoading.set(false);
1919
- },
2007
+ }
1920
2008
  });
1921
2009
  }
1922
2010
  applyExistingWalletSetting() {
@@ -2160,7 +2248,7 @@ class CreditBalanceSectionComponent {
2160
2248
 
2161
2249
  <!-- Credit Transactions Modal (compact width) -->
2162
2250
  @if (showCreditTransactions()) {
2163
- <div class="fixed inset-0 flex items-center justify-center z-50 p-4" [style.background-color]="'var(--cp-modal-overlay-bg)'" (click)="closeCreditTransactions()">
2251
+ <div class="fixed inset-0 flex items-center justify-center z-[100] p-4" [style.background-color]="'var(--cp-modal-overlay-bg)'" (click)="closeCreditTransactions()">
2164
2252
  <div class="w-full max-w-sm max-h-[80vh] flex flex-col mx-auto" [style.background-color]="'var(--cp-modal-bg)'" [style.border-radius]="'var(--cp-modal-radius)'" (click)="$event.stopPropagation()">
2165
2253
  <!-- Modal Header -->
2166
2254
  <div class="flex justify-between items-center p-4 border-b border-gray-100">
@@ -2264,7 +2352,7 @@ class CreditBalanceSectionComponent {
2264
2352
 
2265
2353
  <!-- Wallet Settings Modal -->
2266
2354
  @if (showWalletSettings()) {
2267
- <div class="fixed inset-0 flex items-center justify-center z-50 p-6" [style.background-color]="'var(--cp-modal-overlay-bg)'" (click)="closeWalletSettings()">
2355
+ <div class="fixed inset-0 flex items-center justify-center z-[100] p-6" [style.background-color]="'var(--cp-modal-overlay-bg)'" (click)="closeWalletSettings()">
2268
2356
  <div class="w-full max-w-3xl min-h-[75vh] max-h-[85vh] flex flex-col shadow-xl" [style.background-color]="'var(--cp-modal-bg)'" [style.border-radius]="'var(--cp-modal-radius)'" (click)="$event.stopPropagation()">
2269
2357
  <!-- Modal Header -->
2270
2358
  <div class="flex justify-between items-center p-4 border-b border-gray-100">
@@ -2624,7 +2712,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
2624
2712
 
2625
2713
  <!-- Credit Transactions Modal (compact width) -->
2626
2714
  @if (showCreditTransactions()) {
2627
- <div class="fixed inset-0 flex items-center justify-center z-50 p-4" [style.background-color]="'var(--cp-modal-overlay-bg)'" (click)="closeCreditTransactions()">
2715
+ <div class="fixed inset-0 flex items-center justify-center z-[100] p-4" [style.background-color]="'var(--cp-modal-overlay-bg)'" (click)="closeCreditTransactions()">
2628
2716
  <div class="w-full max-w-sm max-h-[80vh] flex flex-col mx-auto" [style.background-color]="'var(--cp-modal-bg)'" [style.border-radius]="'var(--cp-modal-radius)'" (click)="$event.stopPropagation()">
2629
2717
  <!-- Modal Header -->
2630
2718
  <div class="flex justify-between items-center p-4 border-b border-gray-100">
@@ -2728,7 +2816,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
2728
2816
 
2729
2817
  <!-- Wallet Settings Modal -->
2730
2818
  @if (showWalletSettings()) {
2731
- <div class="fixed inset-0 flex items-center justify-center z-50 p-6" [style.background-color]="'var(--cp-modal-overlay-bg)'" (click)="closeWalletSettings()">
2819
+ <div class="fixed inset-0 flex items-center justify-center z-[100] p-6" [style.background-color]="'var(--cp-modal-overlay-bg)'" (click)="closeWalletSettings()">
2732
2820
  <div class="w-full max-w-3xl min-h-[75vh] max-h-[85vh] flex flex-col shadow-xl" [style.background-color]="'var(--cp-modal-bg)'" [style.border-radius]="'var(--cp-modal-radius)'" (click)="$event.stopPropagation()">
2733
2821
  <!-- Modal Header -->
2734
2822
  <div class="flex justify-between items-center p-4 border-b border-gray-100">
@@ -2861,7 +2949,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
2861
2949
  </div>
2862
2950
  </div>
2863
2951
  }
2864
- `,
2952
+ `
2865
2953
  }]
2866
2954
  }], propDecorators: { wallets: [{
2867
2955
  type: Input
@@ -2881,46 +2969,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
2881
2969
  type: Output
2882
2970
  }] } });
2883
2971
 
2884
- class EntitlementsSectionComponent {
2972
+ class EntitlementSummaryComponent {
2885
2973
  sanitizer = inject(DomSanitizer);
2886
2974
  entitlementSummary = [];
2887
- entitlementUsage = [];
2888
- sectionsConfig;
2889
- entitlementTab = signal('summary');
2890
- expandedEntitlements = new Set();
2891
- Math = Math;
2892
- _isSectionHidden(key) {
2893
- return isSectionHidden(this.sectionsConfig, key);
2894
- }
2895
- _getSectionLabel(key) {
2896
- return getSectionLabel(this.sectionsConfig, key);
2897
- }
2898
2975
  _getIcon(name) {
2899
2976
  return getIcon(this.sanitizer, name);
2900
2977
  }
2901
2978
  _capitalize(str) {
2902
2979
  return capitalize(str);
2903
2980
  }
2904
- _formatNumber(num) {
2905
- return formatNumber(num);
2906
- }
2907
- changeEntitlementTab(tab) {
2908
- this.entitlementTab.set(tab);
2909
- }
2910
- getMeteredEntitlements() {
2911
- return (this.entitlementUsage || []).filter((usage) => usage.type !== 'boolean' && usage.feature_type !== 'boolean');
2912
- }
2913
2981
  formatUsageModel(entitlement) {
2914
2982
  if (!entitlement.usage_model)
2915
2983
  return '';
2916
- const model = entitlement.usage_model.split('_').join(' ');
2984
+ const model = String(entitlement.usage_model).split('_').join(' ');
2917
2985
  let result = capitalize(model);
2918
2986
  if (entitlement.feature_type === 'metered') {
2919
2987
  if (entitlement.prepaid) {
2920
2988
  result += '/ Prepaid';
2921
2989
  }
2922
2990
  else if (entitlement.price_type) {
2923
- result += '/ ' + capitalize(entitlement.price_type);
2991
+ result += '/ ' + capitalize(String(entitlement.price_type));
2924
2992
  }
2925
2993
  }
2926
2994
  return result;
@@ -2933,9 +3001,9 @@ class EntitlementsSectionComponent {
2933
3001
  return 'Unlimited';
2934
3002
  if (allowance === null || allowance === undefined)
2935
3003
  return '0';
2936
- let result = formatNumber(allowance);
3004
+ let result = formatNumber(Number(allowance));
2937
3005
  if (entitlement.included_allowance_reset_interval && entitlement.included_allowance_reset_interval !== 'none') {
2938
- result += ' ' + getResetIntervalLabel(entitlement.included_allowance_reset_interval);
3006
+ result += ' ' + getResetIntervalLabel(String(entitlement.included_allowance_reset_interval));
2939
3007
  }
2940
3008
  return result;
2941
3009
  }
@@ -2946,17 +3014,17 @@ class EntitlementsSectionComponent {
2946
3014
  const limit = entitlement.usage_limit ?? 'Unlimited';
2947
3015
  if (limit === -1)
2948
3016
  return 'Unlimited';
2949
- let result = typeof limit === 'number' ? formatNumber(limit) : limit;
3017
+ let result = typeof limit === 'number' ? formatNumber(limit) : String(limit);
2950
3018
  if (entitlement.usage_limit_reset_interval && entitlement.usage_limit_reset_interval !== 'none') {
2951
- result += ' ' + getResetIntervalLabel(entitlement.usage_limit_reset_interval);
3019
+ result += ' ' + getResetIntervalLabel(String(entitlement.usage_limit_reset_interval));
2952
3020
  }
2953
3021
  return result;
2954
3022
  }
2955
3023
  if (entitlement.purchased_qty !== null && entitlement.purchased_qty !== undefined) {
2956
- const qty = entitlement.purchased_qty === -1 ? 'Unlimited' : formatNumber(entitlement.purchased_qty);
3024
+ const qty = entitlement.purchased_qty === -1 ? 'Unlimited' : formatNumber(Number(entitlement.purchased_qty));
2957
3025
  let interval = '';
2958
3026
  if (entitlement.billing_interval && entitlement.billing_interval !== 'none') {
2959
- interval = ' ' + getResetIntervalLabel(entitlement.billing_interval);
3027
+ interval = ' ' + getResetIntervalLabel(String(entitlement.billing_interval));
2960
3028
  }
2961
3029
  const softLimit = entitlement.soft_limit_enabled ? ' Soft limits enabled' : '';
2962
3030
  return qty + interval + softLimit;
@@ -2964,15 +3032,192 @@ class EntitlementsSectionComponent {
2964
3032
  if (entitlement.included_allowance !== null && entitlement.included_allowance !== undefined) {
2965
3033
  if (entitlement.included_allowance === -1)
2966
3034
  return 'Unlimited';
2967
- let result = formatNumber(entitlement.included_allowance);
3035
+ let result = formatNumber(Number(entitlement.included_allowance));
2968
3036
  if (entitlement.included_allowance_reset_interval && entitlement.included_allowance_reset_interval !== 'none') {
2969
- result += ' ' + getResetIntervalLabel(entitlement.included_allowance_reset_interval);
3037
+ result += ' ' + getResetIntervalLabel(String(entitlement.included_allowance_reset_interval));
2970
3038
  }
2971
3039
  return result;
2972
3040
  }
2973
3041
  return '0';
2974
3042
  }
2975
- toggleEntitlementExpand(id) {
3043
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EntitlementSummaryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3044
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: EntitlementSummaryComponent, isStandalone: true, selector: "cp-entitlement-summary", inputs: { entitlementSummary: "entitlementSummary" }, ngImport: i0, template: `
3045
+ <div class="overflow-x-auto bg-transparent">
3046
+ @if (entitlementSummary.length > 0) {
3047
+ <table class="min-w-full border-collapse text-left relative">
3048
+ <thead>
3049
+ <tr>
3050
+ <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3051
+ [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3052
+ [style.fontSize]="'var(--cp-table-header-size)'"
3053
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</th>
3054
+ <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3055
+ [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3056
+ [style.fontSize]="'var(--cp-table-header-size)'"
3057
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Meter type</th>
3058
+ <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3059
+ [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3060
+ [style.fontSize]="'var(--cp-table-header-size)'"
3061
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Included allowance</th>
3062
+ <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3063
+ [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3064
+ [style.fontSize]="'var(--cp-table-header-size)'"
3065
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Usage limits</th>
3066
+ </tr>
3067
+ </thead>
3068
+ <tbody>
3069
+ @for (entitlement of entitlementSummary; track entitlement.id || $index; let rowIdx = $index) {
3070
+ <tr [class]="rowIdx % 2 === 0 ? 'bg-[var(--cp-table-row-even-bg)]' : 'bg-[var(--cp-table-row-odd-bg)]'">
3071
+ <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3072
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3073
+ [style.fontSize]="'var(--cp-table-row-size)'"
3074
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3075
+ <div class="flex flex-col gap-y-1 items-start max-w-[130px]">
3076
+ <span>{{ entitlement.feature_name || '-' }}</span>
3077
+ <span class="text-[var(--cp-table-text)] max-w-[120px] truncate"
3078
+ [style.fontSize]="'var(--cp-table-row-size)'"
3079
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ entitlement.feature_key }}</span>
3080
+ </div>
3081
+ </td>
3082
+ <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3083
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3084
+ [style.fontSize]="'var(--cp-table-row-size)'"
3085
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3086
+ <div>
3087
+ <span>{{ _capitalize(entitlement.feature_type) }}</span>
3088
+ @if (entitlement.usage_model) {
3089
+ <span class="block mt-1">{{ formatUsageModel(entitlement) }}</span>
3090
+ }
3091
+ </div>
3092
+ </td>
3093
+ <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3094
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3095
+ [style.fontSize]="'var(--cp-table-row-size)'"
3096
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3097
+ {{ formatIncludedAllowance(entitlement) }}
3098
+ </td>
3099
+ <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3100
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3101
+ [style.fontSize]="'var(--cp-table-row-size)'"
3102
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3103
+ {{ formatUsageLimits(entitlement) }}
3104
+ </td>
3105
+ </tr>
3106
+ }
3107
+ </tbody>
3108
+ </table>
3109
+ } @else {
3110
+ <div class="flex flex-col items-center gap-y-3 py-12">
3111
+ <span [innerHTML]="_getIcon('noteEmpty')"></span>
3112
+ <span class="text-sm text-[var(--cp-section-empty-text)]">No entitlements attached to this subscription</span>
3113
+ </div>
3114
+ }
3115
+ </div>
3116
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3117
+ }
3118
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EntitlementSummaryComponent, decorators: [{
3119
+ type: Component,
3120
+ args: [{
3121
+ selector: 'cp-entitlement-summary',
3122
+ standalone: true,
3123
+ imports: [CommonModule],
3124
+ changeDetection: ChangeDetectionStrategy.OnPush,
3125
+ template: `
3126
+ <div class="overflow-x-auto bg-transparent">
3127
+ @if (entitlementSummary.length > 0) {
3128
+ <table class="min-w-full border-collapse text-left relative">
3129
+ <thead>
3130
+ <tr>
3131
+ <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3132
+ [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3133
+ [style.fontSize]="'var(--cp-table-header-size)'"
3134
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</th>
3135
+ <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3136
+ [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3137
+ [style.fontSize]="'var(--cp-table-header-size)'"
3138
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Meter type</th>
3139
+ <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3140
+ [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3141
+ [style.fontSize]="'var(--cp-table-header-size)'"
3142
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Included allowance</th>
3143
+ <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3144
+ [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3145
+ [style.fontSize]="'var(--cp-table-header-size)'"
3146
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Usage limits</th>
3147
+ </tr>
3148
+ </thead>
3149
+ <tbody>
3150
+ @for (entitlement of entitlementSummary; track entitlement.id || $index; let rowIdx = $index) {
3151
+ <tr [class]="rowIdx % 2 === 0 ? 'bg-[var(--cp-table-row-even-bg)]' : 'bg-[var(--cp-table-row-odd-bg)]'">
3152
+ <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3153
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3154
+ [style.fontSize]="'var(--cp-table-row-size)'"
3155
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3156
+ <div class="flex flex-col gap-y-1 items-start max-w-[130px]">
3157
+ <span>{{ entitlement.feature_name || '-' }}</span>
3158
+ <span class="text-[var(--cp-table-text)] max-w-[120px] truncate"
3159
+ [style.fontSize]="'var(--cp-table-row-size)'"
3160
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ entitlement.feature_key }}</span>
3161
+ </div>
3162
+ </td>
3163
+ <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3164
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3165
+ [style.fontSize]="'var(--cp-table-row-size)'"
3166
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3167
+ <div>
3168
+ <span>{{ _capitalize(entitlement.feature_type) }}</span>
3169
+ @if (entitlement.usage_model) {
3170
+ <span class="block mt-1">{{ formatUsageModel(entitlement) }}</span>
3171
+ }
3172
+ </div>
3173
+ </td>
3174
+ <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3175
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3176
+ [style.fontSize]="'var(--cp-table-row-size)'"
3177
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3178
+ {{ formatIncludedAllowance(entitlement) }}
3179
+ </td>
3180
+ <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3181
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3182
+ [style.fontSize]="'var(--cp-table-row-size)'"
3183
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3184
+ {{ formatUsageLimits(entitlement) }}
3185
+ </td>
3186
+ </tr>
3187
+ }
3188
+ </tbody>
3189
+ </table>
3190
+ } @else {
3191
+ <div class="flex flex-col items-center gap-y-3 py-12">
3192
+ <span [innerHTML]="_getIcon('noteEmpty')"></span>
3193
+ <span class="text-sm text-[var(--cp-section-empty-text)]">No entitlements attached to this subscription</span>
3194
+ </div>
3195
+ }
3196
+ </div>
3197
+ `
3198
+ }]
3199
+ }], propDecorators: { entitlementSummary: [{
3200
+ type: Input
3201
+ }] } });
3202
+
3203
+ class EntitlementUsageComponent {
3204
+ sanitizer = inject(DomSanitizer);
3205
+ expandedEntitlements = new Set();
3206
+ Math = Math;
3207
+ entitlementUsage = [];
3208
+ get meteredEntitlements() {
3209
+ return (this.entitlementUsage || []).filter((usage) => usage.type !== 'boolean');
3210
+ }
3211
+ _getIcon(name) {
3212
+ return getIcon(this.sanitizer, name);
3213
+ }
3214
+ _capitalize(str) {
3215
+ return capitalize(str);
3216
+ }
3217
+ _formatNumber(num) {
3218
+ return formatNumber(num);
3219
+ }
3220
+ toggleExpand(id) {
2976
3221
  if (this.expandedEntitlements.has(id)) {
2977
3222
  this.expandedEntitlements.delete(id);
2978
3223
  }
@@ -2980,10 +3225,10 @@ class EntitlementsSectionComponent {
2980
3225
  this.expandedEntitlements.add(id);
2981
3226
  }
2982
3227
  }
2983
- isEntitlementExpanded(id) {
3228
+ isExpanded(id) {
2984
3229
  return this.expandedEntitlements.has(id);
2985
3230
  }
2986
- getEntitlementUsageBalance(usage) {
3231
+ getUsageBalance(usage) {
2987
3232
  const pools = this.getProcessedPools(usage);
2988
3233
  const isAnyUnlimited = pools.some((p) => p.isUnlimited);
2989
3234
  const totalBalance = pools.filter((p) => !p.isUnlimited).reduce((sum, p) => sum + p.balance, 0);
@@ -2993,7 +3238,7 @@ class EntitlementsSectionComponent {
2993
3238
  return formatNumber(Math.abs(totalBalance)) + ' used above limit';
2994
3239
  return formatNumber(totalBalance) + ' left';
2995
3240
  }
2996
- getEntitlementUsagePercent(usage) {
3241
+ getUsagePercent(usage) {
2997
3242
  const pools = this.getProcessedPools(usage);
2998
3243
  const isAnyUnlimited = pools.some((p) => p.isUnlimited);
2999
3244
  if (isAnyUnlimited)
@@ -3004,7 +3249,7 @@ class EntitlementsSectionComponent {
3004
3249
  return 0;
3005
3250
  return Math.min((totalUsed / totalAmount) * 100, 100);
3006
3251
  }
3007
- getEntitlementUsageText(usage) {
3252
+ getUsageText(usage) {
3008
3253
  const pools = this.getProcessedPools(usage);
3009
3254
  const isAnyUnlimited = pools.some((p) => p.isUnlimited);
3010
3255
  const totalAmount = pools.filter((p) => !p.isUnlimited).reduce((sum, p) => sum + p.amount, 0);
@@ -3019,13 +3264,14 @@ class EntitlementsSectionComponent {
3019
3264
  { key: 'included_pool', name: 'Included', color: 'gray-400', order: 1 },
3020
3265
  { key: 'purchased_pool', name: 'Purchased', color: 'gray-400', order: 2 },
3021
3266
  { key: 'pay_as_you_go_pool', name: 'Pay as you go', color: 'blue-500', order: 3 },
3022
- { key: 'rollover_quantity_pool', name: 'Rollover', color: 'green-500', order: 4 },
3267
+ { key: 'rollover_quantity_pool', name: 'Rollover', color: 'green-500', order: 4 }
3023
3268
  ];
3024
3269
  for (const config of poolConfigs) {
3025
- const pool = usage[config.key];
3026
- if (pool) {
3027
- const amount = pool.amount === null ? Infinity : parseFloat(pool.amount) || 0;
3028
- const used = parseFloat(pool.used) || 0;
3270
+ const rawPool = usage[config.key];
3271
+ if (rawPool && typeof rawPool === 'object') {
3272
+ const pool = rawPool;
3273
+ const amount = pool.amount === null ? Infinity : parseFloat(String(pool.amount)) || 0;
3274
+ const used = parseFloat(String(pool.used)) || 0;
3029
3275
  const balance = amount === Infinity ? Infinity : amount - used;
3030
3276
  const isUnlimited = amount === Infinity;
3031
3277
  const percent = isUnlimited ? 100 : (amount > 0 ? (used / amount) * 100 : 0);
@@ -3038,26 +3284,297 @@ class EntitlementsSectionComponent {
3038
3284
  percent: Math.min(percent, 100),
3039
3285
  isUnlimited,
3040
3286
  order: config.order,
3041
- nextResetAt: pool.next_reset_at ? this.formatResetDate(pool.next_reset_at) : null,
3287
+ nextResetAt: pool.next_reset_at ? this.formatResetDate(String(pool.next_reset_at)) : null
3042
3288
  });
3043
3289
  }
3044
3290
  }
3045
- return pools.sort((a, b) => a.order - b.order);
3291
+ return pools.sort((a, b) => a.order - b.order);
3292
+ }
3293
+ formatResetDate(dateStr) {
3294
+ if (!dateStr)
3295
+ return '';
3296
+ const date = new Date(dateStr);
3297
+ return date
3298
+ .toLocaleDateString('en-US', {
3299
+ month: 'short',
3300
+ day: 'numeric',
3301
+ year: 'numeric',
3302
+ hour: 'numeric',
3303
+ minute: '2-digit',
3304
+ hour12: true
3305
+ })
3306
+ .toLowerCase();
3307
+ }
3308
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EntitlementUsageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3309
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: EntitlementUsageComponent, isStandalone: true, selector: "cp-entitlement-usage", inputs: { entitlementUsage: "entitlementUsage" }, ngImport: i0, template: `
3310
+ <div class="bg-transparent rounded-2xl px-3 pt-5">
3311
+ @if (meteredEntitlements.length > 0) {
3312
+ <!-- Header -->
3313
+ <div class="grid grid-cols-4 border-b border-[var(--cp-table-border)] gap-x-4 pr-12 bg-[var(--cp-table-header-bg)]"
3314
+ [style.padding]="'var(--cp-table-cell-padding, 0.75rem 1.5rem)'">
3315
+ <div class="text-[var(--cp-table-header-text)]"
3316
+ [style.fontSize]="'var(--cp-table-header-size)'"
3317
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</div>
3318
+ <div class="text-[var(--cp-table-header-text)]"
3319
+ [style.fontSize]="'var(--cp-table-header-size)'"
3320
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Type</div>
3321
+ <div class="col-span-2 text-[var(--cp-table-header-text)]"
3322
+ [style.fontSize]="'var(--cp-table-header-size)'"
3323
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Usage</div>
3324
+ </div>
3325
+
3326
+ <!-- Rows -->
3327
+ @for (usage of meteredEntitlements; track usage.id || $index; let rowIdx = $index) {
3328
+ <div class="border-b border-[var(--cp-table-border)] last:border-0"
3329
+ [class]="rowIdx % 2 === 0 ? 'bg-[var(--cp-table-row-even-bg)]' : 'bg-[var(--cp-table-row-odd-bg)]'"
3330
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 1.5rem)'">
3331
+ <!-- Main Row (Collapsible Trigger) -->
3332
+ <div class="flex items-center cursor-pointer" (click)="toggleExpand(usage.id)">
3333
+ <div class="flex-1 grid grid-cols-4 gap-4 items-center pr-8">
3334
+ <!-- Feature -->
3335
+ <div class="flex flex-col gap-y-1 items-start max-w-[120px] text-balance">
3336
+ <span class="text-[var(--cp-table-text)]"
3337
+ [style.fontSize]="'var(--cp-table-row-size)'"
3338
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ usage.feature_name || '-' }}</span>
3339
+ <span class="text-[var(--cp-table-text)] max-w-[120px] truncate"
3340
+ [style.fontSize]="'var(--cp-table-row-size)'"
3341
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ usage.feature_key }}</span>
3342
+ </div>
3343
+
3344
+ <!-- Type -->
3345
+ <div>
3346
+ <span class="text-[var(--cp-table-text)]"
3347
+ [style.fontSize]="'var(--cp-table-row-size)'"
3348
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ _capitalize(usage.type?.split('_').join(' ') || '') }}</span>
3349
+ </div>
3350
+
3351
+ <!-- Usage -->
3352
+ <div class="col-span-2">
3353
+ <span class="text-[var(--cp-table-text)]"
3354
+ [style.fontSize]="'var(--cp-table-row-size)'"
3355
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getUsageBalance(usage) }}</span>
3356
+ <div class="w-full flex items-center gap-x-2">
3357
+ <div class="w-full max-w-[24rem] h-[6px] my-[6px] bg-[var(--cp-section-usage-bar-track-color,#E4E4E7)] flex items-center justify-start rounded overflow-hidden">
3358
+ <div class="h-[6px] rounded" [style.width.%]="getUsagePercent(usage)" [style.backgroundColor]="'var(--cp-section-usage-bar-color)'"></div>
3359
+ </div>
3360
+ <span class="text-[var(--cp-table-text)]"
3361
+ [style.fontSize]="'var(--cp-table-row-size)'"
3362
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getUsageText(usage) }}</span>
3363
+ </div>
3364
+ </div>
3365
+ </div>
3366
+
3367
+ <!-- Expand Icon -->
3368
+ <div class="transform transition-transform duration-200"
3369
+ [class.rotate-180]="isExpanded(usage.id)"
3370
+ [style.color]="'var(--cp-table-expand-icon-color, #71717a)'">
3371
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg>
3372
+ </div>
3373
+ </div>
3374
+
3375
+ <!-- Expanded Content (Pools) -->
3376
+ @if (isExpanded(usage.id)) {
3377
+ <div class="w-full rounded-lg overflow-hidden flex flex-col items-start justify-start gap-y-0 pt-4">
3378
+ @for (pool of getProcessedPools(usage); track pool.pool) {
3379
+ <div class="w-full flex items-center px-2 py-3 gap-x-12 sm:gap-x-20 md:gap-x-40">
3380
+ <span class="w-20 text-[var(--cp-table-text)]"
3381
+ [style.fontSize]="'var(--cp-table-row-size)'"
3382
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ pool.pool }}</span>
3383
+ <div class="flex-1">
3384
+ <span class="text-[var(--cp-table-text)]"
3385
+ [style.fontSize]="'var(--cp-table-row-size)'"
3386
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3387
+ @if (!pool.isUnlimited) {
3388
+ @if (pool.balance < 0) {
3389
+ {{ _formatNumber(Math.abs(pool.balance)) }} used above limit
3390
+ } @else {
3391
+ {{ _formatNumber(pool.balance) }} left
3392
+ }
3393
+ }
3394
+ </span>
3395
+ <div class="w-full flex items-center gap-x-2">
3396
+ <div class="w-full max-w-[18rem] h-[6px] my-[6px] bg-[var(--cp-section-usage-bar-track-color,#E4E4E7)] flex items-center justify-start rounded overflow-hidden">
3397
+ <div class="h-[6px]" [style.width.%]="pool.percent" [style.backgroundColor]="'var(--cp-section-usage-bar-color)'"></div>
3398
+ </div>
3399
+ <span class="text-[var(--cp-table-text)]"
3400
+ [style.fontSize]="'var(--cp-table-row-size)'"
3401
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3402
+ @if (pool.isUnlimited) {
3403
+ {{ _formatNumber(pool.used) }}/ Unlimited
3404
+ } @else {
3405
+ {{ _formatNumber(pool.used) }}/{{ _formatNumber(pool.amount) }}
3406
+ }
3407
+ </span>
3408
+ </div>
3409
+ @if (pool.nextResetAt) {
3410
+ <span class="text-[var(--cp-table-text)]"
3411
+ [style.fontSize]="'var(--cp-table-row-size)'"
3412
+ [style.fontWeight]="'var(--cp-table-row-weight)'">resets on {{ pool.nextResetAt }}</span>
3413
+ }
3414
+ </div>
3415
+ </div>
3416
+ }
3417
+ </div>
3418
+ }
3419
+ </div>
3420
+ }
3421
+ } @else {
3422
+ <div class="flex flex-col items-center gap-y-3 py-12">
3423
+ <span [innerHTML]="_getIcon('noteEmpty')"></span>
3424
+ <span class="text-sm text-[var(--cp-section-empty-text)]">No metered entitlements attached to this subscription</span>
3425
+ </div>
3426
+ }
3427
+ </div>
3428
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3429
+ }
3430
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EntitlementUsageComponent, decorators: [{
3431
+ type: Component,
3432
+ args: [{
3433
+ selector: 'cp-entitlement-usage',
3434
+ standalone: true,
3435
+ imports: [CommonModule],
3436
+ changeDetection: ChangeDetectionStrategy.OnPush,
3437
+ template: `
3438
+ <div class="bg-transparent rounded-2xl px-3 pt-5">
3439
+ @if (meteredEntitlements.length > 0) {
3440
+ <!-- Header -->
3441
+ <div class="grid grid-cols-4 border-b border-[var(--cp-table-border)] gap-x-4 pr-12 bg-[var(--cp-table-header-bg)]"
3442
+ [style.padding]="'var(--cp-table-cell-padding, 0.75rem 1.5rem)'">
3443
+ <div class="text-[var(--cp-table-header-text)]"
3444
+ [style.fontSize]="'var(--cp-table-header-size)'"
3445
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</div>
3446
+ <div class="text-[var(--cp-table-header-text)]"
3447
+ [style.fontSize]="'var(--cp-table-header-size)'"
3448
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Type</div>
3449
+ <div class="col-span-2 text-[var(--cp-table-header-text)]"
3450
+ [style.fontSize]="'var(--cp-table-header-size)'"
3451
+ [style.fontWeight]="'var(--cp-table-header-weight)'">Usage</div>
3452
+ </div>
3453
+
3454
+ <!-- Rows -->
3455
+ @for (usage of meteredEntitlements; track usage.id || $index; let rowIdx = $index) {
3456
+ <div class="border-b border-[var(--cp-table-border)] last:border-0"
3457
+ [class]="rowIdx % 2 === 0 ? 'bg-[var(--cp-table-row-even-bg)]' : 'bg-[var(--cp-table-row-odd-bg)]'"
3458
+ [style.padding]="'var(--cp-table-cell-padding, 1rem 1.5rem)'">
3459
+ <!-- Main Row (Collapsible Trigger) -->
3460
+ <div class="flex items-center cursor-pointer" (click)="toggleExpand(usage.id)">
3461
+ <div class="flex-1 grid grid-cols-4 gap-4 items-center pr-8">
3462
+ <!-- Feature -->
3463
+ <div class="flex flex-col gap-y-1 items-start max-w-[120px] text-balance">
3464
+ <span class="text-[var(--cp-table-text)]"
3465
+ [style.fontSize]="'var(--cp-table-row-size)'"
3466
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ usage.feature_name || '-' }}</span>
3467
+ <span class="text-[var(--cp-table-text)] max-w-[120px] truncate"
3468
+ [style.fontSize]="'var(--cp-table-row-size)'"
3469
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ usage.feature_key }}</span>
3470
+ </div>
3471
+
3472
+ <!-- Type -->
3473
+ <div>
3474
+ <span class="text-[var(--cp-table-text)]"
3475
+ [style.fontSize]="'var(--cp-table-row-size)'"
3476
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ _capitalize(usage.type?.split('_').join(' ') || '') }}</span>
3477
+ </div>
3478
+
3479
+ <!-- Usage -->
3480
+ <div class="col-span-2">
3481
+ <span class="text-[var(--cp-table-text)]"
3482
+ [style.fontSize]="'var(--cp-table-row-size)'"
3483
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getUsageBalance(usage) }}</span>
3484
+ <div class="w-full flex items-center gap-x-2">
3485
+ <div class="w-full max-w-[24rem] h-[6px] my-[6px] bg-[var(--cp-section-usage-bar-track-color,#E4E4E7)] flex items-center justify-start rounded overflow-hidden">
3486
+ <div class="h-[6px] rounded" [style.width.%]="getUsagePercent(usage)" [style.backgroundColor]="'var(--cp-section-usage-bar-color)'"></div>
3487
+ </div>
3488
+ <span class="text-[var(--cp-table-text)]"
3489
+ [style.fontSize]="'var(--cp-table-row-size)'"
3490
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getUsageText(usage) }}</span>
3491
+ </div>
3492
+ </div>
3493
+ </div>
3494
+
3495
+ <!-- Expand Icon -->
3496
+ <div class="transform transition-transform duration-200"
3497
+ [class.rotate-180]="isExpanded(usage.id)"
3498
+ [style.color]="'var(--cp-table-expand-icon-color, #71717a)'">
3499
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg>
3500
+ </div>
3501
+ </div>
3502
+
3503
+ <!-- Expanded Content (Pools) -->
3504
+ @if (isExpanded(usage.id)) {
3505
+ <div class="w-full rounded-lg overflow-hidden flex flex-col items-start justify-start gap-y-0 pt-4">
3506
+ @for (pool of getProcessedPools(usage); track pool.pool) {
3507
+ <div class="w-full flex items-center px-2 py-3 gap-x-12 sm:gap-x-20 md:gap-x-40">
3508
+ <span class="w-20 text-[var(--cp-table-text)]"
3509
+ [style.fontSize]="'var(--cp-table-row-size)'"
3510
+ [style.fontWeight]="'var(--cp-table-row-weight)'">{{ pool.pool }}</span>
3511
+ <div class="flex-1">
3512
+ <span class="text-[var(--cp-table-text)]"
3513
+ [style.fontSize]="'var(--cp-table-row-size)'"
3514
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3515
+ @if (!pool.isUnlimited) {
3516
+ @if (pool.balance < 0) {
3517
+ {{ _formatNumber(Math.abs(pool.balance)) }} used above limit
3518
+ } @else {
3519
+ {{ _formatNumber(pool.balance) }} left
3520
+ }
3521
+ }
3522
+ </span>
3523
+ <div class="w-full flex items-center gap-x-2">
3524
+ <div class="w-full max-w-[18rem] h-[6px] my-[6px] bg-[var(--cp-section-usage-bar-track-color,#E4E4E7)] flex items-center justify-start rounded overflow-hidden">
3525
+ <div class="h-[6px]" [style.width.%]="pool.percent" [style.backgroundColor]="'var(--cp-section-usage-bar-color)'"></div>
3526
+ </div>
3527
+ <span class="text-[var(--cp-table-text)]"
3528
+ [style.fontSize]="'var(--cp-table-row-size)'"
3529
+ [style.fontWeight]="'var(--cp-table-row-weight)'">
3530
+ @if (pool.isUnlimited) {
3531
+ {{ _formatNumber(pool.used) }}/ Unlimited
3532
+ } @else {
3533
+ {{ _formatNumber(pool.used) }}/{{ _formatNumber(pool.amount) }}
3534
+ }
3535
+ </span>
3536
+ </div>
3537
+ @if (pool.nextResetAt) {
3538
+ <span class="text-[var(--cp-table-text)]"
3539
+ [style.fontSize]="'var(--cp-table-row-size)'"
3540
+ [style.fontWeight]="'var(--cp-table-row-weight)'">resets on {{ pool.nextResetAt }}</span>
3541
+ }
3542
+ </div>
3543
+ </div>
3544
+ }
3545
+ </div>
3546
+ }
3547
+ </div>
3548
+ }
3549
+ } @else {
3550
+ <div class="flex flex-col items-center gap-y-3 py-12">
3551
+ <span [innerHTML]="_getIcon('noteEmpty')"></span>
3552
+ <span class="text-sm text-[var(--cp-section-empty-text)]">No metered entitlements attached to this subscription</span>
3553
+ </div>
3554
+ }
3555
+ </div>
3556
+ `
3557
+ }]
3558
+ }], propDecorators: { entitlementUsage: [{
3559
+ type: Input
3560
+ }] } });
3561
+
3562
+ class EntitlementsSectionComponent {
3563
+ entitlementSummary = [];
3564
+ entitlementUsage = [];
3565
+ sectionsConfig;
3566
+ entitlementTab = signal('summary');
3567
+ get hasMeteredEntitlements() {
3568
+ return (this.entitlementUsage || []).some((usage) => usage.type !== 'boolean');
3046
3569
  }
3047
- formatResetDate(dateStr) {
3048
- if (!dateStr)
3049
- return '';
3050
- const date = new Date(dateStr);
3051
- return date
3052
- .toLocaleDateString('en-US', {
3053
- month: 'short',
3054
- day: 'numeric',
3055
- year: 'numeric',
3056
- hour: 'numeric',
3057
- minute: '2-digit',
3058
- hour12: true,
3059
- })
3060
- .toLowerCase();
3570
+ _isSectionHidden(key) {
3571
+ return isSectionHidden(this.sectionsConfig, key);
3572
+ }
3573
+ _getSectionLabel(key) {
3574
+ return getSectionLabel(this.sectionsConfig, key);
3575
+ }
3576
+ changeEntitlementTab(tab) {
3577
+ this.entitlementTab.set(tab);
3061
3578
  }
3062
3579
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EntitlementsSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3063
3580
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: EntitlementsSectionComponent, isStandalone: true, selector: "cp-entitlements-section", inputs: { entitlementSummary: "entitlementSummary", entitlementUsage: "entitlementUsage", sectionsConfig: "sectionsConfig" }, ngImport: i0, template: `
@@ -3089,7 +3606,7 @@ class EntitlementsSectionComponent {
3089
3606
  (click)="changeEntitlementTab('summary')">
3090
3607
  Summary
3091
3608
  </button>
3092
- @if (getMeteredEntitlements().length > 0) {
3609
+ @if (hasMeteredEntitlements) {
3093
3610
  <button
3094
3611
  type="button"
3095
3612
  class="px-6 py-1.5 rounded-md text-sm font-medium transition-all outline-none"
@@ -3104,188 +3621,24 @@ class EntitlementsSectionComponent {
3104
3621
 
3105
3622
  <!-- Summary Tab Content -->
3106
3623
  @if (entitlementTab() === 'summary') {
3107
- <div class="overflow-x-auto bg-transparent">
3108
- @if (entitlementSummary.length > 0) {
3109
- <table class="min-w-full border-collapse text-left relative">
3110
- <thead>
3111
- <tr>
3112
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3113
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3114
- [style.fontSize]="'var(--cp-table-header-size)'"
3115
- [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</th>
3116
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3117
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3118
- [style.fontSize]="'var(--cp-table-header-size)'"
3119
- [style.fontWeight]="'var(--cp-table-header-weight)'">Meter type</th>
3120
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3121
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3122
- [style.fontSize]="'var(--cp-table-header-size)'"
3123
- [style.fontWeight]="'var(--cp-table-header-weight)'">Included allowance</th>
3124
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3125
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3126
- [style.fontSize]="'var(--cp-table-header-size)'"
3127
- [style.fontWeight]="'var(--cp-table-header-weight)'">Usage limits</th>
3128
- </tr>
3129
- </thead>
3130
- <tbody>
3131
- @for (entitlement of entitlementSummary; track entitlement.id || $index; let rowIdx = $index) {
3132
- <tr [class]="rowIdx % 2 === 0 ? 'bg-[var(--cp-table-row-even-bg)]' : 'bg-[var(--cp-table-row-odd-bg)]'">
3133
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3134
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3135
- [style.fontSize]="'var(--cp-table-row-size)'"
3136
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3137
- <div class="flex flex-col gap-y-1 items-start max-w-[130px]">
3138
- <span>{{ entitlement.feature_name || '-' }}</span>
3139
- <span class="text-xs bg-gray-100 text-gray-800 px-2 py-0.5 rounded max-w-[120px] truncate">{{ entitlement.feature_key }}</span>
3140
- </div>
3141
- </td>
3142
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3143
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3144
- [style.fontSize]="'var(--cp-table-row-size)'"
3145
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3146
- <div>
3147
- <span>{{ _capitalize(entitlement.feature_type) }}</span>
3148
- @if (entitlement.usage_model) {
3149
- <span class="block mt-1">{{ formatUsageModel(entitlement) }}</span>
3150
- }
3151
- </div>
3152
- </td>
3153
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3154
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3155
- [style.fontSize]="'var(--cp-table-row-size)'"
3156
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3157
- {{ formatIncludedAllowance(entitlement) }}
3158
- </td>
3159
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3160
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3161
- [style.fontSize]="'var(--cp-table-row-size)'"
3162
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3163
- {{ formatUsageLimits(entitlement) }}
3164
- </td>
3165
- </tr>
3166
- }
3167
- </tbody>
3168
- </table>
3169
- } @else {
3170
- <div class="flex flex-col items-center gap-y-3 py-12">
3171
- <span [innerHTML]="_getIcon('noteEmpty')"></span>
3172
- <span class="text-sm text-[var(--cp-section-empty-text)]">No entitlements attached to this subscription</span>
3173
- </div>
3174
- }
3175
- </div>
3624
+ <cp-entitlement-summary [entitlementSummary]="entitlementSummary"></cp-entitlement-summary>
3176
3625
  }
3177
3626
 
3178
3627
  <!-- Usage Tab Content -->
3179
3628
  @if (entitlementTab() === 'usage') {
3180
- <div class="bg-transparent rounded-2xl px-3 pt-5">
3181
- @if (getMeteredEntitlements().length > 0) {
3182
- <!-- Header -->
3183
- <div class="grid grid-cols-4 border-b border-[var(--cp-table-border)] gap-x-4 py-3 pl-3 pr-12 bg-[var(--cp-table-header-bg)]">
3184
- <div class="text-[var(--cp-table-header-text)]"
3185
- [style.fontSize]="'var(--cp-table-header-size)'"
3186
- [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</div>
3187
- <div class="text-[var(--cp-table-header-text)]"
3188
- [style.fontSize]="'var(--cp-table-header-size)'"
3189
- [style.fontWeight]="'var(--cp-table-header-weight)'">Type</div>
3190
- <div class="col-span-2 text-[var(--cp-table-header-text)]"
3191
- [style.fontSize]="'var(--cp-table-header-size)'"
3192
- [style.fontWeight]="'var(--cp-table-header-weight)'">Usage</div>
3193
- </div>
3194
-
3195
- <!-- Rows -->
3196
- @for (usage of getMeteredEntitlements(); track usage.id || $index) {
3197
- <div class="py-4 px-4 border-b border-[var(--cp-table-border)] last:border-0">
3198
- <!-- Main Row (Collapsible Trigger) -->
3199
- <div class="flex items-center cursor-pointer" (click)="toggleEntitlementExpand(usage.id)">
3200
- <div class="flex-1 grid grid-cols-4 gap-4 items-center pr-8">
3201
- <!-- Feature -->
3202
- <div class="flex flex-col gap-y-1 items-start max-w-[120px]">
3203
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">{{ usage.feature_name || '-' }}</span>
3204
- <span class="text-xs bg-gray-100 text-gray-800 px-2 py-0.5 rounded max-w-[120px] truncate">{{ usage.feature_key }}</span>
3205
- </div>
3206
-
3207
- <!-- Type -->
3208
- <div>
3209
- <span class="text-xs text-[var(--cp-link-color)]">{{ _capitalize(usage.type?.split('_').join(' ') || '') }}</span>
3210
- </div>
3211
-
3212
- <!-- Usage -->
3213
- <div class="col-span-2">
3214
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">{{ getEntitlementUsageBalance(usage) }}</span>
3215
- <div class="flex items-center gap-x-2">
3216
- <div class="w-96 h-1.5 my-1.5 bg-[var(--cp-section-usage-bar-track-color,#E4E4E7)] flex items-start justify-start rounded overflow-hidden">
3217
- <div class="h-1.5 bg-[var(--cp-section-usage-bar-color,#006FEE)] rounded" [style.width.%]="getEntitlementUsagePercent(usage)"></div>
3218
- </div>
3219
- <span class="text-[var(--cp-table-text)]"
3220
- [style.fontSize]="'var(--cp-table-row-size)'"
3221
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getEntitlementUsageText(usage) }}</span>
3222
- </div>
3223
- </div>
3224
- </div>
3225
-
3226
- <!-- Expand Icon -->
3227
- <div class="transform transition-transform duration-200" [class.rotate-180]="isEntitlementExpanded(usage.id)">
3228
- <span [innerHTML]="_getIcon('arrowDown')"></span>
3229
- </div>
3230
- </div>
3231
-
3232
- <!-- Expanded Content (Pools) -->
3233
- @if (isEntitlementExpanded(usage.id)) {
3234
- <div class="w-full rounded-lg overflow-hidden flex flex-col items-start justify-start gap-y-0 pt-4">
3235
- @for (pool of getProcessedPools(usage); track pool.pool) {
3236
- <div class="w-full flex items-center px-6 py-3 gap-x-40">
3237
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)] w-20">{{ pool.pool }}</span>
3238
- <div>
3239
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">
3240
- @if (!pool.isUnlimited) {
3241
- @if (pool.balance < 0) {
3242
- {{ _formatNumber(Math.abs(pool.balance)) }} used above limit
3243
- } @else {
3244
- {{ _formatNumber(pool.balance) }} left
3245
- }
3246
- }
3247
- </span>
3248
- <div class="flex items-center gap-x-2">
3249
- <div class="w-72 h-1.5 my-1.5 bg-[var(--cp-section-usage-bar-track-color,#E4E4E7)] flex items-start justify-start rounded overflow-hidden">
3250
- <div class="h-1.5 rounded" [class]="'bg-' + pool.color" [style.width.%]="pool.percent"></div>
3251
- </div>
3252
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">
3253
- @if (pool.isUnlimited) {
3254
- {{ _formatNumber(pool.used) }}/ Unlimited
3255
- } @else {
3256
- {{ _formatNumber(pool.used) }}/{{ _formatNumber(pool.amount) }}
3257
- }
3258
- </span>
3259
- </div>
3260
- @if (pool.nextResetAt) {
3261
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">resets on {{ pool.nextResetAt }}</span>
3262
- }
3263
- </div>
3264
- </div>
3265
- }
3266
- </div>
3267
- }
3268
- </div>
3269
- }
3270
- } @else {
3271
- <div class="flex flex-col items-center gap-y-3 py-12">
3272
- <span [innerHTML]="_getIcon('noteEmpty')"></span>
3273
- <span class="text-sm text-[var(--cp-section-empty-text)]">No metered entitlements attached to this subscription</span>
3274
- </div>
3275
- }
3276
- </div>
3629
+ <cp-entitlement-usage [entitlementUsage]="entitlementUsage"></cp-entitlement-usage>
3277
3630
  }
3278
3631
  </div>
3279
3632
  </div>
3280
3633
  }
3281
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3634
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: EntitlementSummaryComponent, selector: "cp-entitlement-summary", inputs: ["entitlementSummary"] }, { kind: "component", type: EntitlementUsageComponent, selector: "cp-entitlement-usage", inputs: ["entitlementUsage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3282
3635
  }
3283
3636
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EntitlementsSectionComponent, decorators: [{
3284
3637
  type: Component,
3285
3638
  args: [{
3286
3639
  selector: 'cp-entitlements-section',
3287
3640
  standalone: true,
3288
- imports: [CommonModule],
3641
+ imports: [CommonModule, EntitlementSummaryComponent, EntitlementUsageComponent],
3289
3642
  changeDetection: ChangeDetectionStrategy.OnPush,
3290
3643
  template: `
3291
3644
  @if (!_isSectionHidden('entitlementUsage')) {
@@ -3316,7 +3669,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
3316
3669
  (click)="changeEntitlementTab('summary')">
3317
3670
  Summary
3318
3671
  </button>
3319
- @if (getMeteredEntitlements().length > 0) {
3672
+ @if (hasMeteredEntitlements) {
3320
3673
  <button
3321
3674
  type="button"
3322
3675
  class="px-6 py-1.5 rounded-md text-sm font-medium transition-all outline-none"
@@ -3331,181 +3684,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
3331
3684
 
3332
3685
  <!-- Summary Tab Content -->
3333
3686
  @if (entitlementTab() === 'summary') {
3334
- <div class="overflow-x-auto bg-transparent">
3335
- @if (entitlementSummary.length > 0) {
3336
- <table class="min-w-full border-collapse text-left relative">
3337
- <thead>
3338
- <tr>
3339
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3340
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3341
- [style.fontSize]="'var(--cp-table-header-size)'"
3342
- [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</th>
3343
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3344
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3345
- [style.fontSize]="'var(--cp-table-header-size)'"
3346
- [style.fontWeight]="'var(--cp-table-header-weight)'">Meter type</th>
3347
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3348
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3349
- [style.fontSize]="'var(--cp-table-header-size)'"
3350
- [style.fontWeight]="'var(--cp-table-header-weight)'">Included allowance</th>
3351
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3352
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3353
- [style.fontSize]="'var(--cp-table-header-size)'"
3354
- [style.fontWeight]="'var(--cp-table-header-weight)'">Usage limits</th>
3355
- </tr>
3356
- </thead>
3357
- <tbody>
3358
- @for (entitlement of entitlementSummary; track entitlement.id || $index; let rowIdx = $index) {
3359
- <tr [class]="rowIdx % 2 === 0 ? 'bg-[var(--cp-table-row-even-bg)]' : 'bg-[var(--cp-table-row-odd-bg)]'">
3360
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3361
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3362
- [style.fontSize]="'var(--cp-table-row-size)'"
3363
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3364
- <div class="flex flex-col gap-y-1 items-start max-w-[130px]">
3365
- <span>{{ entitlement.feature_name || '-' }}</span>
3366
- <span class="text-xs bg-gray-100 text-gray-800 px-2 py-0.5 rounded max-w-[120px] truncate">{{ entitlement.feature_key }}</span>
3367
- </div>
3368
- </td>
3369
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3370
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3371
- [style.fontSize]="'var(--cp-table-row-size)'"
3372
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3373
- <div>
3374
- <span>{{ _capitalize(entitlement.feature_type) }}</span>
3375
- @if (entitlement.usage_model) {
3376
- <span class="block mt-1">{{ formatUsageModel(entitlement) }}</span>
3377
- }
3378
- </div>
3379
- </td>
3380
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3381
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3382
- [style.fontSize]="'var(--cp-table-row-size)'"
3383
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3384
- {{ formatIncludedAllowance(entitlement) }}
3385
- </td>
3386
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3387
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3388
- [style.fontSize]="'var(--cp-table-row-size)'"
3389
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3390
- {{ formatUsageLimits(entitlement) }}
3391
- </td>
3392
- </tr>
3393
- }
3394
- </tbody>
3395
- </table>
3396
- } @else {
3397
- <div class="flex flex-col items-center gap-y-3 py-12">
3398
- <span [innerHTML]="_getIcon('noteEmpty')"></span>
3399
- <span class="text-sm text-[var(--cp-section-empty-text)]">No entitlements attached to this subscription</span>
3400
- </div>
3401
- }
3402
- </div>
3687
+ <cp-entitlement-summary [entitlementSummary]="entitlementSummary"></cp-entitlement-summary>
3403
3688
  }
3404
3689
 
3405
3690
  <!-- Usage Tab Content -->
3406
3691
  @if (entitlementTab() === 'usage') {
3407
- <div class="bg-transparent rounded-2xl px-3 pt-5">
3408
- @if (getMeteredEntitlements().length > 0) {
3409
- <!-- Header -->
3410
- <div class="grid grid-cols-4 border-b border-[var(--cp-table-border)] gap-x-4 py-3 pl-3 pr-12 bg-[var(--cp-table-header-bg)]">
3411
- <div class="text-[var(--cp-table-header-text)]"
3412
- [style.fontSize]="'var(--cp-table-header-size)'"
3413
- [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</div>
3414
- <div class="text-[var(--cp-table-header-text)]"
3415
- [style.fontSize]="'var(--cp-table-header-size)'"
3416
- [style.fontWeight]="'var(--cp-table-header-weight)'">Type</div>
3417
- <div class="col-span-2 text-[var(--cp-table-header-text)]"
3418
- [style.fontSize]="'var(--cp-table-header-size)'"
3419
- [style.fontWeight]="'var(--cp-table-header-weight)'">Usage</div>
3420
- </div>
3421
-
3422
- <!-- Rows -->
3423
- @for (usage of getMeteredEntitlements(); track usage.id || $index) {
3424
- <div class="py-4 px-4 border-b border-[var(--cp-table-border)] last:border-0">
3425
- <!-- Main Row (Collapsible Trigger) -->
3426
- <div class="flex items-center cursor-pointer" (click)="toggleEntitlementExpand(usage.id)">
3427
- <div class="flex-1 grid grid-cols-4 gap-4 items-center pr-8">
3428
- <!-- Feature -->
3429
- <div class="flex flex-col gap-y-1 items-start max-w-[120px]">
3430
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">{{ usage.feature_name || '-' }}</span>
3431
- <span class="text-xs bg-gray-100 text-gray-800 px-2 py-0.5 rounded max-w-[120px] truncate">{{ usage.feature_key }}</span>
3432
- </div>
3433
-
3434
- <!-- Type -->
3435
- <div>
3436
- <span class="text-xs text-[var(--cp-link-color)]">{{ _capitalize(usage.type?.split('_').join(' ') || '') }}</span>
3437
- </div>
3438
-
3439
- <!-- Usage -->
3440
- <div class="col-span-2">
3441
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">{{ getEntitlementUsageBalance(usage) }}</span>
3442
- <div class="flex items-center gap-x-2">
3443
- <div class="w-96 h-1.5 my-1.5 bg-[var(--cp-section-usage-bar-track-color,#E4E4E7)] flex items-start justify-start rounded overflow-hidden">
3444
- <div class="h-1.5 bg-[var(--cp-section-usage-bar-color,#006FEE)] rounded" [style.width.%]="getEntitlementUsagePercent(usage)"></div>
3445
- </div>
3446
- <span class="text-[var(--cp-table-text)]"
3447
- [style.fontSize]="'var(--cp-table-row-size)'"
3448
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getEntitlementUsageText(usage) }}</span>
3449
- </div>
3450
- </div>
3451
- </div>
3452
-
3453
- <!-- Expand Icon -->
3454
- <div class="transform transition-transform duration-200" [class.rotate-180]="isEntitlementExpanded(usage.id)">
3455
- <span [innerHTML]="_getIcon('arrowDown')"></span>
3456
- </div>
3457
- </div>
3458
-
3459
- <!-- Expanded Content (Pools) -->
3460
- @if (isEntitlementExpanded(usage.id)) {
3461
- <div class="w-full rounded-lg overflow-hidden flex flex-col items-start justify-start gap-y-0 pt-4">
3462
- @for (pool of getProcessedPools(usage); track pool.pool) {
3463
- <div class="w-full flex items-center px-6 py-3 gap-x-40">
3464
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)] w-20">{{ pool.pool }}</span>
3465
- <div>
3466
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">
3467
- @if (!pool.isUnlimited) {
3468
- @if (pool.balance < 0) {
3469
- {{ _formatNumber(Math.abs(pool.balance)) }} used above limit
3470
- } @else {
3471
- {{ _formatNumber(pool.balance) }} left
3472
- }
3473
- }
3474
- </span>
3475
- <div class="flex items-center gap-x-2">
3476
- <div class="w-72 h-1.5 my-1.5 bg-[var(--cp-section-usage-bar-track-color,#E4E4E7)] flex items-start justify-start rounded overflow-hidden">
3477
- <div class="h-1.5 rounded" [class]="'bg-' + pool.color" [style.width.%]="pool.percent"></div>
3478
- </div>
3479
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">
3480
- @if (pool.isUnlimited) {
3481
- {{ _formatNumber(pool.used) }}/ Unlimited
3482
- } @else {
3483
- {{ _formatNumber(pool.used) }}/{{ _formatNumber(pool.amount) }}
3484
- }
3485
- </span>
3486
- </div>
3487
- @if (pool.nextResetAt) {
3488
- <span class="text-[13px] leading-[120%] text-[var(--cp-table-text)]">resets on {{ pool.nextResetAt }}</span>
3489
- }
3490
- </div>
3491
- </div>
3492
- }
3493
- </div>
3494
- }
3495
- </div>
3496
- }
3497
- } @else {
3498
- <div class="flex flex-col items-center gap-y-3 py-12">
3499
- <span [innerHTML]="_getIcon('noteEmpty')"></span>
3500
- <span class="text-sm text-[var(--cp-section-empty-text)]">No metered entitlements attached to this subscription</span>
3501
- </div>
3502
- }
3503
- </div>
3692
+ <cp-entitlement-usage [entitlementUsage]="entitlementUsage"></cp-entitlement-usage>
3504
3693
  }
3505
3694
  </div>
3506
3695
  </div>
3507
3696
  }
3508
- `,
3697
+ `
3509
3698
  }]
3510
3699
  }], propDecorators: { entitlementSummary: [{
3511
3700
  type: Input
@@ -3696,7 +3885,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
3696
3885
  </div>
3697
3886
  </div>
3698
3887
  }
3699
- `,
3888
+ `
3700
3889
  }]
3701
3890
  }], propDecorators: { subscription: [{
3702
3891
  type: Input
@@ -3927,7 +4116,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
3927
4116
  </div>
3928
4117
  </div>
3929
4118
  }
3930
- `,
4119
+ `
3931
4120
  }]
3932
4121
  }], propDecorators: { billingHistory: [{
3933
4122
  type: Input
@@ -3973,7 +4162,7 @@ class PlansSectionComponent {
3973
4162
  monthly: 'Monthly',
3974
4163
  quarterly: 'Quarterly',
3975
4164
  biannually: 'Biannually',
3976
- yearly: 'Yearly',
4165
+ yearly: 'Yearly'
3977
4166
  };
3978
4167
  return labels[interval] || capitalize(interval);
3979
4168
  }
@@ -3981,36 +4170,40 @@ class PlansSectionComponent {
3981
4170
  const allPriceOptions = [
3982
4171
  ...(plan.price_options || []),
3983
4172
  ...(plan.entitlement_price_options || []),
3984
- ...(plan.credit_attachment_price_options || []),
4173
+ ...(plan.credit_attachment_price_options || [])
3985
4174
  ];
3986
4175
  return allPriceOptions.find((po) => po.price?.billing_interval === this.selectedPlanInterval());
3987
4176
  }
3988
4177
  getPlanPriceInteger(plan) {
3989
4178
  const priceOption = this.getPlanPriceOption(plan);
3990
- if (!priceOption?.price)
4179
+ const price = priceOption?.price;
4180
+ if (!price)
3991
4181
  return 'Contact';
3992
- let amount = priceOption.price.price;
3993
- if (priceOption.price.tiers?.length > 0) {
3994
- const tier = priceOption.price.tiers[0];
3995
- amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4182
+ let amount = price.price;
4183
+ const tiers = price.tiers;
4184
+ if (tiers && tiers.length > 0) {
4185
+ const tier = tiers[0];
4186
+ amount = (tier.unit_price || tier.package_price || tier.flat_fee || 0);
3996
4187
  }
3997
- const currency = priceOption.price.currency || 'USD';
4188
+ const currency = price.currency || 'USD';
3998
4189
  const symbol = getCurrencySymbol(currency);
3999
- const price = formatPriceAmount(amount);
4000
- const amountParts = price?.split('.');
4190
+ const formatted = formatPriceAmount(amount);
4191
+ const amountParts = formatted?.split('.');
4001
4192
  return `${symbol}${amountParts?.[0] ?? '0'}`;
4002
4193
  }
4003
4194
  getPlanPriceDecimal(plan) {
4004
4195
  const priceOption = this.getPlanPriceOption(plan);
4005
- if (!priceOption?.price)
4196
+ const price = priceOption?.price;
4197
+ if (!price)
4006
4198
  return '00';
4007
- let amount = priceOption.price.price;
4008
- if (priceOption.price.tiers?.length > 0) {
4009
- const tier = priceOption.price.tiers[0];
4010
- amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4199
+ let amount = price.price;
4200
+ const tiers = price.tiers;
4201
+ if (tiers && tiers.length > 0) {
4202
+ const tier = tiers[0];
4203
+ amount = (tier.unit_price || tier.package_price || tier.flat_fee || 0);
4011
4204
  }
4012
- const price = formatPriceAmount(amount);
4013
- const amountParts = price?.split('.');
4205
+ const formatted = formatPriceAmount(amount);
4206
+ const amountParts = formatted?.split('.');
4014
4207
  return amountParts && amountParts.length > 1 ? amountParts[1].padEnd(2, '0').slice(0, 2) : '00';
4015
4208
  }
4016
4209
  getMultiplyNumber(interval, intervalValue) {
@@ -4021,26 +4214,29 @@ class PlansSectionComponent {
4021
4214
  monthly: v,
4022
4215
  quarterly: 3 * v,
4023
4216
  biannually: 6 * v,
4024
- yearly: 12 * v,
4217
+ yearly: 12 * v
4025
4218
  };
4026
4219
  return map[interval] ?? v;
4027
4220
  }
4028
4221
  getPlanFixedPriceBilledAmount(plan) {
4029
4222
  const priceOption = this.getPlanPriceOption(plan);
4030
- if (!priceOption?.price)
4223
+ const price = priceOption?.price;
4224
+ if (!price)
4031
4225
  return 0;
4032
- let unitPrice = priceOption.price.price;
4033
- if (priceOption.price.tiers?.length) {
4034
- const tier = priceOption.price.tiers[0];
4035
- unitPrice = tier.unit_price ?? tier.package_price ?? tier.flat_fee ?? 0;
4226
+ let unitPrice = price.price;
4227
+ const tiers = price.tiers;
4228
+ if (tiers?.length) {
4229
+ const tier = tiers[0];
4230
+ unitPrice = (tier.unit_price ?? tier.package_price ?? tier.flat_fee ?? 0);
4036
4231
  }
4037
4232
  const interval = this.selectedPlanInterval();
4038
- const intervalValue = priceOption.price.billing_interval_value ?? 1;
4233
+ const intervalValue = price.billing_interval_value ?? 1;
4039
4234
  return this.getMultiplyNumber(interval, intervalValue) * (unitPrice ?? 0);
4040
4235
  }
4041
4236
  getPlanFixedPriceCurrencySymbol(plan) {
4042
4237
  const po = this.getPlanPriceOption(plan);
4043
- return getCurrencySymbol(po?.price?.currency);
4238
+ const price = po?.price;
4239
+ return getCurrencySymbol(price?.currency || 'USD');
4044
4240
  }
4045
4241
  hasFixedPrice(plan) {
4046
4242
  const interval = this.selectedPlanInterval();
@@ -4056,49 +4252,56 @@ class PlansSectionComponent {
4056
4252
  const interval = this.selectedPlanInterval();
4057
4253
  return [
4058
4254
  ...(plan.entitlement_price_options || []).filter((po) => po.price?.billing_interval === interval),
4059
- ...(plan.credit_attachment_price_options || []).filter((po) => po.price?.billing_interval === interval),
4255
+ ...(plan.credit_attachment_price_options || []).filter((po) => po.price?.billing_interval === interval)
4060
4256
  ];
4061
4257
  }
4062
4258
  getDynamicPriceName(priceOption) {
4063
- return priceOption?.price?.name || priceOption?.price?.owner?.feature?.name || priceOption?.price?.owner?.name || 'Feature';
4259
+ const price = priceOption?.price;
4260
+ const owner = price?.owner;
4261
+ const feature = owner && 'feature' in owner ? owner.feature : undefined;
4262
+ return price?.name || feature?.name || owner?.name || 'Feature';
4064
4263
  }
4065
4264
  formatDynamicPrice(priceOption) {
4066
- if (!priceOption?.price)
4265
+ const price = priceOption?.price;
4266
+ if (!price)
4067
4267
  return '';
4068
- const tiers = priceOption.price.tiers || [];
4268
+ const tiers = price.tiers || [];
4069
4269
  if (tiers.length === 0)
4070
4270
  return '';
4071
4271
  const tier = tiers[0];
4072
- const currency = priceOption.price.currency || 'USD';
4272
+ const currency = price.currency || 'USD';
4073
4273
  const symbol = getCurrencySymbol(currency);
4074
- const amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4274
+ const amount = (tier.unit_price || tier.package_price || tier.flat_fee || 0);
4075
4275
  const formattedAmount = formatPriceAmount(amount);
4076
- const owner = priceOption.price.owner;
4077
- const unitLabel = owner?.feature?.unit_singular || owner?.unit_singular || owner?.feature?.name || owner?.name || '';
4276
+ const owner = price.owner;
4277
+ const feature = owner && 'feature' in owner ? owner.feature : undefined;
4278
+ const unitLabel = feature?.unit_singular || owner?.unit_singular || feature?.name || owner?.name || '';
4078
4279
  return unitLabel ? `${symbol}${formattedAmount}/${unitLabel}` : `${symbol}${formattedAmount}`;
4079
4280
  }
4080
4281
  formatDynamicPriceFull(priceOption) {
4081
- if (!priceOption?.price)
4282
+ const price = priceOption?.price;
4283
+ if (!price)
4082
4284
  return '';
4083
- const tiers = priceOption.price.tiers || [];
4285
+ const tiers = price.tiers || [];
4084
4286
  if (tiers.length === 0)
4085
4287
  return '';
4086
4288
  const tier = tiers[0];
4087
- const currency = priceOption.price.currency || 'USD';
4289
+ const currency = price.currency || 'USD';
4088
4290
  const symbol = getCurrencySymbol(currency);
4089
- const amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4291
+ const amount = (tier.unit_price || tier.package_price || tier.flat_fee || 0);
4090
4292
  const name = this.getDynamicPriceName(priceOption);
4091
4293
  return `${symbol}${amount.toFixed(2)}/${name}`;
4092
4294
  }
4093
4295
  getDynamicPriceAmountDisplay(priceOption) {
4094
- if (!priceOption?.price)
4296
+ const price = priceOption?.price;
4297
+ if (!price)
4095
4298
  return '';
4096
- const tiers = priceOption.price.tiers || [];
4299
+ const tiers = price.tiers || [];
4097
4300
  if (tiers.length === 0)
4098
4301
  return '';
4099
4302
  const tier = tiers[0];
4100
- const amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4101
- const currency = priceOption.price.currency || 'USD';
4303
+ const amount = (tier.unit_price || tier.package_price || tier.flat_fee || 0);
4304
+ const currency = price.currency || 'USD';
4102
4305
  const symbol = getCurrencySymbol(currency);
4103
4306
  return `${symbol}${amount.toFixed(2)}`;
4104
4307
  }
@@ -4106,30 +4309,30 @@ class PlansSectionComponent {
4106
4309
  const prices = this.getDynamicPrices(plan);
4107
4310
  if (prices.length === 0)
4108
4311
  return '0';
4109
- const firstPrice = prices[0];
4110
- const tiers = firstPrice?.price?.tiers || [];
4312
+ const firstPriceObj = prices[0].price;
4313
+ const tiers = firstPriceObj?.tiers || [];
4111
4314
  if (tiers.length === 0)
4112
4315
  return '0';
4113
4316
  const tier = tiers[0];
4114
- const amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4115
- const currency = firstPrice?.price?.currency || 'USD';
4317
+ const amount = (tier.unit_price || tier.package_price || tier.flat_fee || 0);
4318
+ const currency = firstPriceObj?.currency || 'USD';
4116
4319
  const symbol = getCurrencySymbol(currency);
4117
- const price = formatPriceAmount(amount);
4118
- const amountParts = price?.split('.');
4320
+ const formatted = formatPriceAmount(amount);
4321
+ const amountParts = formatted?.split('.');
4119
4322
  return `${symbol}${amountParts?.[0] ?? '0'}`;
4120
4323
  }
4121
4324
  getMainDynamicPriceDecimal(plan) {
4122
4325
  const prices = this.getDynamicPrices(plan);
4123
4326
  if (prices.length === 0)
4124
4327
  return '00';
4125
- const firstPrice = prices[0];
4126
- const tiers = firstPrice?.price?.tiers || [];
4328
+ const firstPriceObj = prices[0].price;
4329
+ const tiers = firstPriceObj?.tiers || [];
4127
4330
  if (tiers.length === 0)
4128
4331
  return '00';
4129
4332
  const tier = tiers[0];
4130
- const amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4131
- const price = formatPriceAmount(amount);
4132
- const amountParts = price?.split('.');
4333
+ const amount = (tier.unit_price || tier.package_price || tier.flat_fee || 0);
4334
+ const formatted = formatPriceAmount(amount);
4335
+ const amountParts = formatted?.split('.');
4133
4336
  return amountParts && amountParts.length > 1 ? amountParts[1].padEnd(2, '0').slice(0, 2) : '00';
4134
4337
  }
4135
4338
  getMainDynamicPriceUnit(plan) {
@@ -4247,15 +4450,14 @@ class PlansSectionComponent {
4247
4450
  <div class="flex gap-x-2 overflow-x-auto whitespace-nowrap px-6 py-4 -mx-4">
4248
4451
  @for (plan of plans; track plan.id; let idx = $index) {
4249
4452
  <div
4250
- class="flex flex-col shrink-0 w-[330px] overflow-hidden"
4251
- [style.borderRadius]="'var(--pt-card-radius, 14px)'"
4453
+ class="flex flex-col shrink-0 w-[330px]"
4454
+ [style.borderRadius]="plan.is_current_plan ? 'var(--pt-current-sub-card-radius, var(--pt-card-radius, 1rem))' : 'var(--pt-card-radius, 1rem)'"
4252
4455
  [style.borderWidth]="'var(--pt-card-border-width, 1px)'"
4253
4456
  [style.borderStyle]="'solid'"
4254
- [style.borderColor]="'var(--pt-card-border)'"
4457
+ [style.borderColor]="'var(--pt-card-border, #e5e7eb)'"
4255
4458
  [style.background-color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-bg)' : 'var(--pt-card-header-bg)'">
4256
4459
  <!-- Card Header -->
4257
- <div class="flex items-center justify-between pl-4 pr-[5px] pt-[6px] pb-[2px] rounded-t-[14px]"
4258
- [style.background-color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-bg)' : 'var(--pt-card-header-bg)'">
4460
+ <div class="flex items-center justify-between pl-4 pr-[5px] pt-[6px] pb-[2px]">
4259
4461
  <span
4260
4462
  class="text-sm font-medium"
4261
4463
  [style.color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-text)' : 'var(--pt-card-header-text)'">
@@ -4272,12 +4474,11 @@ class PlansSectionComponent {
4272
4474
 
4273
4475
  <!-- Card Body -->
4274
4476
  <div
4275
- class="flex-grow rounded-[14px] w-full p-2 pb-10"
4276
- [style.background-color]="plan.is_current_plan ? undefined : 'var(--pt-card-bg, #ffffff)'"
4277
- [style.border]="'1px solid var(--pt-card-border, var(--cp-section-content-border))'"
4278
- [style.backgroundImage]="plan.is_current_plan ? 'linear-gradient(180deg, var(--pt-current-sub-card-gradient-color, #E4E4E7) 4.81%, rgba(222, 247, 100, 0) 42.31%)' : undefined"
4279
- [class.rounded-t-none]="!plan.is_current_plan"
4280
- [class.border-t-0]="!plan.is_current_plan">
4477
+ class="flex-grow w-full p-2 pb-10"
4478
+ [style.borderRadius]="'calc(' + (plan.is_current_plan ? 'var(--pt-current-sub-card-radius, var(--pt-card-radius, 1rem))' : 'var(--pt-card-radius, 1rem)') + ' - 2px)'"
4479
+ [style.border]="'1px solid ' + (plan.is_current_plan ? 'var(--pt-current-sub-card-header-bg)' : 'var(--pt-card-header-bg)')"
4480
+ [style.background-color]="'var(--pt-card-bg, #ffffff)'"
4481
+ [style.backgroundImage]="plan.is_current_plan ? 'var(--pt-card-gradient)' : undefined">
4281
4482
 
4282
4483
  <!-- Description -->
4283
4484
  @if (shouldShowPlanDescription()) {
@@ -4563,15 +4764,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
4563
4764
  <div class="flex gap-x-2 overflow-x-auto whitespace-nowrap px-6 py-4 -mx-4">
4564
4765
  @for (plan of plans; track plan.id; let idx = $index) {
4565
4766
  <div
4566
- class="flex flex-col shrink-0 w-[330px] overflow-hidden"
4567
- [style.borderRadius]="'var(--pt-card-radius, 14px)'"
4767
+ class="flex flex-col shrink-0 w-[330px]"
4768
+ [style.borderRadius]="plan.is_current_plan ? 'var(--pt-current-sub-card-radius, var(--pt-card-radius, 1rem))' : 'var(--pt-card-radius, 1rem)'"
4568
4769
  [style.borderWidth]="'var(--pt-card-border-width, 1px)'"
4569
4770
  [style.borderStyle]="'solid'"
4570
- [style.borderColor]="'var(--pt-card-border)'"
4771
+ [style.borderColor]="'var(--pt-card-border, #e5e7eb)'"
4571
4772
  [style.background-color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-bg)' : 'var(--pt-card-header-bg)'">
4572
4773
  <!-- Card Header -->
4573
- <div class="flex items-center justify-between pl-4 pr-[5px] pt-[6px] pb-[2px] rounded-t-[14px]"
4574
- [style.background-color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-bg)' : 'var(--pt-card-header-bg)'">
4774
+ <div class="flex items-center justify-between pl-4 pr-[5px] pt-[6px] pb-[2px]">
4575
4775
  <span
4576
4776
  class="text-sm font-medium"
4577
4777
  [style.color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-text)' : 'var(--pt-card-header-text)'">
@@ -4588,12 +4788,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
4588
4788
 
4589
4789
  <!-- Card Body -->
4590
4790
  <div
4591
- class="flex-grow rounded-[14px] w-full p-2 pb-10"
4592
- [style.background-color]="plan.is_current_plan ? undefined : 'var(--pt-card-bg, #ffffff)'"
4593
- [style.border]="'1px solid var(--pt-card-border, var(--cp-section-content-border))'"
4594
- [style.backgroundImage]="plan.is_current_plan ? 'linear-gradient(180deg, var(--pt-current-sub-card-gradient-color, #E4E4E7) 4.81%, rgba(222, 247, 100, 0) 42.31%)' : undefined"
4595
- [class.rounded-t-none]="!plan.is_current_plan"
4596
- [class.border-t-0]="!plan.is_current_plan">
4791
+ class="flex-grow w-full p-2 pb-10"
4792
+ [style.borderRadius]="'calc(' + (plan.is_current_plan ? 'var(--pt-current-sub-card-radius, var(--pt-card-radius, 1rem))' : 'var(--pt-card-radius, 1rem)') + ' - 2px)'"
4793
+ [style.border]="'1px solid ' + (plan.is_current_plan ? 'var(--pt-current-sub-card-header-bg)' : 'var(--pt-card-header-bg)')"
4794
+ [style.background-color]="'var(--pt-card-bg, #ffffff)'"
4795
+ [style.backgroundImage]="plan.is_current_plan ? 'var(--pt-card-gradient)' : undefined">
4597
4796
 
4598
4797
  <!-- Description -->
4599
4798
  @if (shouldShowPlanDescription()) {
@@ -4813,7 +5012,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
4813
5012
  </div>
4814
5013
  </div>
4815
5014
  }
4816
- `,
5015
+ `
4817
5016
  }]
4818
5017
  }], propDecorators: { plans: [{
4819
5018
  type: Input
@@ -4843,7 +5042,7 @@ class InvoicePreviewComponent {
4843
5042
  return date.toLocaleDateString(undefined, {
4844
5043
  month: 'short',
4845
5044
  day: 'numeric',
4846
- year: 'numeric',
5045
+ year: 'numeric'
4847
5046
  });
4848
5047
  }
4849
5048
  formatInvoicePrice(amount) {
@@ -4864,12 +5063,12 @@ class InvoicePreviewComponent {
4864
5063
  if (!invoice)
4865
5064
  return '$';
4866
5065
  const c = invoice.currency;
4867
- return c?.symbol ?? c?.Symbol ?? '$';
5066
+ return (c?.symbol ?? '$');
4868
5067
  }
4869
5068
  getInvoiceSummaryNumber(invoice, ...keys) {
4870
5069
  if (!invoice)
4871
5070
  return 0;
4872
- const s = invoice.summary ?? {};
5071
+ const s = (invoice.summary ?? {});
4873
5072
  for (const k of keys) {
4874
5073
  const v = s[k];
4875
5074
  if (v !== undefined && v !== null && v !== '') {
@@ -4882,51 +5081,45 @@ class InvoicePreviewComponent {
4882
5081
  getInvoiceLineItems(invoice) {
4883
5082
  if (!invoice)
4884
5083
  return [];
4885
- const lineItems = invoice.line_items ?? invoice.lineItems ?? invoice.items ?? invoice.invoice_lines ?? [];
4886
- const chargeItems = invoice.charge_items ?? invoice.chargeItems ?? [];
4887
- const usageItems = invoice.usage_items ?? invoice.usageItems ?? [];
4888
- const creditItems = invoice.credit_items ?? invoice.creditItems ?? [];
5084
+ const lineItems = invoice.line_items ?? [];
5085
+ const chargeItems = invoice.charge_items ?? [];
5086
+ const usageItems = invoice.usage_items ?? [];
5087
+ const creditItems = invoice.credit_items ?? [];
4889
5088
  const normalize = (item, itemType) => this.normalizeInvoiceLineItem(item, itemType);
4890
5089
  return [
4891
- ...(Array.isArray(lineItems)
4892
- ? lineItems.map((i) => normalize(i, 'line_item'))
4893
- : []),
4894
- ...(Array.isArray(chargeItems)
4895
- ? chargeItems.map((i) => normalize(i, 'charge_item'))
4896
- : []),
4897
- ...(Array.isArray(usageItems)
4898
- ? usageItems.map((i) => normalize(i, 'usage_item'))
4899
- : []),
4900
- ...(Array.isArray(creditItems)
4901
- ? creditItems.map((i) => normalize(i, 'credit_item'))
4902
- : []),
5090
+ ...lineItems.map((i) => normalize(i, 'line_item')),
5091
+ ...chargeItems.map((i) => normalize(i, 'charge_item')),
5092
+ ...usageItems.map((i) => normalize(i, 'usage_item')),
5093
+ ...creditItems.map((i) => normalize(i, 'credit_item'))
4903
5094
  ];
4904
5095
  }
4905
5096
  getInvoiceLineItemRangeLabel(raw) {
4906
- const tiers = raw?.usage_tiers?.tiers ?? raw?.tiers ?? [];
4907
- const tier = Array.isArray(tiers) && tiers.length > 0 ? tiers[0] : null;
5097
+ const usageTiers = raw['usage_tiers'];
5098
+ const tiers = usageTiers?.['tiers'] ?? raw['tiers'] ?? [];
5099
+ const tier = (Array.isArray(tiers) && tiers.length > 0 ? tiers[0] : null);
4908
5100
  if (!tier)
4909
5101
  return '';
4910
- const first = tier.first_unit ?? tier.firstUnit ?? 0;
4911
- const last = tier.last_unit ?? tier.lastUnit ?? -1;
4912
- if (last === -1 || last == null)
5102
+ const first = tier['first_unit'] ?? tier['firstUnit'] ?? 0;
5103
+ const last = tier['last_unit'] ?? tier['lastUnit'] ?? -1;
5104
+ if (last === -1 || last === null || last === undefined)
4913
5105
  return `${first} and above`;
4914
5106
  return `${first} to ${last}`;
4915
5107
  }
4916
5108
  normalizeInvoiceLineItem(item, itemType) {
4917
5109
  const raw = item || {};
4918
- const id = raw.id ?? raw.Id ?? '';
4919
- const name = raw.name ?? raw.Name ?? '';
4920
- const description = (raw.description ?? raw.Description ?? '') || this.getInvoiceLineItemRangeLabel(raw);
4921
- const quantity = Number(raw.quantity ?? raw.Quantity ?? 0);
4922
- const totalAmountNum = this.toNumber(raw.total_amount ?? raw.totalAmount ?? raw.amount ?? raw.Amount ?? 0);
4923
- const amountStr = String(raw.amount ?? raw.Amount ?? raw.total_amount ?? raw.totalAmount ?? '0');
4924
- const totalAmountStr = String(raw.total_amount ?? raw.totalAmount ?? raw.amount ?? raw.Amount ?? '0');
4925
- const tiers = raw?.usage_tiers?.tiers ?? raw?.tiers ?? [];
4926
- const firstTier = Array.isArray(tiers) && tiers.length > 0 ? tiers[0] : null;
4927
- const tierUnitPrice = firstTier != null ? (firstTier.unit_price ?? firstTier.unitPrice) : undefined;
5110
+ const id = raw['id'] ?? raw['Id'] ?? '';
5111
+ const name = raw['name'] ?? raw['Name'] ?? '';
5112
+ const description = (raw['description'] ?? raw['Description'] ?? '') || this.getInvoiceLineItemRangeLabel(raw);
5113
+ const quantity = Number(raw['quantity'] ?? raw['Quantity'] ?? 0);
5114
+ const totalAmountNum = this.toNumber((raw['total_amount'] ?? raw['totalAmount'] ?? raw['amount'] ?? raw['Amount'] ?? 0));
5115
+ const amountStr = String(raw['amount'] ?? raw['Amount'] ?? raw['total_amount'] ?? raw['totalAmount'] ?? '0');
5116
+ const totalAmountStr = String(raw['total_amount'] ?? raw['totalAmount'] ?? raw['amount'] ?? raw['Amount'] ?? '0');
5117
+ const usageTiers = raw['usage_tiers'];
5118
+ const tiers = usageTiers?.['tiers'] ?? raw['tiers'] ?? [];
5119
+ const firstTier = (Array.isArray(tiers) && tiers.length > 0 ? tiers[0] : null);
5120
+ const tierUnitPrice = firstTier !== null && firstTier !== undefined ? (firstTier['unit_price'] ?? firstTier['unitPrice']) : undefined;
4928
5121
  const derivedUnitPrice = quantity > 0 && totalAmountNum > 0 ? totalAmountNum / quantity : undefined;
4929
- const rawUnitPrice = raw.unit_price ?? raw.unitPrice ?? tierUnitPrice;
5122
+ const rawUnitPrice = raw['unit_price'] ?? raw['unitPrice'] ?? tierUnitPrice;
4930
5123
  const rawUnitNum = rawUnitPrice !== undefined &&
4931
5124
  rawUnitPrice !== null &&
4932
5125
  String(rawUnitPrice).trim() !== ''
@@ -4941,7 +5134,7 @@ class InvoicePreviewComponent {
4941
5134
  unit_price: String(unitPriceNum),
4942
5135
  amount: amountStr,
4943
5136
  total_amount: totalAmountStr,
4944
- itemType,
5137
+ itemType
4945
5138
  };
4946
5139
  }
4947
5140
  buildTenantAddress(addr) {
@@ -4953,41 +5146,29 @@ class InvoicePreviewComponent {
4953
5146
  addr.city,
4954
5147
  addr.state,
4955
5148
  addr.postal_code,
4956
- addr.country,
5149
+ addr.country
4957
5150
  ].filter(Boolean);
4958
5151
  return parts.length ? parts.join(', ') : 'No Tenant address provided';
4959
5152
  }
4960
5153
  buildBilledToAddress(customer) {
4961
5154
  if (!customer)
4962
5155
  return '-';
4963
- const billing = customer?.billing_configuration?.billing_address;
5156
+ const billing = customer.billing_address;
4964
5157
  if (billing) {
4965
5158
  const parts = [
4966
- billing.line_1,
4967
- billing.line_2,
5159
+ billing.address_line_one,
5160
+ billing.address_line_two,
4968
5161
  billing.city,
4969
5162
  billing.state,
4970
- billing.postal_code,
4971
- billing.country,
4972
- ].filter(Boolean);
4973
- return parts.length ? parts.join(', ') : '-';
4974
- }
4975
- const addr = customer?.address;
4976
- if (addr) {
4977
- const parts = [
4978
- addr.line_1,
4979
- addr.line_2,
4980
- addr.city,
4981
- addr.state,
4982
- addr.postal_code,
4983
- addr.country,
5163
+ billing.zip_code,
5164
+ billing.country
4984
5165
  ].filter(Boolean);
4985
5166
  return parts.length ? parts.join(', ') : '-';
4986
5167
  }
4987
5168
  return '-';
4988
5169
  }
4989
5170
  escapeHtml(s) {
4990
- if (s == null || s === undefined)
5171
+ if (s === null || s === undefined)
4991
5172
  return '';
4992
5173
  return String(s)
4993
5174
  .replace(/&/g, '&amp;')
@@ -5030,14 +5211,14 @@ class InvoicePreviewComponent {
5030
5211
  const paid = fmt(this.getInvoiceSummaryNumber(inv, 'total_amount_paid', 'totalAmountPaid'));
5031
5212
  const due = fmt(this.getInvoiceSummaryNumber(inv, 'total_outstanding_amount', 'totalOutstandingAmount'));
5032
5213
  const rows = items
5033
- .map((item) => `<div style="border-top:1px solid #e5e7eb;display:grid;grid-template-columns:minmax(8rem,1fr) auto auto auto auto;gap:1rem;align-items:start;padding:1rem 0.75rem;font-size:13px;color:#374151;"><div><span style="font-weight:500;color:#2563eb;">${this.escapeHtml(item.name)}</span>${item.description ? `<p style="font-size:12px;color:#6b7280;margin:2px 0 0 0;">${this.escapeHtml(item.description)}</p>` : ''}</div><div>${sym}${fmt(this.toNumber(item.unit_price))}</div><div>${item.quantity}</div><div>${sym}${fmt(this.toNumber(item.total_amount || item.amount))}</div><div>${sym}${fmt(this.toNumber(item.total_amount || item.amount))}</div></div>`)
5214
+ .map((item) => `<div style="border-top:1px solid #e5e7eb;display:grid;grid-template-columns:minmax(8rem,1fr) auto auto auto auto;gap:1rem;align-items:start;padding:1rem 0.75rem;font-size:13px;color:#374151;"><div><span style="font-weight:500;color:#2563eb;">${this.escapeHtml(String(item['name']))}</span>${item['description'] ? `<p style="font-size:12px;color:#6b7280;margin:2px 0 0 0;">${this.escapeHtml(String(item['description']))}</p>` : ''}</div><div>${sym}${fmt(this.toNumber(item['unit_price']))}</div><div>${item['quantity']}</div><div>${sym}${fmt(this.toNumber((item['total_amount'] || item['amount'])))}</div><div>${sym}${fmt(this.toNumber((item['total_amount'] || item['amount'])))}</div></div>`)
5034
5215
  .join('');
5035
- return `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Invoice</title><style>*{box-sizing:border-box;}body{margin:0;padding:0;font-family:ui-sans-serif,system-ui,sans-serif;font-size:16px;color:#111827;line-height:1.5;background:#fff;}</style></head><body><div style="max-width:48rem;margin:0 auto;padding:2rem;"><div style="background:#fff;padding:2rem;border-radius:0.75rem;border-top:4px solid #111827;box-shadow:0 1px 3px 0 rgb(0 0 0/0.1);"><div style="display:flex;justify-content:space-between;align-items:flex-start;"><div style="display:flex;align-items:center;gap:0.75rem;"><strong style="font-size:1.25rem;font-weight:700;color:#111827;">${this.escapeHtml(inv.tenant?.business_name || 'Metrifox Sandbox')}</strong></div><div style="text-align:right;"><div style="font-size:1.25rem;font-weight:700;color:#111827;text-transform:uppercase;">INVOICE</div><div style="font-size:13px;color:#111827;margin-top:2px;">${this.escapeHtml(inv.invoice_number || '-')}</div></div></div><div style="display:grid;grid-template-columns:minmax(8rem,1fr) auto auto auto auto;gap:1rem;background:#e5e7eb;padding:0.5rem 0.75rem;border-radius:0.375rem;font-size:13px;font-weight:500;color:#374151;margin-top:2rem;"><span>Item name</span><span>Price</span><span>Qty</span><span>Subtotal</span><span>Amount</span></div>${rows}<div style="background:#f5f5f5;padding:0.75rem;width:50%;margin-left:auto;margin-top:1.25rem;border-radius:0.25rem;"><div style="display:flex;justify-content:space-between;border-bottom:1px solid #e5e7eb;padding-bottom:0.5rem;"><div><div style="font-size:13px;font-weight:500;color:#111827;">Subtotal</div><div style="font-size:10px;color:#737373;margin:0.5rem 0;">Discount</div><div style="font-size:10px;color:#737373;">Tax</div><div style="font-size:13px;font-weight:500;color:#111827;margin-top:8px;">Grand total</div></div><div style="text-align:right;"><div style="font-size:13px;font-weight:500;color:#1f2937;">${sym}${sub}</div><div style="font-size:10px;color:#737373;margin:0.5rem 0;">${sym}${disc}</div><div style="font-size:10px;color:#737373;">${sym}${tax}</div><div style="font-size:13px;font-weight:500;color:#1f2937;margin-top:8px;">${sym}${grand}</div></div></div><div style="display:flex;justify-content:space-between;padding-top:0.5rem;"><div><div style="font-size:13px;font-weight:500;color:#111827;">Amount paid</div><div style="font-size:13px;font-weight:500;color:#111827;">Amount due</div></div><div style="text-align:right;"><div style="font-size:13px;font-weight:500;color:#1f2937;">${sym}${paid}</div><div style="font-size:16px;font-weight:500;">${sym}${due}</div></div></div></div><div style="border-top:1px solid #d1d5db;padding-top:1rem;margin-top:3rem;text-align:center;font-size:10px;color:#111827;">Powered by MetriFox</div></div></div></body></html>`;
5216
+ return `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Invoice</title><style>*{box-sizing:border-box;}body{margin:0;padding:0;font-family:ui-sans-serif,system-ui,sans-serif;font-size:16px;color:#111827;line-height:1.5;background:#fff;}</style></head><body><div style="max-width:48rem;margin:0 auto;padding:2rem;"><div style="background:#fff;padding:2rem;border-radius:0.75rem;border-top:4px solid #111827;box-shadow:0 1px 3px 0 rgb(0 0 0/0.1);"><div style="display:flex;justify-content:space-between;align-items:flex-start;"><div style="display:flex;align-items:center;gap:0.75rem;"><strong style="font-size:1.25rem;font-weight:700;color:#111827;">${this.escapeHtml(String(inv.tenant?.business_name || 'Metrifox Sandbox'))}</strong></div><div style="text-align:right;"><div style="font-size:1.25rem;font-weight:700;color:#111827;text-transform:uppercase;">INVOICE</div><div style="font-size:13px;color:#111827;margin-top:2px;">${this.escapeHtml(String(inv.invoice_number || '-'))}</div></div></div><div style="display:grid;grid-template-columns:minmax(8rem,1fr) auto auto auto auto;gap:1rem;background:#e5e7eb;padding:0.5rem 0.75rem;border-radius:0.375rem;font-size:13px;font-weight:500;color:#374151;margin-top:2rem;"><span>Item name</span><span>Price</span><span>Qty</span><span>Subtotal</span><span>Amount</span></div>${rows}<div style="background:#f5f5f5;padding:0.75rem;width:50%;margin-left:auto;margin-top:1.25rem;border-radius:0.25rem;"><div style="display:flex;justify-content:space-between;border-bottom:1px solid #e5e7eb;padding-bottom:0.5rem;"><div><div style="font-size:13px;font-weight:500;color:#111827;">Subtotal</div><div style="font-size:10px;color:#737373;margin:0.5rem 0;">Discount</div><div style="font-size:10px;color:#737373;">Tax</div><div style="font-size:13px;font-weight:500;color:#111827;margin-top:8px;">Grand total</div></div><div style="text-align:right;"><div style="font-size:13px;font-weight:500;color:#1f2937;">${sym}${sub}</div><div style="font-size:10px;color:#737373;margin:0.5rem 0;">${sym}${disc}</div><div style="font-size:10px;color:#737373;">${sym}${tax}</div><div style="font-size:13px;font-weight:500;color:#1f2937;margin-top:8px;">${sym}${grand}</div></div></div><div style="display:flex;justify-content:space-between;padding-top:0.5rem;"><div><div style="font-size:13px;font-weight:500;color:#111827;">Amount paid</div><div style="font-size:13px;font-weight:500;color:#111827;">Amount due</div></div><div style="text-align:right;"><div style="font-size:13px;font-weight:500;color:#1f2937;">${sym}${paid}</div><div style="font-size:16px;font-weight:500;">${sym}${due}</div></div></div></div><div style="border-top:1px solid #d1d5db;padding-top:1rem;margin-top:3rem;text-align:center;font-size:10px;color:#111827;">Powered by MetriFox</div></div></div></body></html>`;
5036
5217
  }
5037
5218
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: InvoicePreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5038
5219
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: InvoicePreviewComponent, isStandalone: true, selector: "cp-invoice-preview", inputs: { show: "show", selectedInvoice: "selectedInvoice", invoiceDetails: "invoiceDetails", invoiceDetailsLoading: "invoiceDetailsLoading" }, outputs: { close: "close" }, ngImport: i0, template: `
5039
5220
  @if (show && selectedInvoice) {
5040
- <div class="invoice-preview-modal fixed inset-0 z-50 overflow-hidden">
5221
+ <div class="invoice-preview-modal fixed inset-0 z-[100] overflow-hidden">
5041
5222
  <!-- Backdrop -->
5042
5223
  <div
5043
5224
  class="invoice-preview-backdrop absolute inset-0 bg-black/50 transition-opacity"
@@ -5374,7 +5555,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
5374
5555
  type: Component,
5375
5556
  args: [{ selector: 'cp-invoice-preview', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
5376
5557
  @if (show && selectedInvoice) {
5377
- <div class="invoice-preview-modal fixed inset-0 z-50 overflow-hidden">
5558
+ <div class="invoice-preview-modal fixed inset-0 z-[100] overflow-hidden">
5378
5559
  <!-- Backdrop -->
5379
5560
  <div
5380
5561
  class="invoice-preview-backdrop absolute inset-0 bg-black/50 transition-opacity"
@@ -5794,7 +5975,7 @@ class CustomerPortalComponent {
5794
5975
  const allPriceOptions = [
5795
5976
  ...(plan.price_options || []),
5796
5977
  ...(plan.entitlement_price_options || []),
5797
- ...(plan.credit_attachment_price_options || []),
5978
+ ...(plan.credit_attachment_price_options || [])
5798
5979
  ];
5799
5980
  allPriceOptions.forEach((po) => {
5800
5981
  if (po.price?.billing_interval) {
@@ -5808,11 +5989,25 @@ class CustomerPortalComponent {
5808
5989
  cssVars = computed(() => {
5809
5990
  const custom = this.themeSignal() ?? MetrifoxService.getTheme()?.customerPortal;
5810
5991
  const theme = mergeCustomerPortalTheme(defaultCustomerPortalTheme, custom);
5811
- return MetrifoxService.customerPortalThemeToCssVars(theme);
5992
+ const vars = MetrifoxService.customerPortalThemeToCssVars(theme);
5993
+ const gradientVars = MetrifoxService.getBackgroundImage(theme);
5994
+ return {
5995
+ ...vars,
5996
+ ...gradientVars,
5997
+ 'font-family': 'var(--cp-font-family)',
5998
+ 'background-color': 'var(--cp-bg)',
5999
+ 'border-radius': 'var(--cp-radius)'
6000
+ };
5812
6001
  });
5813
6002
  ngOnInit() {
5814
6003
  this.loadCustomerDetails();
5815
6004
  }
6005
+ ngOnChanges(changes) {
6006
+ if (changes['customerKey'] && !changes['customerKey'].firstChange) {
6007
+ this.lastLoadedCustomerKey = null;
6008
+ this.loadCustomerDetails();
6009
+ }
6010
+ }
5816
6011
  ngOnDestroy() {
5817
6012
  this.destroy$.next();
5818
6013
  this.destroy$.complete();
@@ -5844,9 +6039,9 @@ class CustomerPortalComponent {
5844
6039
  this.error.set(err.message || 'Failed to load customer data');
5845
6040
  this.errorOccurred.emit({
5846
6041
  message: err.message || 'Failed to load customer data',
5847
- code: err.status?.toString(),
6042
+ code: err.status?.toString()
5848
6043
  });
5849
- },
6044
+ }
5850
6045
  });
5851
6046
  }
5852
6047
  loadAdditionalData() {
@@ -5857,7 +6052,7 @@ class CustomerPortalComponent {
5857
6052
  const subscriptionId = firstSubscription?.subscription?.id;
5858
6053
  const productKey = firstSubscription?.product_key;
5859
6054
  const requests = {
5860
- wallets: this.metrifoxService.getCustomerWallets(this.customerKey),
6055
+ wallets: this.metrifoxService.getCustomerWallets(this.customerKey)
5861
6056
  };
5862
6057
  if (subscriptionId) {
5863
6058
  requests.history = this.metrifoxService.getBillingHistory(subscriptionId);
@@ -5901,7 +6096,7 @@ class CustomerPortalComponent {
5901
6096
  this.isLoadingData = false;
5902
6097
  this.loading.set(false);
5903
6098
  this.dataLoaded.emit({ customerDetails: details });
5904
- },
6099
+ }
5905
6100
  });
5906
6101
  }
5907
6102
  loadDataForSubscription(sub) {
@@ -5952,7 +6147,7 @@ class CustomerPortalComponent {
5952
6147
  this.entitlementSummary.set([]);
5953
6148
  this.entitlementUsage.set([]);
5954
6149
  this.productPlans.set(null);
5955
- },
6150
+ }
5956
6151
  });
5957
6152
  }
5958
6153
  loadCreditAllocations(walletId, tab) {
@@ -5968,7 +6163,7 @@ class CustomerPortalComponent {
5968
6163
  error: () => {
5969
6164
  this.creditAllocations.set([]);
5970
6165
  this.allocationsLoading.set(false);
5971
- },
6166
+ }
5972
6167
  });
5973
6168
  }
5974
6169
  selectTab(index) {
@@ -6003,11 +6198,11 @@ class CustomerPortalComponent {
6003
6198
  if (invoiceId) {
6004
6199
  this.metrifoxService.getInvoiceDetails(invoiceId).pipe(takeUntil(this.destroy$)).subscribe({
6005
6200
  next: (data) => {
6006
- const inv = data?.data ?? data;
6201
+ const inv = (data?.data ?? data);
6007
6202
  this.invoiceDetails.set(inv);
6008
6203
  this.invoiceDetailsLoading.set(false);
6009
6204
  },
6010
- error: () => this.invoiceDetailsLoading.set(false),
6205
+ error: () => this.invoiceDetailsLoading.set(false)
6011
6206
  });
6012
6207
  }
6013
6208
  else {
@@ -6029,11 +6224,11 @@ class CustomerPortalComponent {
6029
6224
  }
6030
6225
  }
6031
6226
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: CustomerPortalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6032
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: CustomerPortalComponent, isStandalone: true, selector: "metrifox-customer-portal", inputs: { customerKey: "customerKey", sectionsConfig: "sectionsConfig", theme: "theme" }, outputs: { dataLoaded: "dataLoaded", errorOccurred: "errorOccurred" }, ngImport: i0, template: `
6227
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: CustomerPortalComponent, isStandalone: true, selector: "metrifox-customer-portal", inputs: { customerKey: "customerKey", sectionsConfig: "sectionsConfig", theme: "theme" }, outputs: { dataLoaded: "dataLoaded", errorOccurred: "errorOccurred" }, usesOnChanges: true, ngImport: i0, template: `
6033
6228
  <div class="font-sans antialiased" [ngStyle]="cssVars()">
6034
6229
  <!-- Error State -->
6035
6230
  @if (error()) {
6036
- <div class="max-w-[60rem] mx-auto py-6 px-4">
6231
+ <div class="max-w-[60rem] mx-auto" [style.padding]="'var(--cp-container-padding, 40px 24px)'">
6037
6232
  <div class="bg-red-50 p-4 rounded-lg text-red-700">
6038
6233
  Error loading customer details: {{ error() }}
6039
6234
  </div>
@@ -6042,7 +6237,7 @@ class CustomerPortalComponent {
6042
6237
 
6043
6238
  <!-- Loading State -->
6044
6239
  @if (loading() && !error()) {
6045
- <div class="max-w-[60rem] mx-auto py-6 px-4">
6240
+ <div class="max-w-[60rem] mx-auto" [style.padding]="'var(--cp-container-padding, 40px 24px)'">
6046
6241
  <div class="animate-pulse space-y-4">
6047
6242
  <div class="h-12 bg-gray-200 rounded-lg"></div>
6048
6243
  <div class="h-16 bg-gray-200 rounded-lg"></div>
@@ -6055,7 +6250,7 @@ class CustomerPortalComponent {
6055
6250
 
6056
6251
  <!-- Content -->
6057
6252
  @if (!loading() && !error() && customerDetails()) {
6058
- <div class="max-w-[60rem] mx-auto py-6 px-4 space-y-4">
6253
+ <div class="w-full max-w-[60rem] mx-auto min-w-0 flex flex-col gap-6" [style.padding]="'var(--cp-container-padding, 40px 24px)'">
6059
6254
  <!-- Empty Subscription State -->
6060
6255
  @if (subscriptions().length === 0) {
6061
6256
  <div class="w-full"
@@ -6132,7 +6327,7 @@ class CustomerPortalComponent {
6132
6327
 
6133
6328
  <!-- Subscription Content Template -->
6134
6329
  <ng-template #subscriptionContent let-subscription>
6135
- <div class="space-y-4">
6330
+ <div class="flex flex-col gap-6">
6136
6331
  <cp-subscription-section
6137
6332
  [subscription]="subscription"
6138
6333
  [sectionsConfig]="sectionsConfig"
@@ -6192,12 +6387,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
6192
6387
  PaymentSectionComponent,
6193
6388
  BillingHistorySectionComponent,
6194
6389
  PlansSectionComponent,
6195
- InvoicePreviewComponent,
6390
+ InvoicePreviewComponent
6196
6391
  ], changeDetection: ChangeDetectionStrategy.OnPush, template: `
6197
6392
  <div class="font-sans antialiased" [ngStyle]="cssVars()">
6198
6393
  <!-- Error State -->
6199
6394
  @if (error()) {
6200
- <div class="max-w-[60rem] mx-auto py-6 px-4">
6395
+ <div class="max-w-[60rem] mx-auto" [style.padding]="'var(--cp-container-padding, 40px 24px)'">
6201
6396
  <div class="bg-red-50 p-4 rounded-lg text-red-700">
6202
6397
  Error loading customer details: {{ error() }}
6203
6398
  </div>
@@ -6206,7 +6401,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
6206
6401
 
6207
6402
  <!-- Loading State -->
6208
6403
  @if (loading() && !error()) {
6209
- <div class="max-w-[60rem] mx-auto py-6 px-4">
6404
+ <div class="max-w-[60rem] mx-auto" [style.padding]="'var(--cp-container-padding, 40px 24px)'">
6210
6405
  <div class="animate-pulse space-y-4">
6211
6406
  <div class="h-12 bg-gray-200 rounded-lg"></div>
6212
6407
  <div class="h-16 bg-gray-200 rounded-lg"></div>
@@ -6219,7 +6414,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
6219
6414
 
6220
6415
  <!-- Content -->
6221
6416
  @if (!loading() && !error() && customerDetails()) {
6222
- <div class="max-w-[60rem] mx-auto py-6 px-4 space-y-4">
6417
+ <div class="w-full max-w-[60rem] mx-auto min-w-0 flex flex-col gap-6" [style.padding]="'var(--cp-container-padding, 40px 24px)'">
6223
6418
  <!-- Empty Subscription State -->
6224
6419
  @if (subscriptions().length === 0) {
6225
6420
  <div class="w-full"
@@ -6296,7 +6491,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
6296
6491
 
6297
6492
  <!-- Subscription Content Template -->
6298
6493
  <ng-template #subscriptionContent let-subscription>
6299
- <div class="space-y-4">
6494
+ <div class="flex flex-col gap-6">
6300
6495
  <cp-subscription-section
6301
6496
  [subscription]="subscription"
6302
6497
  [sectionsConfig]="sectionsConfig"
@@ -6455,6 +6650,7 @@ var ResetIntervals;
6455
6650
  ResetIntervals["DAILY"] = "daily";
6456
6651
  ResetIntervals["BILLING_PERIOD"] = "billing_period";
6457
6652
  ResetIntervals["NEVER"] = "never";
6653
+ ResetIntervals["NONE"] = "none";
6458
6654
  })(ResetIntervals || (ResetIntervals = {}));
6459
6655
  /**
6460
6656
  * Enforcement types
@@ -6482,6 +6678,7 @@ var BillingTimingTypes;
6482
6678
  (function (BillingTimingTypes) {
6483
6679
  BillingTimingTypes["IN_ADVANCE"] = "in_advance";
6484
6680
  BillingTimingTypes["IN_ARREARS"] = "in_arrears";
6681
+ BillingTimingTypes["PAY_AS_YOU_GO"] = "pay_as_you_go";
6485
6682
  })(BillingTimingTypes || (BillingTimingTypes = {}));
6486
6683
  /**
6487
6684
  * Aggregation methods
@@ -6532,56 +6729,75 @@ var LocalizationSelection;
6532
6729
  LocalizationSelection["SMART_PRE_FILL"] = "smart_pre_fill";
6533
6730
  })(LocalizationSelection || (LocalizationSelection = {}));
6534
6731
 
6535
- // Default theme matching React SDK
6536
6732
  const defaultPricingTableTheme = {
6537
6733
  plans: {
6538
6734
  currentPlanCard: {
6539
- header: { background: '#E4E4E7', textColor: '#111827' },
6540
- gradientColor: '#E4E4E7',
6735
+ header: {
6736
+ background: '#e5e7eb',
6737
+ textColor: '#111827'
6738
+ },
6739
+ gradientColor: '#e5e7eb'
6541
6740
  },
6542
6741
  planCards: {
6543
6742
  background: '#ffffff',
6544
- border: { color: '#E4E4E7', width: '1px', radius: '8px' },
6545
- header: { background: '#E4E4E7', textColor: '#111827' },
6546
- description: { textColor: '#71717A', textButtonColor: '#2563eb' },
6743
+ border: {
6744
+ color: '#e5e7eb',
6745
+ width: '1px',
6746
+ radius: '8px'
6747
+ },
6748
+ header: {
6749
+ background: '#e5e7eb',
6750
+ textColor: '#111827'
6751
+ },
6752
+ description: {
6753
+ textColor: '#6b7280',
6754
+ textButtonColor: '#2563eb'
6755
+ },
6547
6756
  price: {
6548
6757
  amountColor: '#111827',
6549
- primaryTextColor: '#71717A',
6550
- secondaryTextColor: '#A1A1AA',
6758
+ primaryTextColor: '#6b7280',
6759
+ secondaryTextColor: '#9ca3af',
6551
6760
  background: 'transparent',
6552
- borderColor: 'transparent',
6553
- },
6761
+ borderColor: 'transparent'
6762
+ }
6763
+ },
6764
+ planFeatures: {
6765
+ textColor: '#374151',
6766
+ iconColor: '#0BB02F'
6554
6767
  },
6555
- planFeatures: { textColor: '#3F3F46', iconColor: '#0BB02F' },
6556
6768
  planButton: {
6557
6769
  background: '#3D3D3D',
6558
6770
  textColor: '#ffffff',
6559
6771
  secondaryBackground: '#E4E4E7',
6560
6772
  secondaryTextColor: '#3F3F46',
6561
- textButtonColor: '#2563eb',
6773
+ textButtonColor: '#2563eb'
6562
6774
  },
6563
6775
  planToggle: {
6564
- background: '#E4E4E7',
6776
+ background: '#e5e7eb',
6565
6777
  activeBackground: '#1f2937',
6566
6778
  activeText: '#ffffff',
6567
- inactiveText: '#71717A',
6779
+ inactiveText: '#6b7280'
6568
6780
  },
6569
- planTags: { freeTrialBackground: '#dbeafe', freeTrialText: '#1e40af' },
6781
+ planTags: {
6782
+ freeTrialBackground: '#dbeafe',
6783
+ freeTrialText: '#1e40af'
6784
+ }
6570
6785
  },
6571
6786
  tabs: {
6572
- inactiveText: '#A1A1AA',
6787
+ inactiveText: '#9ca3af',
6573
6788
  activeText: '#2563eb',
6574
6789
  indicator: '#2563eb',
6575
- borderColor: '#A1A1AA',
6790
+ borderColor: '#9ca3af'
6576
6791
  },
6577
6792
  checkoutBar: {
6578
- background: '#FAFAFA',
6579
- borderColor: '#E4E4E7',
6793
+ background: '#f9fafb',
6794
+ borderColor: '#e5e7eb',
6580
6795
  textColor: '#3F3F46',
6581
6796
  buttonBackground: '#2563eb',
6582
- buttonTextColor: '#ffffff',
6583
- },
6797
+ buttonTextColor: '#ffffff'
6798
+ }
6584
6799
  };
6800
+
6585
6801
  function mergePricingTableTheme(defaultTheme, custom) {
6586
6802
  if (!custom || typeof custom !== 'object')
6587
6803
  return defaultTheme;
@@ -6605,12 +6821,12 @@ function mergePricingTableTheme(defaultTheme, custom) {
6605
6821
  }
6606
6822
  // SVG Icons
6607
6823
  const ICONS = {
6608
- check: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`,
6609
- search: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.3-4.3"></path></svg>`,
6610
- close: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="m15 9-6 6"></path><path d="m9 9 6 6"></path></svg>`,
6611
- trash: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"></path><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path></svg>`,
6612
- minus: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"></path></svg>`,
6613
- plus: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"></path><path d="M12 5v14"></path></svg>`,
6824
+ check: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>',
6825
+ search: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.3-4.3"></path></svg>',
6826
+ close: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="m15 9-6 6"></path><path d="m9 9 6 6"></path></svg>',
6827
+ trash: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"></path><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path></svg>',
6828
+ minus: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"></path></svg>',
6829
+ plus: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"></path><path d="M12 5v14"></path></svg>'
6614
6830
  };
6615
6831
  /**
6616
6832
  * Pricing Table Component
@@ -6635,15 +6851,24 @@ class PricingTableComponent {
6635
6851
  checkoutUsername;
6636
6852
  metrifoxService = inject(MetrifoxService);
6637
6853
  sanitizer = inject(DomSanitizer);
6854
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
6638
6855
  constructor() { }
6639
6856
  /** Product key to load pricing for */
6640
6857
  productKey;
6641
6858
  /** Show only plans (hide single purchases) */
6642
- plansOnly = false;
6859
+ plansOnlySignal = signal(false);
6860
+ set plansOnly(value) { this.plansOnlySignal.set(value); }
6643
6861
  /** Show only single purchases (hide plans) */
6644
- singlePurchasesOnly = false;
6862
+ singlePurchasesOnlySignal = signal(false);
6863
+ set singlePurchasesOnly(value) { this.singlePurchasesOnlySignal.set(value); }
6645
6864
  /** Show tab header when both plans and purchases exist */
6646
- showTabHeader = true;
6865
+ showTabHeaderSignal = signal(true);
6866
+ set showTabHeader(value) { this.showTabHeaderSignal.set(value); }
6867
+ /** Optional theme override for this instance */
6868
+ themeSignal = signal(undefined);
6869
+ set theme(value) {
6870
+ this.themeSignal.set(value);
6871
+ }
6647
6872
  /** Emitted when a plan is selected */
6648
6873
  planSelected = new EventEmitter();
6649
6874
  /** Emitted when a single purchase is selected */
@@ -6661,8 +6886,8 @@ class PricingTableComponent {
6661
6886
  // Computed
6662
6887
  plans = computed(() => this.product()?.plans || []);
6663
6888
  singlePurchases = computed(() => this.product()?.single_purchases || []);
6664
- showPlans = computed(() => this.plansOnly || (!this.plansOnly && !this.singlePurchasesOnly));
6665
- showSinglePurchases = computed(() => this.singlePurchasesOnly || (!this.plansOnly && !this.singlePurchasesOnly));
6889
+ showPlans = computed(() => this.plansOnlySignal() || (!this.plansOnlySignal() && !this.singlePurchasesOnlySignal()));
6890
+ showSinglePurchases = computed(() => this.singlePurchasesOnlySignal() || (!this.plansOnlySignal() && !this.singlePurchasesOnlySignal()));
6666
6891
  hasBothTypes = computed(() => this.plans().length > 0 && this.singlePurchases().length > 0);
6667
6892
  tabOptions = computed(() => {
6668
6893
  const options = [];
@@ -6696,11 +6921,12 @@ class PricingTableComponent {
6696
6921
  return purchases.filter((p) => p.published_version?.name?.toLowerCase().includes(term));
6697
6922
  });
6698
6923
  cssVars = computed(() => {
6699
- const userTheme = MetrifoxService.getTheme()?.pricingTable;
6700
- const theme = mergePricingTableTheme(defaultPricingTableTheme, userTheme);
6924
+ const custom = this.themeSignal() ?? MetrifoxService.getTheme()?.pricingTable;
6925
+ const theme = mergePricingTableTheme(defaultPricingTableTheme, custom);
6701
6926
  return {
6702
6927
  ...MetrifoxService.pricingTableThemeToCssVars(theme),
6703
6928
  ...MetrifoxService.getBackgroundImage(theme),
6929
+ 'font-family': 'var(--pt-font-family, var(--cp-font-family, inherit))'
6704
6930
  };
6705
6931
  });
6706
6932
  ngOnInit() {
@@ -6738,9 +6964,9 @@ class PricingTableComponent {
6738
6964
  this.error.set(err.message || 'Failed to load pricing');
6739
6965
  this.errorOccurred.emit({
6740
6966
  message: err.message || 'Failed to load pricing',
6741
- code: err.status?.toString(),
6967
+ code: err.status?.toString()
6742
6968
  });
6743
- },
6969
+ }
6744
6970
  });
6745
6971
  }
6746
6972
  /**
@@ -6763,7 +6989,7 @@ class PricingTableComponent {
6763
6989
  this.planSelected.emit({
6764
6990
  plan: plan.published_version,
6765
6991
  interval: this.selectedInterval(),
6766
- checkoutUrl,
6992
+ checkoutUrl
6767
6993
  });
6768
6994
  // Open checkout in new tab
6769
6995
  window.open(checkoutUrl, '_blank');
@@ -6775,7 +7001,7 @@ class PricingTableComponent {
6775
7001
  const checkoutUrl = this.metrifoxService.buildCheckoutUrl(this.checkoutUsername, purchase.offering_key);
6776
7002
  this.purchaseSelected.emit({
6777
7003
  purchase: purchase.published_version,
6778
- checkoutUrl,
7004
+ checkoutUrl
6779
7005
  });
6780
7006
  // Open checkout in new tab
6781
7007
  window.open(checkoutUrl, '_blank');
@@ -6836,7 +7062,7 @@ class PricingTableComponent {
6836
7062
  EUR: '€',
6837
7063
  GBP: '£',
6838
7064
  JPY: '¥',
6839
- NGN: '₦',
7065
+ NGN: '₦'
6840
7066
  };
6841
7067
  return symbols[currency] || currency;
6842
7068
  }
@@ -6879,7 +7105,7 @@ class PricingTableComponent {
6879
7105
  monthly: 'Monthly',
6880
7106
  yearly: 'Yearly',
6881
7107
  weekly: 'Weekly',
6882
- daily: 'Daily',
7108
+ daily: 'Daily'
6883
7109
  };
6884
7110
  return labels[interval] || interval;
6885
7111
  }
@@ -6960,7 +7186,7 @@ class PricingTableComponent {
6960
7186
  price: priceOption.price.price,
6961
7187
  currency: priceOption.price.currency,
6962
7188
  quantity,
6963
- offering_key: purchase.offering_key,
7189
+ offering_key: purchase.offering_key
6964
7190
  };
6965
7191
  this.cartItems.update((items) => [...items, item]);
6966
7192
  }
@@ -6985,7 +7211,7 @@ class PricingTableComponent {
6985
7211
  checkoutWindow?.postMessage({
6986
7212
  v: 1,
6987
7213
  type: 'INIT_CART',
6988
- payload: dataToSend,
7214
+ payload: dataToSend
6989
7215
  }, '*');
6990
7216
  break;
6991
7217
  case 'ACK':
@@ -7000,7 +7226,7 @@ class PricingTableComponent {
7000
7226
  }, 5000);
7001
7227
  }
7002
7228
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: PricingTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7003
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: PricingTableComponent, isStandalone: true, selector: "metrifox-pricing-table", inputs: { checkoutUsername: "checkoutUsername", productKey: "productKey", plansOnly: "plansOnly", singlePurchasesOnly: "singlePurchasesOnly", showTabHeader: "showTabHeader" }, outputs: { planSelected: "planSelected", purchaseSelected: "purchaseSelected", errorOccurred: "errorOccurred" }, ngImport: i0, template: `
7229
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.18", type: PricingTableComponent, isStandalone: true, selector: "metrifox-pricing-table", inputs: { checkoutUsername: "checkoutUsername", productKey: "productKey", plansOnly: "plansOnly", singlePurchasesOnly: "singlePurchasesOnly", showTabHeader: "showTabHeader", theme: "theme" }, outputs: { planSelected: "planSelected", purchaseSelected: "purchaseSelected", errorOccurred: "errorOccurred" }, ngImport: i0, template: `
7004
7230
  <div class="font-sans antialiased" [ngStyle]="cssVars()">
7005
7231
  <!-- Loading State -->
7006
7232
  @if (loading()) {
@@ -7032,7 +7258,7 @@ class PricingTableComponent {
7032
7258
  <div class="flex justify-center">
7033
7259
  <div class="w-full max-w-[1089px] bg-transparent h-full rounded-2xl md:px-6 py-5">
7034
7260
  <!-- Tab Header (Listing Tabs) -->
7035
- @if (showTabHeader && hasBothTypes()) {
7261
+ @if (showTabHeaderSignal()) {
7036
7262
  <div class="w-full flex justify-center border-b border-[var(--pt-tabs-border)] mb-6">
7037
7263
  @for (tab of tabOptions(); track tab.value) {
7038
7264
  <div
@@ -7054,31 +7280,36 @@ class PricingTableComponent {
7054
7280
  <!-- Plans View -->
7055
7281
  @if (showPlans() && selectedTab() === 'plan') {
7056
7282
  <!-- Interval Toggle (Plan Tabs) -->
7057
- @if (intervals().length > 1) {
7058
- <div class="flex items-center mb-4 justify-center">
7059
- <div class="rounded-2xl p-1 flex bg-[var(--pt-interval-bg)]">
7060
- @for (interval of intervals(); track interval) {
7061
- <div
7062
- class="py-1 px-3 rounded-xl cursor-pointer transition-colors"
7063
- [class.bg-[var(--pt-interval-active-bg)]]="selectedInterval() === interval"
7064
- (click)="selectInterval(interval)">
7065
- <span
7066
- class="text-sm"
7067
- [class.text-[var(--pt-interval-active-text)]]="selectedInterval() === interval"
7068
- [class.text-[var(--pt-interval-inactive-text)]]="selectedInterval() !== interval">
7069
- {{ formatInterval(interval) }}
7070
- </span>
7071
- </div>
7072
- }
7073
- </div>
7283
+ <div class="flex items-center mb-4 justify-center">
7284
+ <div class="inline-flex items-center gap-1 bg-[var(--pt-interval-bg)] border border-[var(--pt-interval-border,var(--cp-tabs-border,var(--cp-section-content-border)))] p-1 rounded-lg shadow-sm">
7285
+ @for (interval of intervals(); track interval) {
7286
+ <div
7287
+ class="py-1.5 px-6 rounded-md cursor-pointer transition-all flex items-center justify-center"
7288
+ [class.bg-[var(--pt-interval-active-bg)]]="selectedInterval() === interval"
7289
+ [class.shadow-sm]="selectedInterval() === interval"
7290
+ [class.bg-transparent]="selectedInterval() !== interval"
7291
+ [class.hover:opacity-80]="selectedInterval() !== interval"
7292
+ (click)="selectInterval(interval)">
7293
+ <span
7294
+ class="text-sm font-medium whitespace-nowrap"
7295
+ [class.text-[var(--pt-interval-active-text)]]="selectedInterval() === interval"
7296
+ [class.text-[var(--pt-interval-inactive-text)]]="selectedInterval() !== interval">
7297
+ {{ formatInterval(interval) }}
7298
+ </span>
7299
+ </div>
7300
+ }
7074
7301
  </div>
7075
- }
7302
+ </div>
7076
7303
 
7077
7304
  <!-- Plan Cards -->
7078
7305
  <div class="w-full flex gap-x-4 px-4 justify-start overflow-x-auto flex-nowrap">
7079
7306
  @for (plan of plans(); track plan.id) {
7080
7307
  <div
7081
- class="flex flex-col rounded-2xl border border-gray-100 shrink-0 w-[330px]"
7308
+ class="flex flex-col shrink-0 w-[330px]"
7309
+ [style.borderWidth]="'var(--pt-card-border-width, 1px)'"
7310
+ [style.borderStyle]="'solid'"
7311
+ [style.borderColor]="'var(--pt-card-border, #e5e7eb)'"
7312
+ [style.borderRadius]="'var(--pt-card-radius, 1rem)'"
7082
7313
  [class.bg-[var(--pt-current-sub-card-header-bg)]]="plan.published_version.is_current_plan"
7083
7314
  [class.bg-[var(--pt-card-header-bg)]]="!plan.published_version.is_current_plan">
7084
7315
  <!-- Card Header -->
@@ -7102,7 +7333,7 @@ class PricingTableComponent {
7102
7333
  [class.bg-gradient-to-b]="plan.published_version.is_current_plan"
7103
7334
  [class.from-[var(--pt-card-gradient)]]="plan.published_version.is_current_plan"
7104
7335
  [class.to-[var(--pt-card-bg)]]="plan.published_version.is_current_plan">
7105
-
7336
+
7106
7337
  <!-- Description -->
7107
7338
  @if (plan.published_version.description) {
7108
7339
  <div class="h-[51px] mt-1 px-2">
@@ -7145,7 +7376,7 @@ class PricingTableComponent {
7145
7376
  {{ getButtonText(plan.published_version) }}
7146
7377
  </button>
7147
7378
 
7148
- <!-- Features/Entitlements -->
7379
+ <!-- Entitlements -->
7149
7380
  @if (plan.published_version.entitlements?.length || plan.published_version.credit_attachments?.length) {
7150
7381
  <div class="px-2 mt-4">
7151
7382
  <p class="text-sm font-medium text-[var(--pt-feature-text)] mb-3">
@@ -7208,7 +7439,12 @@ class PricingTableComponent {
7208
7439
  class="grid gap-4 px-4 lg:grid-cols-3 md:grid-cols-2 grid-cols-1"
7209
7440
  [class.pb-[72px]]="cartItems().length > 0">
7210
7441
  @for (purchase of filteredSinglePurchases(); track purchase.id) {
7211
- <div class="flex flex-col bg-[var(--pt-card-header-bg)] rounded-2xl border border-gray-100 w-full min-h-[187px]">
7442
+ <div class="flex flex-col bg-[var(--pt-card-header-bg)] w-full min-h-[187px]"
7443
+ [style.borderWidth]="'var(--pt-card-border-width, 1px)'"
7444
+ [style.borderStyle]="'solid'"
7445
+ [style.borderColor]="'var(--pt-card-border, #e5e7eb)'"
7446
+ [style.borderRadius]="'var(--pt-card-radius, 1rem)'"
7447
+ >
7212
7448
  <!-- Card Header -->
7213
7449
  <div class="px-4 pt-2 pb-[2px]">
7214
7450
  <span class="text-sm font-medium text-[var(--pt-card-header-text)]">
@@ -7342,7 +7578,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7342
7578
  <div class="flex justify-center">
7343
7579
  <div class="w-full max-w-[1089px] bg-transparent h-full rounded-2xl md:px-6 py-5">
7344
7580
  <!-- Tab Header (Listing Tabs) -->
7345
- @if (showTabHeader && hasBothTypes()) {
7581
+ @if (showTabHeaderSignal()) {
7346
7582
  <div class="w-full flex justify-center border-b border-[var(--pt-tabs-border)] mb-6">
7347
7583
  @for (tab of tabOptions(); track tab.value) {
7348
7584
  <div
@@ -7364,31 +7600,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7364
7600
  <!-- Plans View -->
7365
7601
  @if (showPlans() && selectedTab() === 'plan') {
7366
7602
  <!-- Interval Toggle (Plan Tabs) -->
7367
- @if (intervals().length > 1) {
7368
- <div class="flex items-center mb-4 justify-center">
7369
- <div class="rounded-2xl p-1 flex bg-[var(--pt-interval-bg)]">
7370
- @for (interval of intervals(); track interval) {
7371
- <div
7372
- class="py-1 px-3 rounded-xl cursor-pointer transition-colors"
7373
- [class.bg-[var(--pt-interval-active-bg)]]="selectedInterval() === interval"
7374
- (click)="selectInterval(interval)">
7375
- <span
7376
- class="text-sm"
7377
- [class.text-[var(--pt-interval-active-text)]]="selectedInterval() === interval"
7378
- [class.text-[var(--pt-interval-inactive-text)]]="selectedInterval() !== interval">
7379
- {{ formatInterval(interval) }}
7380
- </span>
7381
- </div>
7382
- }
7383
- </div>
7603
+ <div class="flex items-center mb-4 justify-center">
7604
+ <div class="inline-flex items-center gap-1 bg-[var(--pt-interval-bg)] border border-[var(--pt-interval-border,var(--cp-tabs-border,var(--cp-section-content-border)))] p-1 rounded-lg shadow-sm">
7605
+ @for (interval of intervals(); track interval) {
7606
+ <div
7607
+ class="py-1.5 px-6 rounded-md cursor-pointer transition-all flex items-center justify-center"
7608
+ [class.bg-[var(--pt-interval-active-bg)]]="selectedInterval() === interval"
7609
+ [class.shadow-sm]="selectedInterval() === interval"
7610
+ [class.bg-transparent]="selectedInterval() !== interval"
7611
+ [class.hover:opacity-80]="selectedInterval() !== interval"
7612
+ (click)="selectInterval(interval)">
7613
+ <span
7614
+ class="text-sm font-medium whitespace-nowrap"
7615
+ [class.text-[var(--pt-interval-active-text)]]="selectedInterval() === interval"
7616
+ [class.text-[var(--pt-interval-inactive-text)]]="selectedInterval() !== interval">
7617
+ {{ formatInterval(interval) }}
7618
+ </span>
7619
+ </div>
7620
+ }
7384
7621
  </div>
7385
- }
7622
+ </div>
7386
7623
 
7387
7624
  <!-- Plan Cards -->
7388
7625
  <div class="w-full flex gap-x-4 px-4 justify-start overflow-x-auto flex-nowrap">
7389
7626
  @for (plan of plans(); track plan.id) {
7390
7627
  <div
7391
- class="flex flex-col rounded-2xl border border-gray-100 shrink-0 w-[330px]"
7628
+ class="flex flex-col shrink-0 w-[330px]"
7629
+ [style.borderWidth]="'var(--pt-card-border-width, 1px)'"
7630
+ [style.borderStyle]="'solid'"
7631
+ [style.borderColor]="'var(--pt-card-border, #e5e7eb)'"
7632
+ [style.borderRadius]="'var(--pt-card-radius, 1rem)'"
7392
7633
  [class.bg-[var(--pt-current-sub-card-header-bg)]]="plan.published_version.is_current_plan"
7393
7634
  [class.bg-[var(--pt-card-header-bg)]]="!plan.published_version.is_current_plan">
7394
7635
  <!-- Card Header -->
@@ -7412,7 +7653,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7412
7653
  [class.bg-gradient-to-b]="plan.published_version.is_current_plan"
7413
7654
  [class.from-[var(--pt-card-gradient)]]="plan.published_version.is_current_plan"
7414
7655
  [class.to-[var(--pt-card-bg)]]="plan.published_version.is_current_plan">
7415
-
7656
+
7416
7657
  <!-- Description -->
7417
7658
  @if (plan.published_version.description) {
7418
7659
  <div class="h-[51px] mt-1 px-2">
@@ -7455,7 +7696,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7455
7696
  {{ getButtonText(plan.published_version) }}
7456
7697
  </button>
7457
7698
 
7458
- <!-- Features/Entitlements -->
7699
+ <!-- Entitlements -->
7459
7700
  @if (plan.published_version.entitlements?.length || plan.published_version.credit_attachments?.length) {
7460
7701
  <div class="px-2 mt-4">
7461
7702
  <p class="text-sm font-medium text-[var(--pt-feature-text)] mb-3">
@@ -7518,7 +7759,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7518
7759
  class="grid gap-4 px-4 lg:grid-cols-3 md:grid-cols-2 grid-cols-1"
7519
7760
  [class.pb-[72px]]="cartItems().length > 0">
7520
7761
  @for (purchase of filteredSinglePurchases(); track purchase.id) {
7521
- <div class="flex flex-col bg-[var(--pt-card-header-bg)] rounded-2xl border border-gray-100 w-full min-h-[187px]">
7762
+ <div class="flex flex-col bg-[var(--pt-card-header-bg)] w-full min-h-[187px]"
7763
+ [style.borderWidth]="'var(--pt-card-border-width, 1px)'"
7764
+ [style.borderStyle]="'solid'"
7765
+ [style.borderColor]="'var(--pt-card-border, #e5e7eb)'"
7766
+ [style.borderRadius]="'var(--pt-card-radius, 1rem)'"
7767
+ >
7522
7768
  <!-- Card Header -->
7523
7769
  <div class="px-4 pt-2 pb-[2px]">
7524
7770
  <span class="text-sm font-medium text-[var(--pt-card-header-text)]">
@@ -7629,6 +7875,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7629
7875
  type: Input
7630
7876
  }], showTabHeader: [{
7631
7877
  type: Input
7878
+ }], theme: [{
7879
+ type: Input
7632
7880
  }], planSelected: [{
7633
7881
  type: Output
7634
7882
  }], purchaseSelected: [{
@@ -7666,8 +7914,8 @@ class MetrifoxModule {
7666
7914
  ngModule: MetrifoxModule,
7667
7915
  providers: [
7668
7916
  provideHttpClient(withInterceptorsFromDi()),
7669
- MetrifoxService,
7670
- ],
7917
+ MetrifoxService
7918
+ ]
7671
7919
  };
7672
7920
  }
7673
7921
  /**
@@ -7676,7 +7924,7 @@ class MetrifoxModule {
7676
7924
  static forChild() {
7677
7925
  return {
7678
7926
  ngModule: MetrifoxModule,
7679
- providers: [],
7927
+ providers: []
7680
7928
  };
7681
7929
  }
7682
7930
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: MetrifoxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -7694,12 +7942,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7694
7942
  imports: [
7695
7943
  CommonModule,
7696
7944
  CustomerPortalComponent,
7697
- PricingTableComponent,
7945
+ PricingTableComponent
7698
7946
  ],
7699
7947
  exports: [
7700
7948
  CustomerPortalComponent,
7701
- PricingTableComponent,
7702
- ],
7949
+ PricingTableComponent
7950
+ ]
7703
7951
  }]
7704
7952
  }] });
7705
7953
  /**
@@ -7722,7 +7970,7 @@ function provideMetrifox(config) {
7722
7970
  }
7723
7971
  return [
7724
7972
  provideHttpClient(),
7725
- MetrifoxService,
7973
+ MetrifoxService
7726
7974
  ];
7727
7975
  }
7728
7976