@metrifox/angular-sdk 0.0.2-beta.2 → 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 (21) hide show
  1. package/dist/fesm2022/index.mjs +1536 -1343
  2. package/dist/lib/metrifox.service.d.ts +5 -5
  3. package/dist/lib/types/enum.d.ts +4 -2
  4. package/dist/lib/types/interface.d.ts +5 -0
  5. package/dist/modules/customer-portal/components/billing-history.component.d.ts +3 -2
  6. package/dist/modules/customer-portal/components/credit/credit-balance-section.component.d.ts +12 -10
  7. package/dist/modules/customer-portal/components/customer-portal.component.d.ts +7 -7
  8. package/dist/modules/customer-portal/components/entitlements/entitlement-summary.component.d.ts +15 -0
  9. package/dist/modules/customer-portal/components/entitlements/entitlement-usage.component.d.ts +35 -0
  10. package/dist/modules/customer-portal/components/entitlements/entitlements-section.component.d.ts +5 -21
  11. package/dist/modules/customer-portal/components/invoice-preview.component.d.ts +8 -7
  12. package/dist/modules/customer-portal/components/payment.component.d.ts +4 -3
  13. package/dist/modules/customer-portal/components/plan/plans-section.component.d.ts +28 -26
  14. package/dist/modules/customer-portal/components/subscription/subscription-details.component.d.ts +12 -0
  15. package/dist/modules/customer-portal/components/subscription/subscription-items.component.d.ts +27 -0
  16. package/dist/modules/customer-portal/components/subscription/subscription-section.component.d.ts +5 -25
  17. package/dist/modules/pricing-table/components/pricing-table.component.d.ts +12 -6
  18. package/dist/modules/pricing-table/utils/defaults.d.ts +2 -0
  19. package/dist/public-api.d.ts +10 -10
  20. package/dist/styles.css +1 -1
  21. 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,14 +691,14 @@ 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',
@@ -705,13 +708,13 @@ const defaultCustomerPortalTheme = {
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: '14px', 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',
@@ -769,8 +772,8 @@ const defaultCustomerPortalTheme = {
769
772
  fontSize: '14px',
770
773
  fontWeight: '400',
771
774
  headerFontSize: '14px',
772
- headerFontWeight: '500',
773
- },
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>
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">
1150
1370
  <span class="text-[var(--cp-section-label-color)]"
1151
1371
  [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>
1170
- <span class="text-[var(--cp-section-label-color)]"
1171
- [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) }}
1561
+ [style.fontWeight]="'var(--cp-section-value-weight, 600)'">
1562
+ {{ _capitalize(child.name) }}
1594
1563
  </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) }}
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() {
@@ -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,209 +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-[var(--cp-table-text)] max-w-[120px] truncate"
3140
- [style.fontSize]="'var(--cp-table-row-size)'"
3141
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ entitlement.feature_key }}</span>
3142
- </div>
3143
- </td>
3144
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3145
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3146
- [style.fontSize]="'var(--cp-table-row-size)'"
3147
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3148
- <div>
3149
- <span>{{ _capitalize(entitlement.feature_type) }}</span>
3150
- @if (entitlement.usage_model) {
3151
- <span class="block mt-1">{{ formatUsageModel(entitlement) }}</span>
3152
- }
3153
- </div>
3154
- </td>
3155
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3156
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3157
- [style.fontSize]="'var(--cp-table-row-size)'"
3158
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3159
- {{ formatIncludedAllowance(entitlement) }}
3160
- </td>
3161
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3162
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3163
- [style.fontSize]="'var(--cp-table-row-size)'"
3164
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3165
- {{ formatUsageLimits(entitlement) }}
3166
- </td>
3167
- </tr>
3168
- }
3169
- </tbody>
3170
- </table>
3171
- } @else {
3172
- <div class="flex flex-col items-center gap-y-3 py-12">
3173
- <span [innerHTML]="_getIcon('noteEmpty')"></span>
3174
- <span class="text-sm text-[var(--cp-section-empty-text)]">No entitlements attached to this subscription</span>
3175
- </div>
3176
- }
3177
- </div>
3624
+ <cp-entitlement-summary [entitlementSummary]="entitlementSummary"></cp-entitlement-summary>
3178
3625
  }
3179
3626
 
3180
3627
  <!-- Usage Tab Content -->
3181
3628
  @if (entitlementTab() === 'usage') {
3182
- <div class="bg-transparent rounded-2xl px-3 pt-5">
3183
- @if (getMeteredEntitlements().length > 0) {
3184
- <!-- Header -->
3185
- <div class="grid grid-cols-4 border-b border-[var(--cp-table-border)] gap-x-4 pr-12 bg-[var(--cp-table-header-bg)]"
3186
- [style.padding]="'var(--cp-table-cell-padding, 0.75rem 1.5rem)'">
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)'">Feature</div>
3190
- <div class="text-[var(--cp-table-header-text)]"
3191
- [style.fontSize]="'var(--cp-table-header-size)'"
3192
- [style.fontWeight]="'var(--cp-table-header-weight)'">Type</div>
3193
- <div class="col-span-2 text-[var(--cp-table-header-text)]"
3194
- [style.fontSize]="'var(--cp-table-header-size)'"
3195
- [style.fontWeight]="'var(--cp-table-header-weight)'">Usage</div>
3196
- </div>
3197
-
3198
- <!-- Rows -->
3199
- @for (usage of getMeteredEntitlements(); track usage.id || $index; let rowIdx = $index) {
3200
- <div class="border-b border-[var(--cp-table-border)] last:border-0"
3201
- [class]="rowIdx % 2 === 0 ? 'bg-[var(--cp-table-row-even-bg)]' : 'bg-[var(--cp-table-row-odd-bg)]'"
3202
- [style.padding]="'var(--cp-table-cell-padding, 1rem 1.5rem)'">
3203
- <!-- Main Row (Collapsible Trigger) -->
3204
- <div class="flex items-center cursor-pointer" (click)="toggleEntitlementExpand(usage.id)">
3205
- <div class="flex-1 grid grid-cols-4 gap-4 items-center pr-8">
3206
- <!-- Feature -->
3207
- <div class="flex flex-col gap-y-1 items-start max-w-[120px] text-balance">
3208
- <span class="text-[var(--cp-table-text)]"
3209
- [style.fontSize]="'var(--cp-table-row-size)'"
3210
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ usage.feature_name || '-' }}</span>
3211
- <span class="text-[var(--cp-table-text)] max-w-[120px] truncate"
3212
- [style.fontSize]="'var(--cp-table-row-size)'"
3213
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ usage.feature_key }}</span>
3214
- </div>
3215
-
3216
- <!-- Type -->
3217
- <div>
3218
- <span class="text-[var(--cp-table-text)]"
3219
- [style.fontSize]="'var(--cp-table-row-size)'"
3220
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ _capitalize(usage.type?.split('_').join(' ') || '') }}</span>
3221
- </div>
3222
-
3223
- <!-- Usage -->
3224
- <div class="col-span-2">
3225
- <span class="text-[var(--cp-table-text)]"
3226
- [style.fontSize]="'var(--cp-table-row-size)'"
3227
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getEntitlementUsageBalance(usage) }}</span>
3228
- <div class="w-full flex items-center gap-x-2">
3229
- <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">
3230
- <div class="h-[6px] rounded" [style.width.%]="getEntitlementUsagePercent(usage)" [style.backgroundColor]="'var(--cp-section-usage-bar-color)'"></div>
3231
- </div>
3232
- <span class="text-[var(--cp-table-text)]"
3233
- [style.fontSize]="'var(--cp-table-row-size)'"
3234
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getEntitlementUsageText(usage) }}</span>
3235
- </div>
3236
- </div>
3237
- </div>
3238
-
3239
- <!-- Expand Icon -->
3240
- <div class="transform transition-transform duration-200" [class.rotate-180]="isEntitlementExpanded(usage.id)">
3241
- <span [innerHTML]="_getIcon('arrowDown')"></span>
3242
- </div>
3243
- </div>
3244
-
3245
- <!-- Expanded Content (Pools) -->
3246
- @if (isEntitlementExpanded(usage.id)) {
3247
- <div class="w-full rounded-lg overflow-hidden flex flex-col items-start justify-start gap-y-0 pt-4">
3248
- @for (pool of getProcessedPools(usage); track pool.pool) {
3249
- <div class="w-full flex items-center px-2 py-3 gap-x-12 sm:gap-x-20 md:gap-x-40">
3250
- <span class="w-20 text-[var(--cp-table-text)]"
3251
- [style.fontSize]="'var(--cp-table-row-size)'"
3252
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ pool.pool }}</span>
3253
- <div class="flex-1">
3254
- <span class="text-[var(--cp-table-text)]"
3255
- [style.fontSize]="'var(--cp-table-row-size)'"
3256
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3257
- @if (!pool.isUnlimited) {
3258
- @if (pool.balance < 0) {
3259
- {{ _formatNumber(Math.abs(pool.balance)) }} used above limit
3260
- } @else {
3261
- {{ _formatNumber(pool.balance) }} left
3262
- }
3263
- }
3264
- </span>
3265
- <div class="w-full flex items-center gap-x-2">
3266
- <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">
3267
- <div class="h-[6px]" [style.width.%]="pool.percent" [style.backgroundColor]="'var(--cp-section-usage-bar-color)'"></div>
3268
- </div>
3269
- <span class="text-[var(--cp-table-text)]"
3270
- [style.fontSize]="'var(--cp-table-row-size)'"
3271
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3272
- @if (pool.isUnlimited) {
3273
- {{ _formatNumber(pool.used) }}/ Unlimited
3274
- } @else {
3275
- {{ _formatNumber(pool.used) }}/{{ _formatNumber(pool.amount) }}
3276
- }
3277
- </span>
3278
- </div>
3279
- @if (pool.nextResetAt) {
3280
- <span class="text-[var(--cp-table-text)]"
3281
- [style.fontSize]="'var(--cp-table-row-size)'"
3282
- [style.fontWeight]="'var(--cp-table-row-weight)'">resets on {{ pool.nextResetAt }}</span>
3283
- }
3284
- </div>
3285
- </div>
3286
- }
3287
- </div>
3288
- }
3289
- </div>
3290
- }
3291
- } @else {
3292
- <div class="flex flex-col items-center gap-y-3 py-12">
3293
- <span [innerHTML]="_getIcon('noteEmpty')"></span>
3294
- <span class="text-sm text-[var(--cp-section-empty-text)]">No metered entitlements attached to this subscription</span>
3295
- </div>
3296
- }
3297
- </div>
3629
+ <cp-entitlement-usage [entitlementUsage]="entitlementUsage"></cp-entitlement-usage>
3298
3630
  }
3299
3631
  </div>
3300
3632
  </div>
3301
3633
  }
3302
- `, 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 });
3303
3635
  }
3304
3636
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EntitlementsSectionComponent, decorators: [{
3305
3637
  type: Component,
3306
3638
  args: [{
3307
3639
  selector: 'cp-entitlements-section',
3308
3640
  standalone: true,
3309
- imports: [CommonModule],
3641
+ imports: [CommonModule, EntitlementSummaryComponent, EntitlementUsageComponent],
3310
3642
  changeDetection: ChangeDetectionStrategy.OnPush,
3311
3643
  template: `
3312
3644
  @if (!_isSectionHidden('entitlementUsage')) {
@@ -3337,7 +3669,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
3337
3669
  (click)="changeEntitlementTab('summary')">
3338
3670
  Summary
3339
3671
  </button>
3340
- @if (getMeteredEntitlements().length > 0) {
3672
+ @if (hasMeteredEntitlements) {
3341
3673
  <button
3342
3674
  type="button"
3343
3675
  class="px-6 py-1.5 rounded-md text-sm font-medium transition-all outline-none"
@@ -3352,202 +3684,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
3352
3684
 
3353
3685
  <!-- Summary Tab Content -->
3354
3686
  @if (entitlementTab() === 'summary') {
3355
- <div class="overflow-x-auto bg-transparent">
3356
- @if (entitlementSummary.length > 0) {
3357
- <table class="min-w-full border-collapse text-left relative">
3358
- <thead>
3359
- <tr>
3360
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3361
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3362
- [style.fontSize]="'var(--cp-table-header-size)'"
3363
- [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</th>
3364
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3365
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3366
- [style.fontSize]="'var(--cp-table-header-size)'"
3367
- [style.fontWeight]="'var(--cp-table-header-weight)'">Meter type</th>
3368
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3369
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3370
- [style.fontSize]="'var(--cp-table-header-size)'"
3371
- [style.fontWeight]="'var(--cp-table-header-weight)'">Included allowance</th>
3372
- <th class="text-[var(--cp-table-header-text)] bg-[var(--cp-table-header-bg)] border-b border-[var(--cp-table-border)] whitespace-nowrap"
3373
- [style.padding]="'var(--cp-table-cell-padding, 0.5rem 0.75rem)'"
3374
- [style.fontSize]="'var(--cp-table-header-size)'"
3375
- [style.fontWeight]="'var(--cp-table-header-weight)'">Usage limits</th>
3376
- </tr>
3377
- </thead>
3378
- <tbody>
3379
- @for (entitlement of entitlementSummary; track entitlement.id || $index; let rowIdx = $index) {
3380
- <tr [class]="rowIdx % 2 === 0 ? 'bg-[var(--cp-table-row-even-bg)]' : 'bg-[var(--cp-table-row-odd-bg)]'">
3381
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3382
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3383
- [style.fontSize]="'var(--cp-table-row-size)'"
3384
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3385
- <div class="flex flex-col gap-y-1 items-start max-w-[130px]">
3386
- <span>{{ entitlement.feature_name || '-' }}</span>
3387
- <span class="text-[var(--cp-table-text)] max-w-[120px] truncate"
3388
- [style.fontSize]="'var(--cp-table-row-size)'"
3389
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ entitlement.feature_key }}</span>
3390
- </div>
3391
- </td>
3392
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3393
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3394
- [style.fontSize]="'var(--cp-table-row-size)'"
3395
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3396
- <div>
3397
- <span>{{ _capitalize(entitlement.feature_type) }}</span>
3398
- @if (entitlement.usage_model) {
3399
- <span class="block mt-1">{{ formatUsageModel(entitlement) }}</span>
3400
- }
3401
- </div>
3402
- </td>
3403
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3404
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3405
- [style.fontSize]="'var(--cp-table-row-size)'"
3406
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3407
- {{ formatIncludedAllowance(entitlement) }}
3408
- </td>
3409
- <td class="text-[var(--cp-table-text)] border-y border-[var(--cp-table-border)]"
3410
- [style.padding]="'var(--cp-table-cell-padding, 1rem 0.75rem)'"
3411
- [style.fontSize]="'var(--cp-table-row-size)'"
3412
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3413
- {{ formatUsageLimits(entitlement) }}
3414
- </td>
3415
- </tr>
3416
- }
3417
- </tbody>
3418
- </table>
3419
- } @else {
3420
- <div class="flex flex-col items-center gap-y-3 py-12">
3421
- <span [innerHTML]="_getIcon('noteEmpty')"></span>
3422
- <span class="text-sm text-[var(--cp-section-empty-text)]">No entitlements attached to this subscription</span>
3423
- </div>
3424
- }
3425
- </div>
3687
+ <cp-entitlement-summary [entitlementSummary]="entitlementSummary"></cp-entitlement-summary>
3426
3688
  }
3427
3689
 
3428
3690
  <!-- Usage Tab Content -->
3429
3691
  @if (entitlementTab() === 'usage') {
3430
- <div class="bg-transparent rounded-2xl px-3 pt-5">
3431
- @if (getMeteredEntitlements().length > 0) {
3432
- <!-- Header -->
3433
- <div class="grid grid-cols-4 border-b border-[var(--cp-table-border)] gap-x-4 pr-12 bg-[var(--cp-table-header-bg)]"
3434
- [style.padding]="'var(--cp-table-cell-padding, 0.75rem 1.5rem)'">
3435
- <div class="text-[var(--cp-table-header-text)]"
3436
- [style.fontSize]="'var(--cp-table-header-size)'"
3437
- [style.fontWeight]="'var(--cp-table-header-weight)'">Feature</div>
3438
- <div class="text-[var(--cp-table-header-text)]"
3439
- [style.fontSize]="'var(--cp-table-header-size)'"
3440
- [style.fontWeight]="'var(--cp-table-header-weight)'">Type</div>
3441
- <div class="col-span-2 text-[var(--cp-table-header-text)]"
3442
- [style.fontSize]="'var(--cp-table-header-size)'"
3443
- [style.fontWeight]="'var(--cp-table-header-weight)'">Usage</div>
3444
- </div>
3445
-
3446
- <!-- Rows -->
3447
- @for (usage of getMeteredEntitlements(); track usage.id || $index; let rowIdx = $index) {
3448
- <div class="border-b border-[var(--cp-table-border)] last:border-0"
3449
- [class]="rowIdx % 2 === 0 ? 'bg-[var(--cp-table-row-even-bg)]' : 'bg-[var(--cp-table-row-odd-bg)]'"
3450
- [style.padding]="'var(--cp-table-cell-padding, 1rem 1.5rem)'">
3451
- <!-- Main Row (Collapsible Trigger) -->
3452
- <div class="flex items-center cursor-pointer" (click)="toggleEntitlementExpand(usage.id)">
3453
- <div class="flex-1 grid grid-cols-4 gap-4 items-center pr-8">
3454
- <!-- Feature -->
3455
- <div class="flex flex-col gap-y-1 items-start max-w-[120px] text-balance">
3456
- <span class="text-[var(--cp-table-text)]"
3457
- [style.fontSize]="'var(--cp-table-row-size)'"
3458
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ usage.feature_name || '-' }}</span>
3459
- <span class="text-[var(--cp-table-text)] max-w-[120px] truncate"
3460
- [style.fontSize]="'var(--cp-table-row-size)'"
3461
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ usage.feature_key }}</span>
3462
- </div>
3463
-
3464
- <!-- Type -->
3465
- <div>
3466
- <span class="text-[var(--cp-table-text)]"
3467
- [style.fontSize]="'var(--cp-table-row-size)'"
3468
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ _capitalize(usage.type?.split('_').join(' ') || '') }}</span>
3469
- </div>
3470
-
3471
- <!-- Usage -->
3472
- <div class="col-span-2">
3473
- <span class="text-[var(--cp-table-text)]"
3474
- [style.fontSize]="'var(--cp-table-row-size)'"
3475
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getEntitlementUsageBalance(usage) }}</span>
3476
- <div class="w-full flex items-center gap-x-2">
3477
- <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">
3478
- <div class="h-[6px] rounded" [style.width.%]="getEntitlementUsagePercent(usage)" [style.backgroundColor]="'var(--cp-section-usage-bar-color)'"></div>
3479
- </div>
3480
- <span class="text-[var(--cp-table-text)]"
3481
- [style.fontSize]="'var(--cp-table-row-size)'"
3482
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ getEntitlementUsageText(usage) }}</span>
3483
- </div>
3484
- </div>
3485
- </div>
3486
-
3487
- <!-- Expand Icon -->
3488
- <div class="transform transition-transform duration-200" [class.rotate-180]="isEntitlementExpanded(usage.id)">
3489
- <span [innerHTML]="_getIcon('arrowDown')"></span>
3490
- </div>
3491
- </div>
3492
-
3493
- <!-- Expanded Content (Pools) -->
3494
- @if (isEntitlementExpanded(usage.id)) {
3495
- <div class="w-full rounded-lg overflow-hidden flex flex-col items-start justify-start gap-y-0 pt-4">
3496
- @for (pool of getProcessedPools(usage); track pool.pool) {
3497
- <div class="w-full flex items-center px-2 py-3 gap-x-12 sm:gap-x-20 md:gap-x-40">
3498
- <span class="w-20 text-[var(--cp-table-text)]"
3499
- [style.fontSize]="'var(--cp-table-row-size)'"
3500
- [style.fontWeight]="'var(--cp-table-row-weight)'">{{ pool.pool }}</span>
3501
- <div class="flex-1">
3502
- <span class="text-[var(--cp-table-text)]"
3503
- [style.fontSize]="'var(--cp-table-row-size)'"
3504
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3505
- @if (!pool.isUnlimited) {
3506
- @if (pool.balance < 0) {
3507
- {{ _formatNumber(Math.abs(pool.balance)) }} used above limit
3508
- } @else {
3509
- {{ _formatNumber(pool.balance) }} left
3510
- }
3511
- }
3512
- </span>
3513
- <div class="w-full flex items-center gap-x-2">
3514
- <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">
3515
- <div class="h-[6px]" [style.width.%]="pool.percent" [style.backgroundColor]="'var(--cp-section-usage-bar-color)'"></div>
3516
- </div>
3517
- <span class="text-[var(--cp-table-text)]"
3518
- [style.fontSize]="'var(--cp-table-row-size)'"
3519
- [style.fontWeight]="'var(--cp-table-row-weight)'">
3520
- @if (pool.isUnlimited) {
3521
- {{ _formatNumber(pool.used) }}/ Unlimited
3522
- } @else {
3523
- {{ _formatNumber(pool.used) }}/{{ _formatNumber(pool.amount) }}
3524
- }
3525
- </span>
3526
- </div>
3527
- @if (pool.nextResetAt) {
3528
- <span class="text-[var(--cp-table-text)]"
3529
- [style.fontSize]="'var(--cp-table-row-size)'"
3530
- [style.fontWeight]="'var(--cp-table-row-weight)'">resets on {{ pool.nextResetAt }}</span>
3531
- }
3532
- </div>
3533
- </div>
3534
- }
3535
- </div>
3536
- }
3537
- </div>
3538
- }
3539
- } @else {
3540
- <div class="flex flex-col items-center gap-y-3 py-12">
3541
- <span [innerHTML]="_getIcon('noteEmpty')"></span>
3542
- <span class="text-sm text-[var(--cp-section-empty-text)]">No metered entitlements attached to this subscription</span>
3543
- </div>
3544
- }
3545
- </div>
3692
+ <cp-entitlement-usage [entitlementUsage]="entitlementUsage"></cp-entitlement-usage>
3546
3693
  }
3547
3694
  </div>
3548
3695
  </div>
3549
3696
  }
3550
- `,
3697
+ `
3551
3698
  }]
3552
3699
  }], propDecorators: { entitlementSummary: [{
3553
3700
  type: Input
@@ -3738,7 +3885,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
3738
3885
  </div>
3739
3886
  </div>
3740
3887
  }
3741
- `,
3888
+ `
3742
3889
  }]
3743
3890
  }], propDecorators: { subscription: [{
3744
3891
  type: Input
@@ -3969,7 +4116,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
3969
4116
  </div>
3970
4117
  </div>
3971
4118
  }
3972
- `,
4119
+ `
3973
4120
  }]
3974
4121
  }], propDecorators: { billingHistory: [{
3975
4122
  type: Input
@@ -4015,7 +4162,7 @@ class PlansSectionComponent {
4015
4162
  monthly: 'Monthly',
4016
4163
  quarterly: 'Quarterly',
4017
4164
  biannually: 'Biannually',
4018
- yearly: 'Yearly',
4165
+ yearly: 'Yearly'
4019
4166
  };
4020
4167
  return labels[interval] || capitalize(interval);
4021
4168
  }
@@ -4023,36 +4170,40 @@ class PlansSectionComponent {
4023
4170
  const allPriceOptions = [
4024
4171
  ...(plan.price_options || []),
4025
4172
  ...(plan.entitlement_price_options || []),
4026
- ...(plan.credit_attachment_price_options || []),
4173
+ ...(plan.credit_attachment_price_options || [])
4027
4174
  ];
4028
4175
  return allPriceOptions.find((po) => po.price?.billing_interval === this.selectedPlanInterval());
4029
4176
  }
4030
4177
  getPlanPriceInteger(plan) {
4031
4178
  const priceOption = this.getPlanPriceOption(plan);
4032
- if (!priceOption?.price)
4179
+ const price = priceOption?.price;
4180
+ if (!price)
4033
4181
  return 'Contact';
4034
- let amount = priceOption.price.price;
4035
- if (priceOption.price.tiers?.length > 0) {
4036
- const tier = priceOption.price.tiers[0];
4037
- 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);
4038
4187
  }
4039
- const currency = priceOption.price.currency || 'USD';
4188
+ const currency = price.currency || 'USD';
4040
4189
  const symbol = getCurrencySymbol(currency);
4041
- const price = formatPriceAmount(amount);
4042
- const amountParts = price?.split('.');
4190
+ const formatted = formatPriceAmount(amount);
4191
+ const amountParts = formatted?.split('.');
4043
4192
  return `${symbol}${amountParts?.[0] ?? '0'}`;
4044
4193
  }
4045
4194
  getPlanPriceDecimal(plan) {
4046
4195
  const priceOption = this.getPlanPriceOption(plan);
4047
- if (!priceOption?.price)
4196
+ const price = priceOption?.price;
4197
+ if (!price)
4048
4198
  return '00';
4049
- let amount = priceOption.price.price;
4050
- if (priceOption.price.tiers?.length > 0) {
4051
- const tier = priceOption.price.tiers[0];
4052
- 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);
4053
4204
  }
4054
- const price = formatPriceAmount(amount);
4055
- const amountParts = price?.split('.');
4205
+ const formatted = formatPriceAmount(amount);
4206
+ const amountParts = formatted?.split('.');
4056
4207
  return amountParts && amountParts.length > 1 ? amountParts[1].padEnd(2, '0').slice(0, 2) : '00';
4057
4208
  }
4058
4209
  getMultiplyNumber(interval, intervalValue) {
@@ -4063,26 +4214,29 @@ class PlansSectionComponent {
4063
4214
  monthly: v,
4064
4215
  quarterly: 3 * v,
4065
4216
  biannually: 6 * v,
4066
- yearly: 12 * v,
4217
+ yearly: 12 * v
4067
4218
  };
4068
4219
  return map[interval] ?? v;
4069
4220
  }
4070
4221
  getPlanFixedPriceBilledAmount(plan) {
4071
4222
  const priceOption = this.getPlanPriceOption(plan);
4072
- if (!priceOption?.price)
4223
+ const price = priceOption?.price;
4224
+ if (!price)
4073
4225
  return 0;
4074
- let unitPrice = priceOption.price.price;
4075
- if (priceOption.price.tiers?.length) {
4076
- const tier = priceOption.price.tiers[0];
4077
- 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);
4078
4231
  }
4079
4232
  const interval = this.selectedPlanInterval();
4080
- const intervalValue = priceOption.price.billing_interval_value ?? 1;
4233
+ const intervalValue = price.billing_interval_value ?? 1;
4081
4234
  return this.getMultiplyNumber(interval, intervalValue) * (unitPrice ?? 0);
4082
4235
  }
4083
4236
  getPlanFixedPriceCurrencySymbol(plan) {
4084
4237
  const po = this.getPlanPriceOption(plan);
4085
- return getCurrencySymbol(po?.price?.currency);
4238
+ const price = po?.price;
4239
+ return getCurrencySymbol(price?.currency || 'USD');
4086
4240
  }
4087
4241
  hasFixedPrice(plan) {
4088
4242
  const interval = this.selectedPlanInterval();
@@ -4098,49 +4252,56 @@ class PlansSectionComponent {
4098
4252
  const interval = this.selectedPlanInterval();
4099
4253
  return [
4100
4254
  ...(plan.entitlement_price_options || []).filter((po) => po.price?.billing_interval === interval),
4101
- ...(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)
4102
4256
  ];
4103
4257
  }
4104
4258
  getDynamicPriceName(priceOption) {
4105
- 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';
4106
4263
  }
4107
4264
  formatDynamicPrice(priceOption) {
4108
- if (!priceOption?.price)
4265
+ const price = priceOption?.price;
4266
+ if (!price)
4109
4267
  return '';
4110
- const tiers = priceOption.price.tiers || [];
4268
+ const tiers = price.tiers || [];
4111
4269
  if (tiers.length === 0)
4112
4270
  return '';
4113
4271
  const tier = tiers[0];
4114
- const currency = priceOption.price.currency || 'USD';
4272
+ const currency = price.currency || 'USD';
4115
4273
  const symbol = getCurrencySymbol(currency);
4116
- 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);
4117
4275
  const formattedAmount = formatPriceAmount(amount);
4118
- const owner = priceOption.price.owner;
4119
- 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 || '';
4120
4279
  return unitLabel ? `${symbol}${formattedAmount}/${unitLabel}` : `${symbol}${formattedAmount}`;
4121
4280
  }
4122
4281
  formatDynamicPriceFull(priceOption) {
4123
- if (!priceOption?.price)
4282
+ const price = priceOption?.price;
4283
+ if (!price)
4124
4284
  return '';
4125
- const tiers = priceOption.price.tiers || [];
4285
+ const tiers = price.tiers || [];
4126
4286
  if (tiers.length === 0)
4127
4287
  return '';
4128
4288
  const tier = tiers[0];
4129
- const currency = priceOption.price.currency || 'USD';
4289
+ const currency = price.currency || 'USD';
4130
4290
  const symbol = getCurrencySymbol(currency);
4131
- 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);
4132
4292
  const name = this.getDynamicPriceName(priceOption);
4133
4293
  return `${symbol}${amount.toFixed(2)}/${name}`;
4134
4294
  }
4135
4295
  getDynamicPriceAmountDisplay(priceOption) {
4136
- if (!priceOption?.price)
4296
+ const price = priceOption?.price;
4297
+ if (!price)
4137
4298
  return '';
4138
- const tiers = priceOption.price.tiers || [];
4299
+ const tiers = price.tiers || [];
4139
4300
  if (tiers.length === 0)
4140
4301
  return '';
4141
4302
  const tier = tiers[0];
4142
- const amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4143
- 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';
4144
4305
  const symbol = getCurrencySymbol(currency);
4145
4306
  return `${symbol}${amount.toFixed(2)}`;
4146
4307
  }
@@ -4148,30 +4309,30 @@ class PlansSectionComponent {
4148
4309
  const prices = this.getDynamicPrices(plan);
4149
4310
  if (prices.length === 0)
4150
4311
  return '0';
4151
- const firstPrice = prices[0];
4152
- const tiers = firstPrice?.price?.tiers || [];
4312
+ const firstPriceObj = prices[0].price;
4313
+ const tiers = firstPriceObj?.tiers || [];
4153
4314
  if (tiers.length === 0)
4154
4315
  return '0';
4155
4316
  const tier = tiers[0];
4156
- const amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4157
- 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';
4158
4319
  const symbol = getCurrencySymbol(currency);
4159
- const price = formatPriceAmount(amount);
4160
- const amountParts = price?.split('.');
4320
+ const formatted = formatPriceAmount(amount);
4321
+ const amountParts = formatted?.split('.');
4161
4322
  return `${symbol}${amountParts?.[0] ?? '0'}`;
4162
4323
  }
4163
4324
  getMainDynamicPriceDecimal(plan) {
4164
4325
  const prices = this.getDynamicPrices(plan);
4165
4326
  if (prices.length === 0)
4166
4327
  return '00';
4167
- const firstPrice = prices[0];
4168
- const tiers = firstPrice?.price?.tiers || [];
4328
+ const firstPriceObj = prices[0].price;
4329
+ const tiers = firstPriceObj?.tiers || [];
4169
4330
  if (tiers.length === 0)
4170
4331
  return '00';
4171
4332
  const tier = tiers[0];
4172
- const amount = tier.unit_price || tier.package_price || tier.flat_fee || 0;
4173
- const price = formatPriceAmount(amount);
4174
- 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('.');
4175
4336
  return amountParts && amountParts.length > 1 ? amountParts[1].padEnd(2, '0').slice(0, 2) : '00';
4176
4337
  }
4177
4338
  getMainDynamicPriceUnit(plan) {
@@ -4289,15 +4450,14 @@ class PlansSectionComponent {
4289
4450
  <div class="flex gap-x-2 overflow-x-auto whitespace-nowrap px-6 py-4 -mx-4">
4290
4451
  @for (plan of plans; track plan.id; let idx = $index) {
4291
4452
  <div
4292
- class="flex flex-col shrink-0 w-[330px] overflow-hidden"
4293
- [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)'"
4294
4455
  [style.borderWidth]="'var(--pt-card-border-width, 1px)'"
4295
4456
  [style.borderStyle]="'solid'"
4296
- [style.borderColor]="'var(--pt-card-border)'"
4457
+ [style.borderColor]="'var(--pt-card-border, #e5e7eb)'"
4297
4458
  [style.background-color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-bg)' : 'var(--pt-card-header-bg)'">
4298
4459
  <!-- Card Header -->
4299
- <div class="flex items-center justify-between pl-4 pr-[5px] pt-[6px] pb-[2px] rounded-t-[14px]"
4300
- [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]">
4301
4461
  <span
4302
4462
  class="text-sm font-medium"
4303
4463
  [style.color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-text)' : 'var(--pt-card-header-text)'">
@@ -4314,12 +4474,11 @@ class PlansSectionComponent {
4314
4474
 
4315
4475
  <!-- Card Body -->
4316
4476
  <div
4317
- class="flex-grow rounded-[14px] w-full p-2 pb-10"
4318
- [style.background-color]="plan.is_current_plan ? undefined : 'var(--pt-card-bg, #ffffff)'"
4319
- [style.border]="'1px solid var(--pt-card-border, var(--cp-section-content-border))'"
4320
- [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"
4321
- [class.rounded-t-none]="!plan.is_current_plan"
4322
- [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">
4323
4482
 
4324
4483
  <!-- Description -->
4325
4484
  @if (shouldShowPlanDescription()) {
@@ -4605,15 +4764,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
4605
4764
  <div class="flex gap-x-2 overflow-x-auto whitespace-nowrap px-6 py-4 -mx-4">
4606
4765
  @for (plan of plans; track plan.id; let idx = $index) {
4607
4766
  <div
4608
- class="flex flex-col shrink-0 w-[330px] overflow-hidden"
4609
- [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)'"
4610
4769
  [style.borderWidth]="'var(--pt-card-border-width, 1px)'"
4611
4770
  [style.borderStyle]="'solid'"
4612
- [style.borderColor]="'var(--pt-card-border)'"
4771
+ [style.borderColor]="'var(--pt-card-border, #e5e7eb)'"
4613
4772
  [style.background-color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-bg)' : 'var(--pt-card-header-bg)'">
4614
4773
  <!-- Card Header -->
4615
- <div class="flex items-center justify-between pl-4 pr-[5px] pt-[6px] pb-[2px] rounded-t-[14px]"
4616
- [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]">
4617
4775
  <span
4618
4776
  class="text-sm font-medium"
4619
4777
  [style.color]="plan.is_current_plan ? 'var(--pt-current-sub-card-header-text)' : 'var(--pt-card-header-text)'">
@@ -4630,12 +4788,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
4630
4788
 
4631
4789
  <!-- Card Body -->
4632
4790
  <div
4633
- class="flex-grow rounded-[14px] w-full p-2 pb-10"
4634
- [style.background-color]="plan.is_current_plan ? undefined : 'var(--pt-card-bg, #ffffff)'"
4635
- [style.border]="'1px solid var(--pt-card-border, var(--cp-section-content-border))'"
4636
- [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"
4637
- [class.rounded-t-none]="!plan.is_current_plan"
4638
- [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">
4639
4796
 
4640
4797
  <!-- Description -->
4641
4798
  @if (shouldShowPlanDescription()) {
@@ -4855,7 +5012,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
4855
5012
  </div>
4856
5013
  </div>
4857
5014
  }
4858
- `,
5015
+ `
4859
5016
  }]
4860
5017
  }], propDecorators: { plans: [{
4861
5018
  type: Input
@@ -4885,7 +5042,7 @@ class InvoicePreviewComponent {
4885
5042
  return date.toLocaleDateString(undefined, {
4886
5043
  month: 'short',
4887
5044
  day: 'numeric',
4888
- year: 'numeric',
5045
+ year: 'numeric'
4889
5046
  });
4890
5047
  }
4891
5048
  formatInvoicePrice(amount) {
@@ -4906,12 +5063,12 @@ class InvoicePreviewComponent {
4906
5063
  if (!invoice)
4907
5064
  return '$';
4908
5065
  const c = invoice.currency;
4909
- return c?.symbol ?? c?.Symbol ?? '$';
5066
+ return (c?.symbol ?? '$');
4910
5067
  }
4911
5068
  getInvoiceSummaryNumber(invoice, ...keys) {
4912
5069
  if (!invoice)
4913
5070
  return 0;
4914
- const s = invoice.summary ?? {};
5071
+ const s = (invoice.summary ?? {});
4915
5072
  for (const k of keys) {
4916
5073
  const v = s[k];
4917
5074
  if (v !== undefined && v !== null && v !== '') {
@@ -4924,51 +5081,45 @@ class InvoicePreviewComponent {
4924
5081
  getInvoiceLineItems(invoice) {
4925
5082
  if (!invoice)
4926
5083
  return [];
4927
- const lineItems = invoice.line_items ?? invoice.lineItems ?? invoice.items ?? invoice.invoice_lines ?? [];
4928
- const chargeItems = invoice.charge_items ?? invoice.chargeItems ?? [];
4929
- const usageItems = invoice.usage_items ?? invoice.usageItems ?? [];
4930
- 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 ?? [];
4931
5088
  const normalize = (item, itemType) => this.normalizeInvoiceLineItem(item, itemType);
4932
5089
  return [
4933
- ...(Array.isArray(lineItems)
4934
- ? lineItems.map((i) => normalize(i, 'line_item'))
4935
- : []),
4936
- ...(Array.isArray(chargeItems)
4937
- ? chargeItems.map((i) => normalize(i, 'charge_item'))
4938
- : []),
4939
- ...(Array.isArray(usageItems)
4940
- ? usageItems.map((i) => normalize(i, 'usage_item'))
4941
- : []),
4942
- ...(Array.isArray(creditItems)
4943
- ? creditItems.map((i) => normalize(i, 'credit_item'))
4944
- : []),
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'))
4945
5094
  ];
4946
5095
  }
4947
5096
  getInvoiceLineItemRangeLabel(raw) {
4948
- const tiers = raw?.usage_tiers?.tiers ?? raw?.tiers ?? [];
4949
- 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);
4950
5100
  if (!tier)
4951
5101
  return '';
4952
- const first = tier.first_unit ?? tier.firstUnit ?? 0;
4953
- const last = tier.last_unit ?? tier.lastUnit ?? -1;
4954
- 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)
4955
5105
  return `${first} and above`;
4956
5106
  return `${first} to ${last}`;
4957
5107
  }
4958
5108
  normalizeInvoiceLineItem(item, itemType) {
4959
5109
  const raw = item || {};
4960
- const id = raw.id ?? raw.Id ?? '';
4961
- const name = raw.name ?? raw.Name ?? '';
4962
- const description = (raw.description ?? raw.Description ?? '') || this.getInvoiceLineItemRangeLabel(raw);
4963
- const quantity = Number(raw.quantity ?? raw.Quantity ?? 0);
4964
- const totalAmountNum = this.toNumber(raw.total_amount ?? raw.totalAmount ?? raw.amount ?? raw.Amount ?? 0);
4965
- const amountStr = String(raw.amount ?? raw.Amount ?? raw.total_amount ?? raw.totalAmount ?? '0');
4966
- const totalAmountStr = String(raw.total_amount ?? raw.totalAmount ?? raw.amount ?? raw.Amount ?? '0');
4967
- const tiers = raw?.usage_tiers?.tiers ?? raw?.tiers ?? [];
4968
- const firstTier = Array.isArray(tiers) && tiers.length > 0 ? tiers[0] : null;
4969
- 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;
4970
5121
  const derivedUnitPrice = quantity > 0 && totalAmountNum > 0 ? totalAmountNum / quantity : undefined;
4971
- const rawUnitPrice = raw.unit_price ?? raw.unitPrice ?? tierUnitPrice;
5122
+ const rawUnitPrice = raw['unit_price'] ?? raw['unitPrice'] ?? tierUnitPrice;
4972
5123
  const rawUnitNum = rawUnitPrice !== undefined &&
4973
5124
  rawUnitPrice !== null &&
4974
5125
  String(rawUnitPrice).trim() !== ''
@@ -4983,7 +5134,7 @@ class InvoicePreviewComponent {
4983
5134
  unit_price: String(unitPriceNum),
4984
5135
  amount: amountStr,
4985
5136
  total_amount: totalAmountStr,
4986
- itemType,
5137
+ itemType
4987
5138
  };
4988
5139
  }
4989
5140
  buildTenantAddress(addr) {
@@ -4995,41 +5146,29 @@ class InvoicePreviewComponent {
4995
5146
  addr.city,
4996
5147
  addr.state,
4997
5148
  addr.postal_code,
4998
- addr.country,
5149
+ addr.country
4999
5150
  ].filter(Boolean);
5000
5151
  return parts.length ? parts.join(', ') : 'No Tenant address provided';
5001
5152
  }
5002
5153
  buildBilledToAddress(customer) {
5003
5154
  if (!customer)
5004
5155
  return '-';
5005
- const billing = customer?.billing_configuration?.billing_address;
5156
+ const billing = customer.billing_address;
5006
5157
  if (billing) {
5007
5158
  const parts = [
5008
- billing.line_1,
5009
- billing.line_2,
5159
+ billing.address_line_one,
5160
+ billing.address_line_two,
5010
5161
  billing.city,
5011
5162
  billing.state,
5012
- billing.postal_code,
5013
- billing.country,
5014
- ].filter(Boolean);
5015
- return parts.length ? parts.join(', ') : '-';
5016
- }
5017
- const addr = customer?.address;
5018
- if (addr) {
5019
- const parts = [
5020
- addr.line_1,
5021
- addr.line_2,
5022
- addr.city,
5023
- addr.state,
5024
- addr.postal_code,
5025
- addr.country,
5163
+ billing.zip_code,
5164
+ billing.country
5026
5165
  ].filter(Boolean);
5027
5166
  return parts.length ? parts.join(', ') : '-';
5028
5167
  }
5029
5168
  return '-';
5030
5169
  }
5031
5170
  escapeHtml(s) {
5032
- if (s == null || s === undefined)
5171
+ if (s === null || s === undefined)
5033
5172
  return '';
5034
5173
  return String(s)
5035
5174
  .replace(/&/g, '&amp;')
@@ -5072,9 +5211,9 @@ class InvoicePreviewComponent {
5072
5211
  const paid = fmt(this.getInvoiceSummaryNumber(inv, 'total_amount_paid', 'totalAmountPaid'));
5073
5212
  const due = fmt(this.getInvoiceSummaryNumber(inv, 'total_outstanding_amount', 'totalOutstandingAmount'));
5074
5213
  const rows = items
5075
- .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>`)
5076
5215
  .join('');
5077
- 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>`;
5078
5217
  }
5079
5218
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: InvoicePreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5080
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: `
@@ -5836,7 +5975,7 @@ class CustomerPortalComponent {
5836
5975
  const allPriceOptions = [
5837
5976
  ...(plan.price_options || []),
5838
5977
  ...(plan.entitlement_price_options || []),
5839
- ...(plan.credit_attachment_price_options || []),
5978
+ ...(plan.credit_attachment_price_options || [])
5840
5979
  ];
5841
5980
  allPriceOptions.forEach((po) => {
5842
5981
  if (po.price?.billing_interval) {
@@ -5851,11 +5990,13 @@ class CustomerPortalComponent {
5851
5990
  const custom = this.themeSignal() ?? MetrifoxService.getTheme()?.customerPortal;
5852
5991
  const theme = mergeCustomerPortalTheme(defaultCustomerPortalTheme, custom);
5853
5992
  const vars = MetrifoxService.customerPortalThemeToCssVars(theme);
5993
+ const gradientVars = MetrifoxService.getBackgroundImage(theme);
5854
5994
  return {
5855
5995
  ...vars,
5996
+ ...gradientVars,
5856
5997
  'font-family': 'var(--cp-font-family)',
5857
5998
  'background-color': 'var(--cp-bg)',
5858
- 'border-radius': 'var(--cp-radius)',
5999
+ 'border-radius': 'var(--cp-radius)'
5859
6000
  };
5860
6001
  });
5861
6002
  ngOnInit() {
@@ -5898,9 +6039,9 @@ class CustomerPortalComponent {
5898
6039
  this.error.set(err.message || 'Failed to load customer data');
5899
6040
  this.errorOccurred.emit({
5900
6041
  message: err.message || 'Failed to load customer data',
5901
- code: err.status?.toString(),
6042
+ code: err.status?.toString()
5902
6043
  });
5903
- },
6044
+ }
5904
6045
  });
5905
6046
  }
5906
6047
  loadAdditionalData() {
@@ -5911,7 +6052,7 @@ class CustomerPortalComponent {
5911
6052
  const subscriptionId = firstSubscription?.subscription?.id;
5912
6053
  const productKey = firstSubscription?.product_key;
5913
6054
  const requests = {
5914
- wallets: this.metrifoxService.getCustomerWallets(this.customerKey),
6055
+ wallets: this.metrifoxService.getCustomerWallets(this.customerKey)
5915
6056
  };
5916
6057
  if (subscriptionId) {
5917
6058
  requests.history = this.metrifoxService.getBillingHistory(subscriptionId);
@@ -5955,7 +6096,7 @@ class CustomerPortalComponent {
5955
6096
  this.isLoadingData = false;
5956
6097
  this.loading.set(false);
5957
6098
  this.dataLoaded.emit({ customerDetails: details });
5958
- },
6099
+ }
5959
6100
  });
5960
6101
  }
5961
6102
  loadDataForSubscription(sub) {
@@ -6006,7 +6147,7 @@ class CustomerPortalComponent {
6006
6147
  this.entitlementSummary.set([]);
6007
6148
  this.entitlementUsage.set([]);
6008
6149
  this.productPlans.set(null);
6009
- },
6150
+ }
6010
6151
  });
6011
6152
  }
6012
6153
  loadCreditAllocations(walletId, tab) {
@@ -6022,7 +6163,7 @@ class CustomerPortalComponent {
6022
6163
  error: () => {
6023
6164
  this.creditAllocations.set([]);
6024
6165
  this.allocationsLoading.set(false);
6025
- },
6166
+ }
6026
6167
  });
6027
6168
  }
6028
6169
  selectTab(index) {
@@ -6057,11 +6198,11 @@ class CustomerPortalComponent {
6057
6198
  if (invoiceId) {
6058
6199
  this.metrifoxService.getInvoiceDetails(invoiceId).pipe(takeUntil(this.destroy$)).subscribe({
6059
6200
  next: (data) => {
6060
- const inv = data?.data ?? data;
6201
+ const inv = (data?.data ?? data);
6061
6202
  this.invoiceDetails.set(inv);
6062
6203
  this.invoiceDetailsLoading.set(false);
6063
6204
  },
6064
- error: () => this.invoiceDetailsLoading.set(false),
6205
+ error: () => this.invoiceDetailsLoading.set(false)
6065
6206
  });
6066
6207
  }
6067
6208
  else {
@@ -6246,7 +6387,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
6246
6387
  PaymentSectionComponent,
6247
6388
  BillingHistorySectionComponent,
6248
6389
  PlansSectionComponent,
6249
- InvoicePreviewComponent,
6390
+ InvoicePreviewComponent
6250
6391
  ], changeDetection: ChangeDetectionStrategy.OnPush, template: `
6251
6392
  <div class="font-sans antialiased" [ngStyle]="cssVars()">
6252
6393
  <!-- Error State -->
@@ -6509,6 +6650,7 @@ var ResetIntervals;
6509
6650
  ResetIntervals["DAILY"] = "daily";
6510
6651
  ResetIntervals["BILLING_PERIOD"] = "billing_period";
6511
6652
  ResetIntervals["NEVER"] = "never";
6653
+ ResetIntervals["NONE"] = "none";
6512
6654
  })(ResetIntervals || (ResetIntervals = {}));
6513
6655
  /**
6514
6656
  * Enforcement types
@@ -6536,6 +6678,7 @@ var BillingTimingTypes;
6536
6678
  (function (BillingTimingTypes) {
6537
6679
  BillingTimingTypes["IN_ADVANCE"] = "in_advance";
6538
6680
  BillingTimingTypes["IN_ARREARS"] = "in_arrears";
6681
+ BillingTimingTypes["PAY_AS_YOU_GO"] = "pay_as_you_go";
6539
6682
  })(BillingTimingTypes || (BillingTimingTypes = {}));
6540
6683
  /**
6541
6684
  * Aggregation methods
@@ -6586,56 +6729,75 @@ var LocalizationSelection;
6586
6729
  LocalizationSelection["SMART_PRE_FILL"] = "smart_pre_fill";
6587
6730
  })(LocalizationSelection || (LocalizationSelection = {}));
6588
6731
 
6589
- // Default theme matching React SDK
6590
6732
  const defaultPricingTableTheme = {
6591
6733
  plans: {
6592
6734
  currentPlanCard: {
6593
- header: { background: '#E4E4E7', textColor: '#111827' },
6594
- gradientColor: '#E4E4E7',
6735
+ header: {
6736
+ background: '#e5e7eb',
6737
+ textColor: '#111827'
6738
+ },
6739
+ gradientColor: '#e5e7eb'
6595
6740
  },
6596
6741
  planCards: {
6597
6742
  background: '#ffffff',
6598
- border: { color: '#E4E4E7', width: '1px', radius: '8px' },
6599
- header: { background: '#E4E4E7', textColor: '#111827' },
6600
- 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
+ },
6601
6756
  price: {
6602
6757
  amountColor: '#111827',
6603
- primaryTextColor: '#71717A',
6604
- secondaryTextColor: '#A1A1AA',
6758
+ primaryTextColor: '#6b7280',
6759
+ secondaryTextColor: '#9ca3af',
6605
6760
  background: 'transparent',
6606
- borderColor: 'transparent',
6607
- },
6761
+ borderColor: 'transparent'
6762
+ }
6763
+ },
6764
+ planFeatures: {
6765
+ textColor: '#374151',
6766
+ iconColor: '#0BB02F'
6608
6767
  },
6609
- planFeatures: { textColor: '#3F3F46', iconColor: '#0BB02F' },
6610
6768
  planButton: {
6611
6769
  background: '#3D3D3D',
6612
6770
  textColor: '#ffffff',
6613
6771
  secondaryBackground: '#E4E4E7',
6614
6772
  secondaryTextColor: '#3F3F46',
6615
- textButtonColor: '#2563eb',
6773
+ textButtonColor: '#2563eb'
6616
6774
  },
6617
6775
  planToggle: {
6618
- background: '#E4E4E7',
6776
+ background: '#e5e7eb',
6619
6777
  activeBackground: '#1f2937',
6620
6778
  activeText: '#ffffff',
6621
- inactiveText: '#71717A',
6779
+ inactiveText: '#6b7280'
6622
6780
  },
6623
- planTags: { freeTrialBackground: '#dbeafe', freeTrialText: '#1e40af' },
6781
+ planTags: {
6782
+ freeTrialBackground: '#dbeafe',
6783
+ freeTrialText: '#1e40af'
6784
+ }
6624
6785
  },
6625
6786
  tabs: {
6626
- inactiveText: '#A1A1AA',
6787
+ inactiveText: '#9ca3af',
6627
6788
  activeText: '#2563eb',
6628
6789
  indicator: '#2563eb',
6629
- borderColor: '#A1A1AA',
6790
+ borderColor: '#9ca3af'
6630
6791
  },
6631
6792
  checkoutBar: {
6632
- background: '#FAFAFA',
6633
- borderColor: '#E4E4E7',
6793
+ background: '#f9fafb',
6794
+ borderColor: '#e5e7eb',
6634
6795
  textColor: '#3F3F46',
6635
6796
  buttonBackground: '#2563eb',
6636
- buttonTextColor: '#ffffff',
6637
- },
6797
+ buttonTextColor: '#ffffff'
6798
+ }
6638
6799
  };
6800
+
6639
6801
  function mergePricingTableTheme(defaultTheme, custom) {
6640
6802
  if (!custom || typeof custom !== 'object')
6641
6803
  return defaultTheme;
@@ -6659,12 +6821,12 @@ function mergePricingTableTheme(defaultTheme, custom) {
6659
6821
  }
6660
6822
  // SVG Icons
6661
6823
  const ICONS = {
6662
- 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>`,
6663
- 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>`,
6664
- 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>`,
6665
- 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>`,
6666
- 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>`,
6667
- 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>'
6668
6830
  };
6669
6831
  /**
6670
6832
  * Pricing Table Component
@@ -6689,15 +6851,24 @@ class PricingTableComponent {
6689
6851
  checkoutUsername;
6690
6852
  metrifoxService = inject(MetrifoxService);
6691
6853
  sanitizer = inject(DomSanitizer);
6854
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
6692
6855
  constructor() { }
6693
6856
  /** Product key to load pricing for */
6694
6857
  productKey;
6695
6858
  /** Show only plans (hide single purchases) */
6696
- plansOnly = false;
6859
+ plansOnlySignal = signal(false);
6860
+ set plansOnly(value) { this.plansOnlySignal.set(value); }
6697
6861
  /** Show only single purchases (hide plans) */
6698
- singlePurchasesOnly = false;
6862
+ singlePurchasesOnlySignal = signal(false);
6863
+ set singlePurchasesOnly(value) { this.singlePurchasesOnlySignal.set(value); }
6699
6864
  /** Show tab header when both plans and purchases exist */
6700
- 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
+ }
6701
6872
  /** Emitted when a plan is selected */
6702
6873
  planSelected = new EventEmitter();
6703
6874
  /** Emitted when a single purchase is selected */
@@ -6715,8 +6886,8 @@ class PricingTableComponent {
6715
6886
  // Computed
6716
6887
  plans = computed(() => this.product()?.plans || []);
6717
6888
  singlePurchases = computed(() => this.product()?.single_purchases || []);
6718
- showPlans = computed(() => this.plansOnly || (!this.plansOnly && !this.singlePurchasesOnly));
6719
- 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()));
6720
6891
  hasBothTypes = computed(() => this.plans().length > 0 && this.singlePurchases().length > 0);
6721
6892
  tabOptions = computed(() => {
6722
6893
  const options = [];
@@ -6750,12 +6921,12 @@ class PricingTableComponent {
6750
6921
  return purchases.filter((p) => p.published_version?.name?.toLowerCase().includes(term));
6751
6922
  });
6752
6923
  cssVars = computed(() => {
6753
- const userTheme = MetrifoxService.getTheme()?.pricingTable;
6754
- const theme = mergePricingTableTheme(defaultPricingTableTheme, userTheme);
6924
+ const custom = this.themeSignal() ?? MetrifoxService.getTheme()?.pricingTable;
6925
+ const theme = mergePricingTableTheme(defaultPricingTableTheme, custom);
6755
6926
  return {
6756
6927
  ...MetrifoxService.pricingTableThemeToCssVars(theme),
6757
6928
  ...MetrifoxService.getBackgroundImage(theme),
6758
- 'font-family': 'var(--pt-font-family, var(--cp-font-family, inherit))',
6929
+ 'font-family': 'var(--pt-font-family, var(--cp-font-family, inherit))'
6759
6930
  };
6760
6931
  });
6761
6932
  ngOnInit() {
@@ -6793,9 +6964,9 @@ class PricingTableComponent {
6793
6964
  this.error.set(err.message || 'Failed to load pricing');
6794
6965
  this.errorOccurred.emit({
6795
6966
  message: err.message || 'Failed to load pricing',
6796
- code: err.status?.toString(),
6967
+ code: err.status?.toString()
6797
6968
  });
6798
- },
6969
+ }
6799
6970
  });
6800
6971
  }
6801
6972
  /**
@@ -6818,7 +6989,7 @@ class PricingTableComponent {
6818
6989
  this.planSelected.emit({
6819
6990
  plan: plan.published_version,
6820
6991
  interval: this.selectedInterval(),
6821
- checkoutUrl,
6992
+ checkoutUrl
6822
6993
  });
6823
6994
  // Open checkout in new tab
6824
6995
  window.open(checkoutUrl, '_blank');
@@ -6830,7 +7001,7 @@ class PricingTableComponent {
6830
7001
  const checkoutUrl = this.metrifoxService.buildCheckoutUrl(this.checkoutUsername, purchase.offering_key);
6831
7002
  this.purchaseSelected.emit({
6832
7003
  purchase: purchase.published_version,
6833
- checkoutUrl,
7004
+ checkoutUrl
6834
7005
  });
6835
7006
  // Open checkout in new tab
6836
7007
  window.open(checkoutUrl, '_blank');
@@ -6891,7 +7062,7 @@ class PricingTableComponent {
6891
7062
  EUR: '€',
6892
7063
  GBP: '£',
6893
7064
  JPY: '¥',
6894
- NGN: '₦',
7065
+ NGN: '₦'
6895
7066
  };
6896
7067
  return symbols[currency] || currency;
6897
7068
  }
@@ -6934,7 +7105,7 @@ class PricingTableComponent {
6934
7105
  monthly: 'Monthly',
6935
7106
  yearly: 'Yearly',
6936
7107
  weekly: 'Weekly',
6937
- daily: 'Daily',
7108
+ daily: 'Daily'
6938
7109
  };
6939
7110
  return labels[interval] || interval;
6940
7111
  }
@@ -7015,7 +7186,7 @@ class PricingTableComponent {
7015
7186
  price: priceOption.price.price,
7016
7187
  currency: priceOption.price.currency,
7017
7188
  quantity,
7018
- offering_key: purchase.offering_key,
7189
+ offering_key: purchase.offering_key
7019
7190
  };
7020
7191
  this.cartItems.update((items) => [...items, item]);
7021
7192
  }
@@ -7040,7 +7211,7 @@ class PricingTableComponent {
7040
7211
  checkoutWindow?.postMessage({
7041
7212
  v: 1,
7042
7213
  type: 'INIT_CART',
7043
- payload: dataToSend,
7214
+ payload: dataToSend
7044
7215
  }, '*');
7045
7216
  break;
7046
7217
  case 'ACK':
@@ -7055,7 +7226,7 @@ class PricingTableComponent {
7055
7226
  }, 5000);
7056
7227
  }
7057
7228
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: PricingTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7058
- 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: `
7059
7230
  <div class="font-sans antialiased" [ngStyle]="cssVars()">
7060
7231
  <!-- Loading State -->
7061
7232
  @if (loading()) {
@@ -7087,7 +7258,7 @@ class PricingTableComponent {
7087
7258
  <div class="flex justify-center">
7088
7259
  <div class="w-full max-w-[1089px] bg-transparent h-full rounded-2xl md:px-6 py-5">
7089
7260
  <!-- Tab Header (Listing Tabs) -->
7090
- @if (showTabHeader && hasBothTypes()) {
7261
+ @if (showTabHeaderSignal()) {
7091
7262
  <div class="w-full flex justify-center border-b border-[var(--pt-tabs-border)] mb-6">
7092
7263
  @for (tab of tabOptions(); track tab.value) {
7093
7264
  <div
@@ -7109,31 +7280,36 @@ class PricingTableComponent {
7109
7280
  <!-- Plans View -->
7110
7281
  @if (showPlans() && selectedTab() === 'plan') {
7111
7282
  <!-- Interval Toggle (Plan Tabs) -->
7112
- @if (intervals().length > 1) {
7113
- <div class="flex items-center mb-4 justify-center">
7114
- <div class="rounded-2xl p-1 flex bg-[var(--pt-interval-bg)]">
7115
- @for (interval of intervals(); track interval) {
7116
- <div
7117
- class="py-1 px-3 rounded-xl cursor-pointer transition-colors"
7118
- [class.bg-[var(--pt-interval-active-bg)]]="selectedInterval() === interval"
7119
- (click)="selectInterval(interval)">
7120
- <span
7121
- class="text-sm"
7122
- [class.text-[var(--pt-interval-active-text)]]="selectedInterval() === interval"
7123
- [class.text-[var(--pt-interval-inactive-text)]]="selectedInterval() !== interval">
7124
- {{ formatInterval(interval) }}
7125
- </span>
7126
- </div>
7127
- }
7128
- </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
+ }
7129
7301
  </div>
7130
- }
7302
+ </div>
7131
7303
 
7132
7304
  <!-- Plan Cards -->
7133
7305
  <div class="w-full flex gap-x-4 px-4 justify-start overflow-x-auto flex-nowrap">
7134
7306
  @for (plan of plans(); track plan.id) {
7135
7307
  <div
7136
- 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)'"
7137
7313
  [class.bg-[var(--pt-current-sub-card-header-bg)]]="plan.published_version.is_current_plan"
7138
7314
  [class.bg-[var(--pt-card-header-bg)]]="!plan.published_version.is_current_plan">
7139
7315
  <!-- Card Header -->
@@ -7157,7 +7333,7 @@ class PricingTableComponent {
7157
7333
  [class.bg-gradient-to-b]="plan.published_version.is_current_plan"
7158
7334
  [class.from-[var(--pt-card-gradient)]]="plan.published_version.is_current_plan"
7159
7335
  [class.to-[var(--pt-card-bg)]]="plan.published_version.is_current_plan">
7160
-
7336
+
7161
7337
  <!-- Description -->
7162
7338
  @if (plan.published_version.description) {
7163
7339
  <div class="h-[51px] mt-1 px-2">
@@ -7200,7 +7376,7 @@ class PricingTableComponent {
7200
7376
  {{ getButtonText(plan.published_version) }}
7201
7377
  </button>
7202
7378
 
7203
- <!-- Features/Entitlements -->
7379
+ <!-- Entitlements -->
7204
7380
  @if (plan.published_version.entitlements?.length || plan.published_version.credit_attachments?.length) {
7205
7381
  <div class="px-2 mt-4">
7206
7382
  <p class="text-sm font-medium text-[var(--pt-feature-text)] mb-3">
@@ -7263,7 +7439,12 @@ class PricingTableComponent {
7263
7439
  class="grid gap-4 px-4 lg:grid-cols-3 md:grid-cols-2 grid-cols-1"
7264
7440
  [class.pb-[72px]]="cartItems().length > 0">
7265
7441
  @for (purchase of filteredSinglePurchases(); track purchase.id) {
7266
- <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
+ >
7267
7448
  <!-- Card Header -->
7268
7449
  <div class="px-4 pt-2 pb-[2px]">
7269
7450
  <span class="text-sm font-medium text-[var(--pt-card-header-text)]">
@@ -7397,7 +7578,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7397
7578
  <div class="flex justify-center">
7398
7579
  <div class="w-full max-w-[1089px] bg-transparent h-full rounded-2xl md:px-6 py-5">
7399
7580
  <!-- Tab Header (Listing Tabs) -->
7400
- @if (showTabHeader && hasBothTypes()) {
7581
+ @if (showTabHeaderSignal()) {
7401
7582
  <div class="w-full flex justify-center border-b border-[var(--pt-tabs-border)] mb-6">
7402
7583
  @for (tab of tabOptions(); track tab.value) {
7403
7584
  <div
@@ -7419,31 +7600,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7419
7600
  <!-- Plans View -->
7420
7601
  @if (showPlans() && selectedTab() === 'plan') {
7421
7602
  <!-- Interval Toggle (Plan Tabs) -->
7422
- @if (intervals().length > 1) {
7423
- <div class="flex items-center mb-4 justify-center">
7424
- <div class="rounded-2xl p-1 flex bg-[var(--pt-interval-bg)]">
7425
- @for (interval of intervals(); track interval) {
7426
- <div
7427
- class="py-1 px-3 rounded-xl cursor-pointer transition-colors"
7428
- [class.bg-[var(--pt-interval-active-bg)]]="selectedInterval() === interval"
7429
- (click)="selectInterval(interval)">
7430
- <span
7431
- class="text-sm"
7432
- [class.text-[var(--pt-interval-active-text)]]="selectedInterval() === interval"
7433
- [class.text-[var(--pt-interval-inactive-text)]]="selectedInterval() !== interval">
7434
- {{ formatInterval(interval) }}
7435
- </span>
7436
- </div>
7437
- }
7438
- </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
+ }
7439
7621
  </div>
7440
- }
7622
+ </div>
7441
7623
 
7442
7624
  <!-- Plan Cards -->
7443
7625
  <div class="w-full flex gap-x-4 px-4 justify-start overflow-x-auto flex-nowrap">
7444
7626
  @for (plan of plans(); track plan.id) {
7445
7627
  <div
7446
- 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)'"
7447
7633
  [class.bg-[var(--pt-current-sub-card-header-bg)]]="plan.published_version.is_current_plan"
7448
7634
  [class.bg-[var(--pt-card-header-bg)]]="!plan.published_version.is_current_plan">
7449
7635
  <!-- Card Header -->
@@ -7467,7 +7653,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7467
7653
  [class.bg-gradient-to-b]="plan.published_version.is_current_plan"
7468
7654
  [class.from-[var(--pt-card-gradient)]]="plan.published_version.is_current_plan"
7469
7655
  [class.to-[var(--pt-card-bg)]]="plan.published_version.is_current_plan">
7470
-
7656
+
7471
7657
  <!-- Description -->
7472
7658
  @if (plan.published_version.description) {
7473
7659
  <div class="h-[51px] mt-1 px-2">
@@ -7510,7 +7696,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7510
7696
  {{ getButtonText(plan.published_version) }}
7511
7697
  </button>
7512
7698
 
7513
- <!-- Features/Entitlements -->
7699
+ <!-- Entitlements -->
7514
7700
  @if (plan.published_version.entitlements?.length || plan.published_version.credit_attachments?.length) {
7515
7701
  <div class="px-2 mt-4">
7516
7702
  <p class="text-sm font-medium text-[var(--pt-feature-text)] mb-3">
@@ -7573,7 +7759,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7573
7759
  class="grid gap-4 px-4 lg:grid-cols-3 md:grid-cols-2 grid-cols-1"
7574
7760
  [class.pb-[72px]]="cartItems().length > 0">
7575
7761
  @for (purchase of filteredSinglePurchases(); track purchase.id) {
7576
- <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
+ >
7577
7768
  <!-- Card Header -->
7578
7769
  <div class="px-4 pt-2 pb-[2px]">
7579
7770
  <span class="text-sm font-medium text-[var(--pt-card-header-text)]">
@@ -7684,6 +7875,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7684
7875
  type: Input
7685
7876
  }], showTabHeader: [{
7686
7877
  type: Input
7878
+ }], theme: [{
7879
+ type: Input
7687
7880
  }], planSelected: [{
7688
7881
  type: Output
7689
7882
  }], purchaseSelected: [{
@@ -7721,8 +7914,8 @@ class MetrifoxModule {
7721
7914
  ngModule: MetrifoxModule,
7722
7915
  providers: [
7723
7916
  provideHttpClient(withInterceptorsFromDi()),
7724
- MetrifoxService,
7725
- ],
7917
+ MetrifoxService
7918
+ ]
7726
7919
  };
7727
7920
  }
7728
7921
  /**
@@ -7731,7 +7924,7 @@ class MetrifoxModule {
7731
7924
  static forChild() {
7732
7925
  return {
7733
7926
  ngModule: MetrifoxModule,
7734
- providers: [],
7927
+ providers: []
7735
7928
  };
7736
7929
  }
7737
7930
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: MetrifoxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -7749,12 +7942,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
7749
7942
  imports: [
7750
7943
  CommonModule,
7751
7944
  CustomerPortalComponent,
7752
- PricingTableComponent,
7945
+ PricingTableComponent
7753
7946
  ],
7754
7947
  exports: [
7755
7948
  CustomerPortalComponent,
7756
- PricingTableComponent,
7757
- ],
7949
+ PricingTableComponent
7950
+ ]
7758
7951
  }]
7759
7952
  }] });
7760
7953
  /**
@@ -7777,7 +7970,7 @@ function provideMetrifox(config) {
7777
7970
  }
7778
7971
  return [
7779
7972
  provideHttpClient(),
7780
- MetrifoxService,
7973
+ MetrifoxService
7781
7974
  ];
7782
7975
  }
7783
7976