@sneat/components 0.27.30 → 0.27.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/esm2022/index.js CHANGED
@@ -12,4 +12,6 @@ export * from './lib/save-event';
12
12
  export * from './lib/date-input/date-input.component';
13
13
  export * from './lib/user-country/user-country.component';
14
14
  export * from './lib/card-list/sneat-card-list.component';
15
+ export * from './lib/subscription-recovery/subscription-recovery.component';
16
+ export * from './lib/subscription-settings/subscription-settings.component';
15
17
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/components/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qCAAqC,CAAC;AACpD,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC","sourcesContent":["export * from './lib/app-version';\nexport * from './lib/pipes';\nexport * from './lib/virtual-slider/virtual-slider';\nexport * from './lib/card-list';\nexport * from './lib/error-card';\nexport * from './lib/country-selector';\nexport * from './lib/filter-item';\nexport * from './lib/copyright';\nexport * from './lib/dialog-header';\nexport * from './lib/country-input';\nexport * from './lib/save-event';\nexport * from './lib/date-input/date-input.component';\nexport * from './lib/user-country/user-country.component';\nexport * from './lib/card-list/sneat-card-list.component';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/components/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qCAAqC,CAAC;AACpD,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,6DAA6D,CAAC;AAC5E,cAAc,6DAA6D,CAAC","sourcesContent":["export * from './lib/app-version';\nexport * from './lib/pipes';\nexport * from './lib/virtual-slider/virtual-slider';\nexport * from './lib/card-list';\nexport * from './lib/error-card';\nexport * from './lib/country-selector';\nexport * from './lib/filter-item';\nexport * from './lib/copyright';\nexport * from './lib/dialog-header';\nexport * from './lib/country-input';\nexport * from './lib/save-event';\nexport * from './lib/date-input/date-input.component';\nexport * from './lib/user-country/user-country.component';\nexport * from './lib/card-list/sneat-card-list.component';\nexport * from './lib/subscription-recovery/subscription-recovery.component';\nexport * from './lib/subscription-settings/subscription-settings.component';\n"]}
@@ -64,32 +64,34 @@ export class CountriesLoaderService {
64
64
  * Automatically loads country data if not yet loaded.
65
65
  */
66
66
  async getCountries() {
67
- await this.loadCountries();
68
- return Object.values(this.countriesData.countriesByID);
67
+ return Object.values((await this.loadedCountries()).countriesByID);
69
68
  }
70
69
  /**
71
70
  * Gets countries by ID lookup.
72
71
  * Automatically loads country data if not yet loaded.
73
72
  */
74
73
  async getCountriesByID() {
75
- await this.loadCountries();
76
- return this.countriesData.countriesByID;
74
+ return (await this.loadedCountries()).countriesByID;
77
75
  }
78
76
  /**
79
77
  * Gets a specific country by ID.
80
78
  * Automatically loads country data if not yet loaded.
81
79
  */
82
80
  async getCountryByID(id) {
83
- await this.loadCountries();
84
- return this.countriesData.countriesByID[id];
81
+ return (await this.loadedCountries()).countriesByID[id];
85
82
  }
86
83
  /**
87
84
  * Gets the unknown country constant.
88
85
  * Automatically loads country data if not yet loaded.
89
86
  */
90
87
  async getUnknownCountry() {
88
+ return (await this.loadedCountries()).unknownCountry;
89
+ }
90
+ async loadedCountries() {
91
91
  await this.loadCountries();
92
- return this.countriesData.unknownCountry;
92
+ if (!this.countriesData)
93
+ throw new Error('Country data was cleared during loading');
94
+ return this.countriesData;
93
95
  }
94
96
  /**
95
97
  * Gets countries filtered by geo region.
@@ -1 +1 @@
1
- {"version":3,"file":"countries-loader.service.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/country-selector/countries-loader.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { inject, Injectable, signal } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { firstValueFrom } from 'rxjs';\nimport { GeoRegion, ICountry } from './countries';\n\ninterface CountriesData {\n countriesByID: Record<string, ICountry>;\n unknownCountry: ICountry;\n}\n\n/**\n * Service to lazy load country data.\n * This reduces the initial bundle size by loading country data on-demand.\n */\n@Injectable({ providedIn: 'root' })\nexport class CountriesLoaderService {\n private readonly http = inject(HttpClient);\n private countriesData?: CountriesData;\n private loadPromise?: Promise<void>;\n\n /**\n * True when the last load attempt failed (countries.json couldn't be\n * fetched/parsed). Consumers can read this to show an error in the UI. Reset\n * to false on a successful (re)load. See `reload()` to retry.\n */\n readonly loadFailed = signal(false);\n\n /**\n * Loads country data from JSON file.\n * Subsequent calls return the same promise (singleton pattern).\n */\n private async loadCountries(): Promise<void> {\n if (this.countriesData) {\n return; // Already loaded\n }\n\n if (!this.loadPromise) {\n this.loadPromise = (async () => {\n try {\n this.countriesData = await firstValueFrom(\n this.http.get<CountriesData>('assets/data/countries.json'),\n );\n this.loadFailed.set(false);\n } catch (error) {\n console.error('Failed to load countries:', error);\n this.loadFailed.set(true);\n // Set to empty to avoid repeated failures\n this.countriesData = {\n countriesByID: {},\n unknownCountry: {\n id: '--',\n id3: '---',\n title: 'Unknown',\n geoRegions: [],\n emoji: '🏳️',\n },\n };\n }\n })();\n }\n\n return this.loadPromise;\n }\n\n /**\n * Discards the cached data and re-attempts the load — used to retry after a\n * failure (`loadFailed()` is true). Resolves once the reload settles.\n */\n async reload(): Promise<void> {\n this.countriesData = undefined;\n this.loadPromise = undefined;\n await this.loadCountries();\n }\n\n /**\n * Gets all countries as an array.\n * Automatically loads country data if not yet loaded.\n */\n async getCountries(): Promise<readonly ICountry[]> {\n await this.loadCountries();\n return Object.values(this.countriesData!.countriesByID);\n }\n\n /**\n * Gets countries by ID lookup.\n * Automatically loads country data if not yet loaded.\n */\n async getCountriesByID(): Promise<Record<string, ICountry>> {\n await this.loadCountries();\n return this.countriesData!.countriesByID;\n }\n\n /**\n * Gets a specific country by ID.\n * Automatically loads country data if not yet loaded.\n */\n async getCountryByID(id: string): Promise<ICountry | undefined> {\n await this.loadCountries();\n return this.countriesData!.countriesByID[id];\n }\n\n /**\n * Gets the unknown country constant.\n * Automatically loads country data if not yet loaded.\n */\n async getUnknownCountry(): Promise<ICountry> {\n await this.loadCountries();\n return this.countriesData!.unknownCountry;\n }\n\n /**\n * Gets countries filtered by geo region.\n * Automatically loads country data if not yet loaded.\n */\n async getCountriesByRegion(region: GeoRegion): Promise<readonly ICountry[]> {\n const countries = await this.getCountries();\n return countries.filter((c) => c.geoRegions.includes(region));\n }\n}\n"]}
1
+ {"version":3,"file":"countries-loader.service.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/country-selector/countries-loader.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { inject, Injectable, signal } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { firstValueFrom } from 'rxjs';\nimport { GeoRegion, ICountry } from './countries';\n\ninterface CountriesData {\n countriesByID: Record<string, ICountry>;\n unknownCountry: ICountry;\n}\n\n/**\n * Service to lazy load country data.\n * This reduces the initial bundle size by loading country data on-demand.\n */\n@Injectable({ providedIn: 'root' })\nexport class CountriesLoaderService {\n private readonly http = inject(HttpClient);\n private countriesData?: CountriesData;\n private loadPromise?: Promise<void>;\n\n /**\n * True when the last load attempt failed (countries.json couldn't be\n * fetched/parsed). Consumers can read this to show an error in the UI. Reset\n * to false on a successful (re)load. See `reload()` to retry.\n */\n readonly loadFailed = signal(false);\n\n /**\n * Loads country data from JSON file.\n * Subsequent calls return the same promise (singleton pattern).\n */\n private async loadCountries(): Promise<void> {\n if (this.countriesData) {\n return; // Already loaded\n }\n\n if (!this.loadPromise) {\n this.loadPromise = (async () => {\n try {\n this.countriesData = await firstValueFrom(\n this.http.get<CountriesData>('assets/data/countries.json'),\n );\n this.loadFailed.set(false);\n } catch (error) {\n console.error('Failed to load countries:', error);\n this.loadFailed.set(true);\n // Set to empty to avoid repeated failures\n this.countriesData = {\n countriesByID: {},\n unknownCountry: {\n id: '--',\n id3: '---',\n title: 'Unknown',\n geoRegions: [],\n emoji: '🏳️',\n },\n };\n }\n })();\n }\n\n return this.loadPromise;\n }\n\n /**\n * Discards the cached data and re-attempts the load — used to retry after a\n * failure (`loadFailed()` is true). Resolves once the reload settles.\n */\n async reload(): Promise<void> {\n this.countriesData = undefined;\n this.loadPromise = undefined;\n await this.loadCountries();\n }\n\n /**\n * Gets all countries as an array.\n * Automatically loads country data if not yet loaded.\n */\n async getCountries(): Promise<readonly ICountry[]> {\n return Object.values((await this.loadedCountries()).countriesByID);\n }\n\n /**\n * Gets countries by ID lookup.\n * Automatically loads country data if not yet loaded.\n */\n async getCountriesByID(): Promise<Record<string, ICountry>> {\n return (await this.loadedCountries()).countriesByID;\n }\n\n /**\n * Gets a specific country by ID.\n * Automatically loads country data if not yet loaded.\n */\n async getCountryByID(id: string): Promise<ICountry | undefined> {\n return (await this.loadedCountries()).countriesByID[id];\n }\n\n /**\n * Gets the unknown country constant.\n * Automatically loads country data if not yet loaded.\n */\n async getUnknownCountry(): Promise<ICountry> {\n return (await this.loadedCountries()).unknownCountry;\n }\n\n private async loadedCountries(): Promise<CountriesData> {\n await this.loadCountries();\n if (!this.countriesData)\n throw new Error('Country data was cleared during loading');\n return this.countriesData;\n }\n\n /**\n * Gets countries filtered by geo region.\n * Automatically loads country data if not yet loaded.\n */\n async getCountriesByRegion(region: GeoRegion): Promise<readonly ICountry[]> {\n const countries = await this.getCountries();\n return countries.filter((c) => c.geoRegions.includes(region));\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Component, computed, EventEmitter, inject, Input, Output, signal, ChangeDetectionStrategy, input } from '@angular/core';
1
+ import { Component, computed, EventEmitter, inject, Input, Output, signal, ChangeDetectionStrategy, input, } from '@angular/core';
2
2
  import { FormsModule } from '@angular/forms';
3
3
  import { IonButton, IonItem, IonLabel, IonSegment, IonSegmentButton, } from '@ionic/angular';
4
4
  import { SelectFromListComponent } from '@sneat/ui';
@@ -48,8 +48,9 @@ export class CountrySelectorComponent {
48
48
  (c.geoRegions.includes('North America') ||
49
49
  c.geoRegions.includes('South America'))) ||
50
50
  c.geoRegions.includes(this.geoRegion()));
51
- if (this.canBeUnknown() && this.unknownCountry()) {
52
- countriesToShow = [...countriesToShow, this.unknownCountry()];
51
+ const unknownCountry = this.unknownCountry();
52
+ if (this.canBeUnknown() && unknownCountry) {
53
+ countriesToShow = [...countriesToShow, unknownCountry];
53
54
  }
54
55
  return countriesToShow;
55
56
  }, /* @ts-ignore */
@@ -1 +1 @@
1
- {"version":3,"file":"country-selector.component.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/country-selector/country-selector.component.ts","../../../../../../libs/components/src/lib/country-selector/country-selector.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n computed,\n EventEmitter,\n inject,\n Input,\n OnChanges,\n OnInit,\n Output,\n signal,\n SimpleChanges,\n ChangeDetectionStrategy,\n input\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n IonButton,\n IonItem,\n IonLabel,\n IonSegment,\n IonSegmentButton,\n} from '@ionic/angular';\nimport { ISelectItem, SelectFromListComponent } from '@sneat/ui';\nimport { GeoRegion, ICountry } from './countries';\nimport { CountriesLoaderService } from './countries-loader.service';\n\n@Component({\n selector: 'sneat-country-selector',\n templateUrl: './country-selector.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n FormsModule,\n SelectFromListComponent,\n IonSegment,\n IonSegmentButton,\n IonItem,\n IonLabel,\n IonButton,\n ],\n})\nexport class CountrySelectorComponent implements OnInit, OnChanges {\n private readonly countriesLoader = inject(CountriesLoaderService);\n\n protected readonly geoRegions: readonly {\n readonly id: string;\n title?: string;\n }[] = [\n { id: 'Europe' },\n { id: 'Asia' },\n { id: 'Americas' },\n { id: 'Africa' },\n ];\n\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input({ required: true }) countryID?: string;\n\n readonly defaultCountryID = input<string>();\n\n readonly readonly = input(false);\n readonly disabled = input(false);\n readonly label = input('search');\n readonly canBeUnknown = input(false);\n\n @Output() readonly countryIDChange = new EventEmitter<string>();\n\n protected readonly filter = signal<string>('');\n protected readonly geoRegion = signal<GeoRegion | 'All' | 'Americas'>('All');\n protected readonly allCountries = signal<readonly ICountry[]>([]);\n protected readonly unknownCountry = signal<ICountry | undefined>(undefined);\n\n // True when the country list failed to load — surfaced in the UI with a Retry.\n protected readonly loadFailed = this.countriesLoader.loadFailed;\n\n protected readonly countries = computed<readonly ISelectItem[]>(() => {\n const allCountries = this.allCountries();\n if (allCountries.length === 0) {\n return []; // Data not loaded yet\n }\n\n const filter = this.filter();\n let countriesToShow: readonly ISelectItem[] = filter\n ? allCountries\n : allCountries.filter(\n (c) =>\n this.geoRegion() === 'All' ||\n (this.geoRegion() === 'Americas' &&\n (c.geoRegions.includes('North America') ||\n c.geoRegions.includes('South America'))) ||\n c.geoRegions.includes(this.geoRegion() as GeoRegion),\n );\n if (this.canBeUnknown() && this.unknownCountry()) {\n countriesToShow = [...countriesToShow, this.unknownCountry()!];\n }\n return countriesToShow;\n });\n\n ngOnInit(): void {\n this.load();\n }\n\n private load(): void {\n this.countriesLoader.getCountries().then((countries) => {\n this.allCountries.set(countries);\n });\n this.countriesLoader.getUnknownCountry().then((unknown) => {\n this.unknownCountry.set(unknown);\n });\n }\n\n // Retry loading the country list after a failure (loadFailed()).\n protected retry(): void {\n this.countriesLoader.reload().then(() => this.load());\n }\n\n // protected geoRegion: GeoRegion | 'All' | 'Americas' = 'All';\n\n protected onChanged(): void {\n this.countryIDChange.emit(this.countryID);\n }\n\n protected onFilterChanged(filter: string): void {\n this.filter.set(filter);\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['country'] && this.countryID === '--' && !this.canBeUnknown()) {\n this.countryID = undefined;\n }\n const defaultCountryID = this.defaultCountryID();\n if (\n changes['defaultCountryID'] &&\n !this.countryID &&\n defaultCountryID &&\n defaultCountryID !== '--'\n ) {\n this.countryID = defaultCountryID;\n this.countryIDChange.emit(this.countryID);\n }\n }\n\n protected onRegionChanged(event: Event): void {\n this.geoRegion.set(\n (event as CustomEvent).detail.value as GeoRegion | 'All' | 'Americas',\n );\n }\n\n protected readonly filterCountryByCode = (\n item: ISelectItem,\n filter: string,\n ) => {\n const f = filter.trim().toUpperCase();\n const c = item as ICountry;\n return c.id === f || c.id3.startsWith(f);\n };\n}\n","@if (loadFailed()) {\n <ion-item color=\"danger\" lines=\"none\">\n <ion-label class=\"ion-text-wrap\">\n Couldn't load the list of countries. Check your connection and try again.\n </ion-label>\n <ion-button slot=\"end\" fill=\"clear\" (click)=\"retry()\">Retry</ion-button>\n </ion-item>\n}\n\n<sneat-select-from-list\n [value]=\"countryID || ''\"\n [isFilterable]=\"true\"\n [filterLabel]=\"label()\"\n [label]=\"label()\"\n [items]=\"countries()\"\n [(ngModel)]=\"countryID\"\n (ngModelChange)=\"onChanged()\"\n [isReadonly]=\"readonly()\"\n [filterItem]=\"filterCountryByCode\"\n (filterChanged)=\"onFilterChanged($event)\"\n labelPlacement=\"start\"\n>\n @if (!countryID && !filter()) {\n <ion-segment [(ngModel)]=\"geoRegion\" (ionChange)=\"onRegionChanged($event)\">\n <ion-segment-button value=\"All\">All</ion-segment-button>\n @for (region of geoRegions; track region.id) {\n <ion-segment-button [value]=\"region.id\">\n <small>{{ region.id }}</small>\n </ion-segment-button>\n }\n </ion-segment>\n }\n</sneat-select-from-list>\n"]}
1
+ {"version":3,"file":"country-selector.component.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/country-selector/country-selector.component.ts","../../../../../../libs/components/src/lib/country-selector/country-selector.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n computed,\n EventEmitter,\n inject,\n Input,\n OnChanges,\n OnInit,\n Output,\n signal,\n SimpleChanges,\n ChangeDetectionStrategy,\n input,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n IonButton,\n IonItem,\n IonLabel,\n IonSegment,\n IonSegmentButton,\n} from '@ionic/angular';\nimport { ISelectItem, SelectFromListComponent } from '@sneat/ui';\nimport { GeoRegion, ICountry } from './countries';\nimport { CountriesLoaderService } from './countries-loader.service';\n\n@Component({\n selector: 'sneat-country-selector',\n templateUrl: './country-selector.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n FormsModule,\n SelectFromListComponent,\n IonSegment,\n IonSegmentButton,\n IonItem,\n IonLabel,\n IonButton,\n ],\n})\nexport class CountrySelectorComponent implements OnInit, OnChanges {\n private readonly countriesLoader = inject(CountriesLoaderService);\n\n protected readonly geoRegions: readonly {\n readonly id: string;\n title?: string;\n }[] = [\n { id: 'Europe' },\n { id: 'Asia' },\n { id: 'Americas' },\n { id: 'Africa' },\n ];\n\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input({ required: true }) countryID?: string;\n\n readonly defaultCountryID = input<string>();\n\n readonly readonly = input(false);\n readonly disabled = input(false);\n readonly label = input('search');\n readonly canBeUnknown = input(false);\n\n @Output() readonly countryIDChange = new EventEmitter<string>();\n\n protected readonly filter = signal<string>('');\n protected readonly geoRegion = signal<GeoRegion | 'All' | 'Americas'>('All');\n protected readonly allCountries = signal<readonly ICountry[]>([]);\n protected readonly unknownCountry = signal<ICountry | undefined>(undefined);\n\n // True when the country list failed to load — surfaced in the UI with a Retry.\n protected readonly loadFailed = this.countriesLoader.loadFailed;\n\n protected readonly countries = computed<readonly ISelectItem[]>(() => {\n const allCountries = this.allCountries();\n if (allCountries.length === 0) {\n return []; // Data not loaded yet\n }\n\n const filter = this.filter();\n let countriesToShow: readonly ISelectItem[] = filter\n ? allCountries\n : allCountries.filter(\n (c) =>\n this.geoRegion() === 'All' ||\n (this.geoRegion() === 'Americas' &&\n (c.geoRegions.includes('North America') ||\n c.geoRegions.includes('South America'))) ||\n c.geoRegions.includes(this.geoRegion() as GeoRegion),\n );\n const unknownCountry = this.unknownCountry();\n if (this.canBeUnknown() && unknownCountry) {\n countriesToShow = [...countriesToShow, unknownCountry];\n }\n return countriesToShow;\n });\n\n ngOnInit(): void {\n this.load();\n }\n\n private load(): void {\n this.countriesLoader.getCountries().then((countries) => {\n this.allCountries.set(countries);\n });\n this.countriesLoader.getUnknownCountry().then((unknown) => {\n this.unknownCountry.set(unknown);\n });\n }\n\n // Retry loading the country list after a failure (loadFailed()).\n protected retry(): void {\n this.countriesLoader.reload().then(() => this.load());\n }\n\n // protected geoRegion: GeoRegion | 'All' | 'Americas' = 'All';\n\n protected onChanged(): void {\n this.countryIDChange.emit(this.countryID);\n }\n\n protected onFilterChanged(filter: string): void {\n this.filter.set(filter);\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['country'] && this.countryID === '--' && !this.canBeUnknown()) {\n this.countryID = undefined;\n }\n const defaultCountryID = this.defaultCountryID();\n if (\n changes['defaultCountryID'] &&\n !this.countryID &&\n defaultCountryID &&\n defaultCountryID !== '--'\n ) {\n this.countryID = defaultCountryID;\n this.countryIDChange.emit(this.countryID);\n }\n }\n\n protected onRegionChanged(event: Event): void {\n this.geoRegion.set(\n (event as CustomEvent).detail.value as GeoRegion | 'All' | 'Americas',\n );\n }\n\n protected readonly filterCountryByCode = (\n item: ISelectItem,\n filter: string,\n ) => {\n const f = filter.trim().toUpperCase();\n const c = item as ICountry;\n return c.id === f || c.id3.startsWith(f);\n };\n}\n","@if (loadFailed()) {\n <ion-item color=\"danger\" lines=\"none\">\n <ion-label class=\"ion-text-wrap\">\n Couldn't load the list of countries. Check your connection and try again.\n </ion-label>\n <ion-button slot=\"end\" fill=\"clear\" (click)=\"retry()\">Retry</ion-button>\n </ion-item>\n}\n\n<sneat-select-from-list\n [value]=\"countryID || ''\"\n [isFilterable]=\"true\"\n [filterLabel]=\"label()\"\n [label]=\"label()\"\n [items]=\"countries()\"\n [(ngModel)]=\"countryID\"\n (ngModelChange)=\"onChanged()\"\n [isReadonly]=\"readonly()\"\n [filterItem]=\"filterCountryByCode\"\n (filterChanged)=\"onFilterChanged($event)\"\n labelPlacement=\"start\"\n>\n @if (!countryID && !filter()) {\n <ion-segment [(ngModel)]=\"geoRegion\" (ionChange)=\"onRegionChanged($event)\">\n <ion-segment-button value=\"All\">All</ion-segment-button>\n @for (region of geoRegions; track region.id) {\n <ion-segment-button [value]=\"region.id\">\n <small>{{ region.id }}</small>\n </ion-segment-button>\n }\n </ion-segment>\n }\n</sneat-select-from-list>\n"]}
@@ -0,0 +1,232 @@
1
+ import { ChangeDetectionStrategy, Component, InjectionToken, inject, input, signal, } from '@angular/core';
2
+ import { ActivatedRoute, RouterLink } from '@angular/router';
3
+ import { IonButton } from '@ionic/angular/ion-button';
4
+ import { IonCard } from '@ionic/angular/ion-card';
5
+ import { IonCardContent } from '@ionic/angular/ion-card-content';
6
+ import { IonCardHeader } from '@ionic/angular/ion-card-header';
7
+ import { IonCardTitle } from '@ionic/angular/ion-card-title';
8
+ import { IonItem } from '@ionic/angular/ion-item';
9
+ import { IonLabel } from '@ionic/angular/ion-label';
10
+ import { IonList } from '@ionic/angular/ion-list';
11
+ import { IonNote } from '@ionic/angular/ion-note';
12
+ import * as i0 from "@angular/core";
13
+ /** The host supplies authenticated read-only billing infrastructure. */
14
+ export const SUBSCRIPTION_RECOVERY = new InjectionToken('SubscriptionRecovery');
15
+ export class SubscriptionRecoveryComponent {
16
+ constructor() {
17
+ this.port = inject(SUBSCRIPTION_RECOVERY, { optional: true });
18
+ this.route = inject(ActivatedRoute);
19
+ this.title = input('Finish subscription setup', /* @ts-ignore */
20
+ ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
21
+ this.items = signal([], /* @ts-ignore */
22
+ ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
23
+ this.mode = signal('live', /* @ts-ignore */
24
+ ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
25
+ this.signedIn = signal(false, /* @ts-ignore */
26
+ ...(ngDevMode ? [{ debugName: "signedIn" }] : /* istanbul ignore next */ []));
27
+ this.busy = signal(false, /* @ts-ignore */
28
+ ...(ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []));
29
+ this.error = signal('', /* @ts-ignore */
30
+ ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
31
+ this.next = signal('', /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "next" }] : /* istanbul ignore next */ []));
33
+ this.generation = 0;
34
+ this.observerGeneration = 0;
35
+ this.identity = null;
36
+ this.routeSubscription = this.route.queryParamMap.subscribe((params) => {
37
+ this.generation++;
38
+ const observerGeneration = ++this.observerGeneration;
39
+ this.stopIdentity?.();
40
+ this.items.set([]);
41
+ this.next.set('');
42
+ this.error.set('');
43
+ this.busy.set(false);
44
+ this.signedIn.set(false);
45
+ const values = params.getAll('checkout');
46
+ if (values.length > 1 || (values.length === 1 && values[0] !== 'test'))
47
+ return;
48
+ this.mode.set(values[0] === 'test' ? 'test' : 'live');
49
+ this.stopIdentity = this.port?.observeIdentity((id) => {
50
+ if (observerGeneration !== this.observerGeneration)
51
+ return;
52
+ this.generation++;
53
+ this.identity = id;
54
+ this.signedIn.set(Boolean(id));
55
+ this.items.set([]);
56
+ this.next.set('');
57
+ this.busy.set(false);
58
+ this.error.set('');
59
+ if (id)
60
+ void this.load(false);
61
+ });
62
+ });
63
+ }
64
+ async load(more) {
65
+ if (!this.port || !this.identity || this.busy())
66
+ return;
67
+ const generation = this.generation;
68
+ const after = more ? this.next() : '';
69
+ this.busy.set(true);
70
+ this.error.set('');
71
+ try {
72
+ const page = await this.port.load(this.mode(), after);
73
+ if (generation !== this.generation)
74
+ return;
75
+ const items = more ? [...this.items(), ...page.items] : page.items;
76
+ this.items.set([
77
+ ...new Map(items.map((item) => [item.id, item])).values(),
78
+ ]);
79
+ this.next.set(page.next ?? '');
80
+ }
81
+ catch {
82
+ if (generation === this.generation)
83
+ this.error.set('Your purchases could not be checked. Please retry.');
84
+ }
85
+ finally {
86
+ if (generation === this.generation)
87
+ this.busy.set(false);
88
+ }
89
+ }
90
+ refresh() {
91
+ if (this.busy())
92
+ return;
93
+ this.generation++;
94
+ this.next.set('');
95
+ void this.load(false);
96
+ }
97
+ ngOnDestroy() {
98
+ this.generation++;
99
+ this.observerGeneration++;
100
+ this.stopIdentity?.();
101
+ this.routeSubscription.unsubscribe();
102
+ }
103
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SubscriptionRecoveryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
104
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SubscriptionRecoveryComponent, isStandalone: true, selector: "sneat-subscription-recovery", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
105
+ @if (
106
+ port && signedIn() && (busy() || error() || items().length || next())
107
+ ) {
108
+ <ion-card aria-label="Unfinished subscriptions">
109
+ <ion-card-header
110
+ ><ion-card-title
111
+ >{{ title() }}
112
+ @if (mode() === 'test') {
113
+ · Test mode
114
+ }
115
+ </ion-card-title></ion-card-header
116
+ >
117
+ <ion-card-content>
118
+ @if (items().length) {
119
+ <ion-list>
120
+ @for (item of items(); track item.id) {
121
+ <ion-item
122
+ [routerLink]="item.path"
123
+ [queryParams]="item.query"
124
+ button
125
+ detail
126
+ >
127
+ <ion-label class="ion-text-wrap"
128
+ ><h2>{{ item.label }}</h2>
129
+ @if (item.description) {
130
+ <p>{{ item.description }}</p>
131
+ }
132
+ <p>{{ item.action }}</p></ion-label
133
+ >
134
+ </ion-item>
135
+ }
136
+ </ion-list>
137
+ }
138
+ @if (busy()) {
139
+ <p role="status">Checking your purchases…</p>
140
+ }
141
+ @if (error()) {
142
+ <p role="alert">{{ error() }}</p>
143
+ <ion-button fill="outline" (click)="load(false)">Retry</ion-button>
144
+ }
145
+ @if (next() && !busy() && !error()) {
146
+ <ion-button fill="clear" (click)="load(true)"
147
+ >Show more purchases</ion-button
148
+ >
149
+ }
150
+ <ion-note
151
+ >Opening a purchase checks its current status. It does not charge
152
+ you again.</ion-note
153
+ >
154
+ </ion-card-content>
155
+ </ion-card>
156
+ }
157
+ `, isInline: true, dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"], outputs: ["ionFocus", "ionBlur"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
158
+ }
159
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SubscriptionRecoveryComponent, decorators: [{
160
+ type: Component,
161
+ args: [{
162
+ selector: 'sneat-subscription-recovery',
163
+ changeDetection: ChangeDetectionStrategy.OnPush,
164
+ imports: [
165
+ RouterLink,
166
+ IonButton,
167
+ IonCard,
168
+ IonCardContent,
169
+ IonCardHeader,
170
+ IonCardTitle,
171
+ IonItem,
172
+ IonLabel,
173
+ IonList,
174
+ IonNote,
175
+ ],
176
+ template: `
177
+ @if (
178
+ port && signedIn() && (busy() || error() || items().length || next())
179
+ ) {
180
+ <ion-card aria-label="Unfinished subscriptions">
181
+ <ion-card-header
182
+ ><ion-card-title
183
+ >{{ title() }}
184
+ @if (mode() === 'test') {
185
+ · Test mode
186
+ }
187
+ </ion-card-title></ion-card-header
188
+ >
189
+ <ion-card-content>
190
+ @if (items().length) {
191
+ <ion-list>
192
+ @for (item of items(); track item.id) {
193
+ <ion-item
194
+ [routerLink]="item.path"
195
+ [queryParams]="item.query"
196
+ button
197
+ detail
198
+ >
199
+ <ion-label class="ion-text-wrap"
200
+ ><h2>{{ item.label }}</h2>
201
+ @if (item.description) {
202
+ <p>{{ item.description }}</p>
203
+ }
204
+ <p>{{ item.action }}</p></ion-label
205
+ >
206
+ </ion-item>
207
+ }
208
+ </ion-list>
209
+ }
210
+ @if (busy()) {
211
+ <p role="status">Checking your purchases…</p>
212
+ }
213
+ @if (error()) {
214
+ <p role="alert">{{ error() }}</p>
215
+ <ion-button fill="outline" (click)="load(false)">Retry</ion-button>
216
+ }
217
+ @if (next() && !busy() && !error()) {
218
+ <ion-button fill="clear" (click)="load(true)"
219
+ >Show more purchases</ion-button
220
+ >
221
+ }
222
+ <ion-note
223
+ >Opening a purchase checks its current status. It does not charge
224
+ you again.</ion-note
225
+ >
226
+ </ion-card-content>
227
+ </ion-card>
228
+ }
229
+ `,
230
+ }]
231
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }] } });
232
+ //# sourceMappingURL=subscription-recovery.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-recovery.component.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/subscription-recovery/subscription-recovery.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n InjectionToken,\n OnDestroy,\n inject,\n input,\n signal,\n} from '@angular/core';\nimport { ActivatedRoute, RouterLink } from '@angular/router';\nimport { IonButton } from '@ionic/angular/ion-button';\nimport { IonCard } from '@ionic/angular/ion-card';\nimport { IonCardContent } from '@ionic/angular/ion-card-content';\nimport { IonCardHeader } from '@ionic/angular/ion-card-header';\nimport { IonCardTitle } from '@ionic/angular/ion-card-title';\nimport { IonItem } from '@ionic/angular/ion-item';\nimport { IonLabel } from '@ionic/angular/ion-label';\nimport { IonList } from '@ionic/angular/ion-list';\nimport { IonNote } from '@ionic/angular/ion-note';\n\nexport type SubscriptionRecoveryMode = 'live' | 'test';\nexport interface SubscriptionRecoveryItem {\n id: string;\n label: string;\n description?: string;\n action: string;\n path: string;\n query: Record<string, string>;\n}\nexport interface SubscriptionRecoveryPort {\n observeIdentity(callback: (id: string | null) => void): () => void;\n load(\n mode: SubscriptionRecoveryMode,\n after: string,\n ): Promise<{ items: SubscriptionRecoveryItem[]; next?: string }>;\n}\n/** The host supplies authenticated read-only billing infrastructure. */\nexport const SUBSCRIPTION_RECOVERY =\n new InjectionToken<SubscriptionRecoveryPort>('SubscriptionRecovery');\n\n@Component({\n selector: 'sneat-subscription-recovery',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n RouterLink,\n IonButton,\n IonCard,\n IonCardContent,\n IonCardHeader,\n IonCardTitle,\n IonItem,\n IonLabel,\n IonList,\n IonNote,\n ],\n template: `\n @if (\n port && signedIn() && (busy() || error() || items().length || next())\n ) {\n <ion-card aria-label=\"Unfinished subscriptions\">\n <ion-card-header\n ><ion-card-title\n >{{ title() }}\n @if (mode() === 'test') {\n · Test mode\n }\n </ion-card-title></ion-card-header\n >\n <ion-card-content>\n @if (items().length) {\n <ion-list>\n @for (item of items(); track item.id) {\n <ion-item\n [routerLink]=\"item.path\"\n [queryParams]=\"item.query\"\n button\n detail\n >\n <ion-label class=\"ion-text-wrap\"\n ><h2>{{ item.label }}</h2>\n @if (item.description) {\n <p>{{ item.description }}</p>\n }\n <p>{{ item.action }}</p></ion-label\n >\n </ion-item>\n }\n </ion-list>\n }\n @if (busy()) {\n <p role=\"status\">Checking your purchases…</p>\n }\n @if (error()) {\n <p role=\"alert\">{{ error() }}</p>\n <ion-button fill=\"outline\" (click)=\"load(false)\">Retry</ion-button>\n }\n @if (next() && !busy() && !error()) {\n <ion-button fill=\"clear\" (click)=\"load(true)\"\n >Show more purchases</ion-button\n >\n }\n <ion-note\n >Opening a purchase checks its current status. It does not charge\n you again.</ion-note\n >\n </ion-card-content>\n </ion-card>\n }\n `,\n})\nexport class SubscriptionRecoveryComponent implements OnDestroy {\n protected readonly port = inject(SUBSCRIPTION_RECOVERY, { optional: true });\n private readonly route = inject(ActivatedRoute);\n readonly title = input('Finish subscription setup');\n protected readonly items = signal<SubscriptionRecoveryItem[]>([]);\n protected readonly mode = signal<SubscriptionRecoveryMode>('live');\n protected readonly signedIn = signal(false);\n protected readonly busy = signal(false);\n protected readonly error = signal('');\n protected readonly next = signal('');\n private generation = 0;\n private observerGeneration = 0;\n private identity: string | null = null;\n private stopIdentity?: () => void;\n private readonly routeSubscription = this.route.queryParamMap.subscribe(\n (params) => {\n this.generation++;\n const observerGeneration = ++this.observerGeneration;\n this.stopIdentity?.();\n this.items.set([]);\n this.next.set('');\n this.error.set('');\n this.busy.set(false);\n this.signedIn.set(false);\n const values = params.getAll('checkout');\n if (values.length > 1 || (values.length === 1 && values[0] !== 'test'))\n return;\n this.mode.set(values[0] === 'test' ? 'test' : 'live');\n this.stopIdentity = this.port?.observeIdentity((id) => {\n if (observerGeneration !== this.observerGeneration) return;\n this.generation++;\n this.identity = id;\n this.signedIn.set(Boolean(id));\n this.items.set([]);\n this.next.set('');\n this.busy.set(false);\n this.error.set('');\n if (id) void this.load(false);\n });\n },\n );\n\n protected async load(more: boolean): Promise<void> {\n if (!this.port || !this.identity || this.busy()) return;\n const generation = this.generation;\n const after = more ? this.next() : '';\n this.busy.set(true);\n this.error.set('');\n try {\n const page = await this.port.load(this.mode(), after);\n if (generation !== this.generation) return;\n const items = more ? [...this.items(), ...page.items] : page.items;\n this.items.set([\n ...new Map(items.map((item) => [item.id, item])).values(),\n ]);\n this.next.set(page.next ?? '');\n } catch {\n if (generation === this.generation)\n this.error.set('Your purchases could not be checked. Please retry.');\n } finally {\n if (generation === this.generation) this.busy.set(false);\n }\n }\n refresh(): void {\n if (this.busy()) return;\n this.generation++;\n this.next.set('');\n void this.load(false);\n }\n ngOnDestroy(): void {\n this.generation++;\n this.observerGeneration++;\n this.stopIdentity?.();\n this.routeSubscription.unsubscribe();\n }\n}\n"]}