@sneat/components 0.1.3 β†’ 0.1.4

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 (170) hide show
  1. package/esm2022/index.js +15 -0
  2. package/esm2022/index.js.map +1 -0
  3. package/esm2022/lib/app-version/app-version.component.js +16 -0
  4. package/esm2022/lib/app-version/app-version.component.js.map +1 -0
  5. package/esm2022/lib/app-version/build-info.js +5 -0
  6. package/esm2022/lib/app-version/build-info.js.map +1 -0
  7. package/esm2022/lib/app-version/index.js +3 -0
  8. package/esm2022/lib/app-version/index.js.map +1 -0
  9. package/esm2022/lib/card-list/index.js +2 -0
  10. package/esm2022/lib/card-list/index.js.map +1 -0
  11. package/esm2022/lib/card-list/sneat-card-list.component.js +106 -0
  12. package/esm2022/lib/card-list/sneat-card-list.component.js.map +1 -0
  13. package/esm2022/lib/copyright/copyright.component.js +11 -0
  14. package/esm2022/lib/copyright/copyright.component.js.map +1 -0
  15. package/esm2022/lib/copyright/index.js +2 -0
  16. package/esm2022/lib/copyright/index.js.map +1 -0
  17. package/esm2022/lib/country-input/country-input.component.js +59 -0
  18. package/esm2022/lib/country-input/country-input.component.js.map +1 -0
  19. package/esm2022/lib/country-input/index.js +2 -0
  20. package/esm2022/lib/country-input/index.js.map +1 -0
  21. package/esm2022/lib/country-selector/countries-loader.service.js +91 -0
  22. package/esm2022/lib/country-selector/countries-loader.service.js.map +1 -0
  23. package/esm2022/lib/country-selector/countries.js +22 -0
  24. package/esm2022/lib/country-selector/countries.js.map +1 -0
  25. package/esm2022/lib/country-selector/country-selector.component.js +103 -0
  26. package/esm2022/lib/country-selector/country-selector.component.js.map +1 -0
  27. package/esm2022/lib/country-selector/country-selector.service.js +15 -0
  28. package/esm2022/lib/country-selector/country-selector.service.js.map +1 -0
  29. package/esm2022/lib/country-selector/index.js +5 -0
  30. package/esm2022/lib/country-selector/index.js.map +1 -0
  31. package/esm2022/lib/date-input/date-input.component.js +70 -0
  32. package/esm2022/lib/date-input/date-input.component.js.map +1 -0
  33. package/esm2022/lib/date-input/date-modal.component.js +53 -0
  34. package/esm2022/lib/date-input/date-modal.component.js.map +1 -0
  35. package/esm2022/lib/dialog-header/dialog-header.component.js +23 -0
  36. package/esm2022/lib/dialog-header/dialog-header.component.js.map +1 -0
  37. package/esm2022/lib/dialog-header/index.js +2 -0
  38. package/esm2022/lib/dialog-header/index.js.map +1 -0
  39. package/esm2022/lib/error-card/index.js +2 -0
  40. package/esm2022/lib/error-card/index.js.map +1 -0
  41. package/esm2022/lib/error-card/sneat-error-card.component.js +23 -0
  42. package/esm2022/lib/error-card/sneat-error-card.component.js.map +1 -0
  43. package/esm2022/lib/filter-item/filter-item.component.js +37 -0
  44. package/esm2022/lib/filter-item/filter-item.component.js.map +1 -0
  45. package/esm2022/lib/filter-item/index.js +2 -0
  46. package/esm2022/lib/filter-item/index.js.map +1 -0
  47. package/esm2022/lib/pipes/country-emoji.pipe.js +69 -0
  48. package/esm2022/lib/pipes/country-emoji.pipe.js.map +1 -0
  49. package/esm2022/lib/pipes/decimal64p2.pipe.js +47 -0
  50. package/esm2022/lib/pipes/decimal64p2.pipe.js.map +1 -0
  51. package/esm2022/lib/pipes/gender.pipes.js +69 -0
  52. package/esm2022/lib/pipes/gender.pipes.js.map +1 -0
  53. package/esm2022/lib/pipes/index.js +7 -0
  54. package/esm2022/lib/pipes/index.js.map +1 -0
  55. package/esm2022/lib/pipes/long-month-name.pipe.js +41 -0
  56. package/esm2022/lib/pipes/long-month-name.pipe.js.map +1 -0
  57. package/esm2022/lib/pipes/short-month-name.pipe.js +31 -0
  58. package/esm2022/lib/pipes/short-month-name.pipe.js.map +1 -0
  59. package/esm2022/lib/pipes/team-emoji.pipe.js +31 -0
  60. package/esm2022/lib/pipes/team-emoji.pipe.js.map +1 -0
  61. package/esm2022/lib/save-event.js +2 -0
  62. package/esm2022/lib/save-event.js.map +1 -0
  63. package/esm2022/lib/user-country/user-country.component.js +136 -0
  64. package/esm2022/lib/user-country/user-country.component.js.map +1 -0
  65. package/esm2022/lib/virtual-slider/virtual-slider.js +83 -0
  66. package/esm2022/lib/virtual-slider/virtual-slider.js.map +1 -0
  67. package/esm2022/sneat-components.js +5 -0
  68. package/esm2022/sneat-components.js.map +1 -0
  69. package/lib/app-version/app-version.component.d.ts +9 -0
  70. package/lib/app-version/build-info.d.ts +4 -0
  71. package/lib/card-list/sneat-card-list.component.d.ts +43 -0
  72. package/lib/copyright/copyright.component.d.ts +5 -0
  73. package/lib/country-input/country-input.component.d.ts +16 -0
  74. package/lib/country-selector/countries-loader.service.d.ts +43 -0
  75. package/lib/country-selector/countries.d.ts +25 -0
  76. package/lib/country-selector/country-selector.component.d.ts +31 -0
  77. package/lib/country-selector/country-selector.service.d.ts +8 -0
  78. package/lib/date-input/date-input.component.d.ts +21 -0
  79. package/lib/date-input/date-modal.component.d.ts +13 -0
  80. package/lib/dialog-header/dialog-header.component.d.ts +8 -0
  81. package/lib/error-card/sneat-error-card.component.d.ts +8 -0
  82. package/lib/filter-item/filter-item.component.d.ts +13 -0
  83. package/lib/pipes/country-emoji.pipe.d.ts +29 -0
  84. package/lib/pipes/decimal64p2.pipe.d.ts +12 -0
  85. package/lib/pipes/gender.pipes.d.ts +20 -0
  86. package/lib/pipes/long-month-name.pipe.d.ts +7 -0
  87. package/lib/pipes/short-month-name.pipe.d.ts +8 -0
  88. package/lib/pipes/team-emoji.pipe.d.ts +8 -0
  89. package/lib/save-event.d.ts +5 -0
  90. package/lib/user-country/user-country.component.d.ts +24 -0
  91. package/lib/virtual-slider/virtual-slider.d.ts +13 -0
  92. package/package.json +14 -2
  93. package/sneat-components.d.ts +5 -0
  94. package/eslint.config.js +0 -7
  95. package/ng-package.json +0 -10
  96. package/project.json +0 -38
  97. package/src/assets/data/countries.json +0 -1730
  98. package/src/lib/app-version/app-version.component.html +0 -15
  99. package/src/lib/app-version/app-version.component.spec.ts +0 -25
  100. package/src/lib/app-version/app-version.component.ts +0 -17
  101. package/src/lib/app-version/build-info.ts +0 -8
  102. package/src/lib/card-list/sneat-card-list.component.html +0 -108
  103. package/src/lib/card-list/sneat-card-list.component.spec.ts +0 -131
  104. package/src/lib/card-list/sneat-card-list.component.ts +0 -125
  105. package/src/lib/copyright/copyright.component.html +0 -1
  106. package/src/lib/copyright/copyright.component.spec.ts +0 -24
  107. package/src/lib/copyright/copyright.component.ts +0 -7
  108. package/src/lib/country-input/country-input.component.html +0 -33
  109. package/src/lib/country-input/country-input.component.spec.ts +0 -84
  110. package/src/lib/country-input/country-input.component.ts +0 -76
  111. package/src/lib/country-selector/countries-loader.service.spec.ts +0 -149
  112. package/src/lib/country-selector/countries-loader.service.ts +0 -100
  113. package/src/lib/country-selector/countries.ts +0 -42
  114. package/src/lib/country-selector/country-selector.component.html +0 -24
  115. package/src/lib/country-selector/country-selector.component.spec.ts +0 -5
  116. package/src/lib/country-selector/country-selector.component.ts +0 -125
  117. package/src/lib/country-selector/country-selector.service.spec.ts +0 -23
  118. package/src/lib/country-selector/country-selector.service.ts +0 -11
  119. package/src/lib/date-input/date-input.component.html +0 -39
  120. package/src/lib/date-input/date-input.component.spec.ts +0 -179
  121. package/src/lib/date-input/date-input.component.ts +0 -97
  122. package/src/lib/date-input/date-modal.component.html +0 -23
  123. package/src/lib/date-input/date-modal.component.spec.ts +0 -105
  124. package/src/lib/date-input/date-modal.component.ts +0 -67
  125. package/src/lib/dialog-header/dialog-header.component.html +0 -8
  126. package/src/lib/dialog-header/dialog-header.component.spec.ts +0 -67
  127. package/src/lib/dialog-header/dialog-header.component.ts +0 -26
  128. package/src/lib/dismissable.ts +0 -6
  129. package/src/lib/error-card/sneat-error-card.component.html +0 -20
  130. package/src/lib/error-card/sneat-error-card.component.spec.ts +0 -49
  131. package/src/lib/error-card/sneat-error-card.component.ts +0 -28
  132. package/src/lib/filter-item/filter-item.component.html +0 -19
  133. package/src/lib/filter-item/filter-item.component.spec.ts +0 -83
  134. package/src/lib/filter-item/filter-item.component.ts +0 -47
  135. package/src/lib/pipes/country-emoji.pipe.spec.ts +0 -116
  136. package/src/lib/pipes/country-emoji.pipe.ts +0 -67
  137. package/src/lib/pipes/decimal64p2.pipe.spec.ts +0 -61
  138. package/src/lib/pipes/decimal64p2.pipe.ts +0 -35
  139. package/src/lib/pipes/gender.pipes.spec.ts +0 -84
  140. package/src/lib/pipes/gender.pipes.ts +0 -65
  141. package/src/lib/pipes/long-month-name.pipe.spec.ts +0 -36
  142. package/src/lib/pipes/long-month-name.pipe.ts +0 -35
  143. package/src/lib/pipes/short-month-name.pipe.spec.ts +0 -28
  144. package/src/lib/pipes/short-month-name.pipe.ts +0 -26
  145. package/src/lib/pipes/team-emoji.pipe.spec.ts +0 -27
  146. package/src/lib/pipes/team-emoji.pipe.ts +0 -26
  147. package/src/lib/save-event.ts +0 -5
  148. package/src/lib/test-ide-bug.ts +0 -24
  149. package/src/lib/user-country/user-country.component.html +0 -44
  150. package/src/lib/user-country/user-country.component.spec.ts +0 -136
  151. package/src/lib/user-country/user-country.component.ts +0 -172
  152. package/src/lib/virtual-slider/odd-even-virtual-slider.ts +0 -1
  153. package/src/lib/virtual-slider/virtual-slider.ts +0 -130
  154. package/src/lib/webstorm-type-err-demo.component.ts +0 -35
  155. package/src/test-setup.ts +0 -3
  156. package/tsconfig.json +0 -13
  157. package/tsconfig.lib.json +0 -19
  158. package/tsconfig.lib.prod.json +0 -7
  159. package/tsconfig.spec.json +0 -31
  160. package/vite.config.mts +0 -10
  161. /package/{src/index.ts β†’ index.d.ts} +0 -0
  162. /package/{src/lib/app-version/index.ts β†’ lib/app-version/index.d.ts} +0 -0
  163. /package/{src/lib/card-list/index.ts β†’ lib/card-list/index.d.ts} +0 -0
  164. /package/{src/lib/copyright/index.ts β†’ lib/copyright/index.d.ts} +0 -0
  165. /package/{src/lib/country-input/index.ts β†’ lib/country-input/index.d.ts} +0 -0
  166. /package/{src/lib/country-selector/index.ts β†’ lib/country-selector/index.d.ts} +0 -0
  167. /package/{src/lib/dialog-header/index.ts β†’ lib/dialog-header/index.d.ts} +0 -0
  168. /package/{src/lib/error-card/index.ts β†’ lib/error-card/index.d.ts} +0 -0
  169. /package/{src/lib/filter-item/index.ts β†’ lib/filter-item/index.d.ts} +0 -0
  170. /package/{src/lib/pipes/index.ts β†’ lib/pipes/index.d.ts} +0 -0
@@ -1,15 +0,0 @@
1
- <ion-item-divider color="light">
2
- <ion-label>App version</ion-label>
3
- </ion-item-divider>
4
- <ion-item>
5
- <ion-input
6
- label="Build:"
7
- color="medium"
8
- readonly="true"
9
- disabled="true"
10
- [value]="
11
- buildInfo.gitHash.substring(0, 7) + ' @ ' + buildInfo.buildTimestamp
12
- "
13
- [title]="buildInfo.gitHash"
14
- />
15
- </ion-item>
@@ -1,25 +0,0 @@
1
- import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2
- import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
3
- import { AppVersionComponent } from './app-version.component';
4
-
5
- describe('AppVersionComponent', () => {
6
- let component: AppVersionComponent;
7
- let fixture: ComponentFixture<AppVersionComponent>;
8
-
9
- beforeEach(waitForAsync(async () => {
10
- await TestBed.configureTestingModule({
11
- imports: [AppVersionComponent],
12
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
13
- })
14
- .overrideComponent(AppVersionComponent, {
15
- set: { imports: [], schemas: [CUSTOM_ELEMENTS_SCHEMA] },
16
- })
17
- .compileComponents();
18
- fixture = TestBed.createComponent(AppVersionComponent);
19
- component = fixture.componentInstance;
20
- }));
21
-
22
- it('should create', () => {
23
- expect(component).toBeTruthy();
24
- });
25
- });
@@ -1,17 +0,0 @@
1
- import { Component } from '@angular/core';
2
- import {
3
- IonInput,
4
- IonItem,
5
- IonItemDivider,
6
- IonLabel,
7
- } from '@ionic/angular/standalone';
8
- import { buildInfo } from './build-info';
9
-
10
- @Component({
11
- selector: 'sneat-app-version',
12
- templateUrl: 'app-version.component.html',
13
- imports: [IonItemDivider, IonLabel, IonItem, IonInput],
14
- })
15
- export class AppVersionComponent {
16
- protected readonly buildInfo = buildInfo;
17
- }
@@ -1,8 +0,0 @@
1
- export const buildInfo: {
2
- // TODO: Needs pre-commit hook to check gitHash and buildTimestamp are NOT changed.
3
- readonly gitHash: string;
4
- readonly buildTimestamp: string;
5
- } = {
6
- gitHash: 'gitHash t0be$et',
7
- buildTimestamp: 'timestamp t0be$et',
8
- };
@@ -1,108 +0,0 @@
1
- <ion-card>
2
- @if (title) {
3
- <ion-item (click)="cardTitleClick.emit()" tappable>
4
- @if (itemIcon && !isLoading && !items?.length) {
5
- <ion-icon [name]="itemIcon" slot="start" />
6
- }
7
- <ion-label style="font-weight: bold">{{ title }}</ion-label>
8
- @if (isFilterable) {
9
- <ion-input [(ngModel)]="filter" placeholder="(type to filter)" />
10
- }
11
- <ion-buttons slot="end">
12
- @if (filter) {
13
- <ion-button (click)="filter = ''" title="Clear filter">
14
- <ion-icon name="close-outline" color="medium" />
15
- </ion-button>
16
- }
17
- @if (mode !== "add" && create) {
18
- <ion-button (click)="showAddForm($event)">
19
- <ion-icon color="primary" slot="start" name="add" />
20
- <ion-label color="medium">Add</ion-label>
21
- </ion-button>
22
- }
23
- </ion-buttons>
24
- </ion-item>
25
- }
26
- @if (tabs) {
27
- <ion-segment [(ngModel)]="tab" (ionChange)="tabChanged.emit(tab || '')">
28
- @for (tab of tabs; track tab.id) {
29
- <ion-segment-button [value]="tab.id">
30
- <ion-label>{{ tab.title }}</ion-label>
31
- </ion-segment-button>
32
- }
33
- </ion-segment>
34
- <ion-buttons>
35
- @if (mode !== "add" && create) {
36
- <ion-button (click)="showAddForm($event)">
37
- <ion-icon color="primary" slot="start" name="add" />
38
- <ion-label color="medium">Add</ion-label>
39
- </ion-button>
40
- }
41
- </ion-buttons>
42
- }
43
- @if (isLoading) {
44
- <ion-card-content>
45
- <ion-skeleton-text animated="" style="width: 100%" />
46
- </ion-card-content>
47
- } @else {
48
- <ion-list>
49
- @for (item of items; track item.id) {
50
- <ion-item
51
- tappable
52
- (click)="itemClick && click($event, item)"
53
- [routerLink]="getRouterLink(item)"
54
- >
55
- @if (itemIcon) {
56
- <ion-icon [name]="itemIcon" slot="start" />
57
- }
58
- <ion-label>{{ item.title || item.id }}</ion-label>
59
- </ion-item>
60
- }
61
- @if (mode === "add") {
62
- <ion-item>
63
- <ion-icon name="earth-outline" slot="start" color="medium" />
64
- <ion-input
65
- [(ngModel)]="name"
66
- placeholder="Name"
67
- [disabled]="!!isAdding"
68
- />
69
- <ion-buttons slot="end">
70
- <ion-button
71
- fill="solid"
72
- color="primary"
73
- [disabled]="isAdding || !name.trim()"
74
- (click)="tryCreate()"
75
- >
76
- Create
77
- </ion-button>
78
- <ion-button
79
- (click)="mode = 'list'"
80
- color="medium"
81
- title="Cancel"
82
- [disabled]="isAdding"
83
- >
84
- <ion-icon name="close-outline" />
85
- </ion-button>
86
- </ion-buttons>
87
- </ion-item>
88
- }
89
- </ion-list>
90
- @if (!items?.length && mode !== "add") {
91
- <ion-card-content>
92
- @if (!noItemsText) {
93
- <p>
94
- {{ noItemsText }}
95
- </p>
96
- } @else {
97
- <p>
98
- Not defined for this project yet. Click the
99
- <span style="background-color: whitesmoke; padding: 4px 8px"
100
- >+ Add</span
101
- >
102
- button above in the header of this card to create a first one.
103
- </p>
104
- }
105
- </ion-card-content>
106
- }
107
- }
108
- </ion-card>
@@ -1,131 +0,0 @@
1
- import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
- import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
3
- import { SneatCardListComponent } from './sneat-card-list.component';
4
- import { ErrorLogger } from '@sneat/core';
5
- import { of, throwError } from 'rxjs';
6
-
7
- describe('SneatCardListComponent', () => {
8
- let component: SneatCardListComponent;
9
- let fixture: ComponentFixture<SneatCardListComponent>;
10
- let errorLogger: { logError: ReturnType<typeof vi.fn> };
11
-
12
- beforeEach(waitForAsync(async () => {
13
- errorLogger = {
14
- logError: vi.fn(),
15
- };
16
-
17
- await TestBed.configureTestingModule({
18
- imports: [SneatCardListComponent],
19
- providers: [
20
- {
21
- provide: ErrorLogger,
22
- useValue: errorLogger,
23
- },
24
- ],
25
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
26
- })
27
- .overrideComponent(SneatCardListComponent, {
28
- set: {
29
- imports: [],
30
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
31
- template: '',
32
- },
33
- })
34
- .compileComponents();
35
-
36
- fixture = TestBed.createComponent(SneatCardListComponent);
37
- component = fixture.componentInstance;
38
- }));
39
-
40
- it('should create', () => {
41
- expect(component).toBeTruthy();
42
- });
43
-
44
- it('should emit itemClick when click is called', () => {
45
- const itemClickSpy = vi.fn();
46
- component.itemClick.subscribe(itemClickSpy);
47
-
48
- const mockEvent = {
49
- preventDefault: vi.fn(),
50
- stopPropagation: vi.fn(),
51
- } as unknown as Event;
52
-
53
- const mockItem = { id: 1, title: 'Test Item' };
54
-
55
- component['click'](mockEvent, mockItem);
56
-
57
- expect(mockEvent.preventDefault).toHaveBeenCalled();
58
- expect(mockEvent.stopPropagation).toHaveBeenCalled();
59
- expect(itemClickSpy).toHaveBeenCalledWith(mockItem);
60
- });
61
-
62
- it('should change mode to add when showAddForm is called', () => {
63
- const mockEvent = {
64
- preventDefault: vi.fn(),
65
- stopPropagation: vi.fn(),
66
- } as unknown as Event;
67
-
68
- component['showAddForm'](mockEvent);
69
-
70
- expect(mockEvent.preventDefault).toHaveBeenCalled();
71
- expect(mockEvent.stopPropagation).toHaveBeenCalled();
72
- expect(component['mode']).toBe('add');
73
- });
74
-
75
- it('should successfully create item when tryCreate is called', () => {
76
- const mockItem = { id: '123', title: 'New Item' };
77
- component.items = [];
78
- component.create = vi.fn().mockReturnValue(of(mockItem));
79
- component['name'] = 'New Item';
80
-
81
- component['tryCreate']();
82
-
83
- expect(component.create).toHaveBeenCalledWith('New Item');
84
- expect(component.items).toContain(mockItem);
85
- expect(component['mode']).toBe('list');
86
- expect(component['name']).toBe('');
87
- expect(component['isAdding']).toBe(false);
88
- });
89
-
90
- it('should handle error when tryCreate fails', () => {
91
- const mockError = new Error('Creation failed');
92
- component.create = vi.fn().mockReturnValue(throwError(() => mockError));
93
- component['name'] = 'New Item';
94
-
95
- component['tryCreate']();
96
-
97
- expect(component.create).toHaveBeenCalledWith('New Item');
98
- expect(errorLogger.logError).toHaveBeenCalledWith(
99
- mockError,
100
- 'Failed to create new item',
101
- );
102
- expect(component['isAdding']).toBe(false);
103
- });
104
-
105
- it('should not add item if create is not defined', () => {
106
- component.create = undefined;
107
- component['name'] = 'New Item';
108
-
109
- component['tryCreate']();
110
-
111
- expect(component['isAdding']).toBe(true);
112
- });
113
-
114
- it('should trim name before creating', () => {
115
- const mockItem = { id: '123', title: 'Trimmed' };
116
- component.items = [];
117
- component.create = vi.fn().mockReturnValue(of(mockItem));
118
- component['name'] = ' Trimmed ';
119
-
120
- component['tryCreate']();
121
-
122
- expect(component.create).toHaveBeenCalledWith('Trimmed');
123
- });
124
-
125
- it('should initialize with default values', () => {
126
- expect(component.filter).toBe('');
127
- expect(component['mode']).toBe('list');
128
- expect(component['name']).toBe('');
129
- expect(component['isAdding']).toBeUndefined();
130
- });
131
- });
@@ -1,125 +0,0 @@
1
- import {
2
- Component,
3
- EventEmitter,
4
- Input,
5
- Output,
6
- ViewChild,
7
- inject,
8
- } from '@angular/core';
9
- import { FormsModule } from '@angular/forms';
10
- import { RouterModule } from '@angular/router';
11
- import {
12
- IonButton,
13
- IonButtons,
14
- IonCard,
15
- IonCardContent,
16
- IonIcon,
17
- IonInput,
18
- IonItem,
19
- IonLabel,
20
- IonList,
21
- IonSegment,
22
- IonSegmentButton,
23
- IonSkeletonText,
24
- } from '@ionic/angular/standalone';
25
- import { IRecord } from '@sneat/data';
26
- import { ErrorLogger, IErrorLogger } from '@sneat/core';
27
- import { Observable } from 'rxjs';
28
-
29
- export interface ICardTab {
30
- id: string;
31
- title: string;
32
- }
33
-
34
- interface IOptionallyTitled {
35
- id?: string;
36
- title?: string;
37
- }
38
-
39
- @Component({
40
- selector: 'sneat-card-list',
41
- templateUrl: './sneat-card-list.component.html',
42
- imports: [
43
- RouterModule,
44
- IonCard,
45
- IonItem,
46
- IonIcon,
47
- IonLabel,
48
- IonInput,
49
- IonButtons,
50
- IonButton,
51
- IonSegment,
52
- IonSegmentButton,
53
- FormsModule,
54
- IonCardContent,
55
- IonSkeletonText,
56
- IonList,
57
- ],
58
- })
59
- export class SneatCardListComponent {
60
- private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);
61
-
62
- @Input() title?: string;
63
- @Input() isFilterable?: boolean;
64
- @Input() isLoading?: boolean;
65
- @Input() items?: { id?: unknown; title?: string }[];
66
- @Input() create?: (name: string) => Observable<IRecord<IOptionallyTitled>>;
67
- @Input() itemIcon?: string;
68
- @Input() tab?: string;
69
- @Input() tabs?: ICardTab[];
70
- @Input() noItemsText?: string;
71
- @Input() getRouterLink: (item: unknown) => string = () =>
72
- undefined as unknown as string;
73
-
74
- @Output() readonly cardTitleClick = new EventEmitter<void>();
75
- @Output() readonly itemClick = new EventEmitter<unknown>();
76
- @Output() readonly tabChanged = new EventEmitter<string>();
77
-
78
- @ViewChild(IonInput, { static: false }) addInput?: IonInput;
79
-
80
- filter = '';
81
-
82
- protected mode: 'list' | 'add' = 'list';
83
- protected name = '';
84
- protected isAdding?: boolean;
85
-
86
- protected click(event: Event, item: unknown): void {
87
- event.preventDefault();
88
- event.stopPropagation();
89
- this.itemClick.emit(item);
90
- }
91
-
92
- protected showAddForm(event: Event): void {
93
- event.preventDefault();
94
- event.stopPropagation();
95
- this.mode = 'add';
96
- setTimeout(() => {
97
- // console.log(this.addInput);
98
- if (this.addInput) {
99
- this.addInput
100
- ?.setFocus()
101
- .catch((err) =>
102
- this.errorLogger.logError(err, 'Failed to set focus'),
103
- );
104
- }
105
- }, 200);
106
- }
107
-
108
- protected tryCreate(): void {
109
- this.isAdding = true;
110
- if (this.create) {
111
- this.create(this.name.trim()).subscribe({
112
- next: (item) => {
113
- this.items?.push(item);
114
- this.isAdding = false;
115
- this.mode = 'list';
116
- this.name = '';
117
- },
118
- error: (err) => {
119
- this.errorLogger.logError(err, 'Failed to create new item');
120
- this.isAdding = false;
121
- },
122
- });
123
- }
124
- }
125
- }
@@ -1 +0,0 @@
1
- <p>2020 &copy; Sneat.team</p>
@@ -1,24 +0,0 @@
1
- import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
-
3
- import { CopyrightComponent } from './copyright.component';
4
-
5
- describe('CopyrightComponent', () => {
6
- let component: CopyrightComponent;
7
- let fixture: ComponentFixture<CopyrightComponent>;
8
-
9
- beforeEach(waitForAsync(async () => {
10
- await TestBed.configureTestingModule({
11
- imports: [CopyrightComponent],
12
- }).compileComponents();
13
- }));
14
-
15
- beforeEach(() => {
16
- fixture = TestBed.createComponent(CopyrightComponent);
17
- component = fixture.componentInstance;
18
- fixture.detectChanges();
19
- });
20
-
21
- it('should create', () => {
22
- expect(component).toBeTruthy();
23
- });
24
- });
@@ -1,7 +0,0 @@
1
- import { Component } from '@angular/core';
2
-
3
- @Component({
4
- selector: 'sneat-copyright',
5
- templateUrl: './copyright.component.html',
6
- })
7
- export class CopyrightComponent {}
@@ -1,33 +0,0 @@
1
- <ion-item class="sneat-tiny-end-padding" lines="none">
2
- <ion-select
3
- interface="popover"
4
- [label]="label"
5
- [(ngModel)]="countryID"
6
- (ionChange)="onCountryChanged()"
7
- >
8
- <ion-select-option value="">All</ion-select-option>
9
- @for (c of countries(); track c.id) {
10
- <ion-select-option [value]="c.id">
11
- {{ c.title }} {{ c.emoji }}
12
- </ion-select-option>
13
- }
14
- </ion-select>
15
- @if (countryID && canReset) {
16
- <ion-buttons slot="end">
17
- <ion-button color="medium" (click)="reset($event)">
18
- <ion-icon name="close-outline" />
19
- </ion-button>
20
- </ion-buttons>
21
- }
22
- <!-- disable for now as select is showing incorrectyl and lookup us not linked-->
23
- <!-- <ion-buttons slot="end" class="ion-no-margin ion-no-padding">-->
24
- <!-- <ion-button *ngIf="canReset && countryID"-->
25
- <!-- color="medium"-->
26
- <!-- (click)="reset($event)" [disabled]="!canReset || !countryID">-->
27
- <!-- <ion-icon name="close-outline"></ion-icon>-->
28
- <!-- </ion-button>-->
29
- <!-- <ion-button (click)="openCountrySelector($event)">-->
30
- <!-- <ion-label>...</ion-label>-->
31
- <!-- </ion-button>-->
32
- <!-- </ion-buttons>-->
33
- </ion-item>
@@ -1,84 +0,0 @@
1
- import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2
- import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
3
- import { CountryInputComponent } from './country-input.component';
4
- import { CountriesLoaderService } from '../country-selector';
5
-
6
- describe('CountryInputComponent', () => {
7
- let component: CountryInputComponent;
8
- let fixture: ComponentFixture<CountryInputComponent>;
9
- let countriesLoader: { getCountries: ReturnType<typeof vi.fn> };
10
-
11
- const mockCountries = [
12
- { id: 'US', emoji: 'πŸ‡ΊπŸ‡Έ', title: 'United States' },
13
- { id: 'UA', emoji: 'πŸ‡ΊπŸ‡¦', title: 'Ukraine' },
14
- ];
15
-
16
- beforeEach(waitForAsync(async () => {
17
- countriesLoader = {
18
- getCountries: vi.fn().mockResolvedValue(mockCountries),
19
- };
20
-
21
- await TestBed.configureTestingModule({
22
- imports: [CountryInputComponent],
23
- providers: [
24
- {
25
- provide: CountriesLoaderService,
26
- useValue: countriesLoader,
27
- },
28
- ],
29
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
30
- })
31
- .overrideComponent(CountryInputComponent, {
32
- set: { imports: [], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: '' },
33
- })
34
- .compileComponents();
35
- fixture = TestBed.createComponent(CountryInputComponent);
36
- component = fixture.componentInstance;
37
- }));
38
-
39
- it('should create', () => {
40
- expect(component).toBeTruthy();
41
- });
42
-
43
- it('should initialize with default values', () => {
44
- expect(component.canReset).toBe(true);
45
- expect(component.label).toBe('Country');
46
- expect(component.countryID).toBe('');
47
- });
48
-
49
- it('should load countries on init', async () => {
50
- await component.ngOnInit();
51
- expect(countriesLoader.getCountries).toHaveBeenCalled();
52
- // Wait for promise to resolve
53
- await Promise.resolve();
54
- expect(component.countries()).toEqual(mockCountries);
55
- });
56
-
57
- it('should emit countryIDChange when onCountryChanged is called', () => {
58
- const emitSpy = vi.fn();
59
- component.countryIDChange.subscribe(emitSpy);
60
- component.countryID = 'US';
61
-
62
- component.onCountryChanged();
63
-
64
- expect(emitSpy).toHaveBeenCalledWith('US');
65
- });
66
-
67
- it('should reset countryID and emit when reset is called', () => {
68
- const emitSpy = vi.fn();
69
- component.countryIDChange.subscribe(emitSpy);
70
- component.countryID = 'US';
71
-
72
- const mockEvent = {
73
- preventDefault: vi.fn(),
74
- stopPropagation: vi.fn(),
75
- } as unknown as Event;
76
-
77
- component.reset(mockEvent);
78
-
79
- expect(mockEvent.preventDefault).toHaveBeenCalled();
80
- expect(mockEvent.stopPropagation).toHaveBeenCalled();
81
- expect(component.countryID).toBe('');
82
- expect(emitSpy).toHaveBeenCalledWith('');
83
- });
84
- });
@@ -1,76 +0,0 @@
1
- import {
2
- Component,
3
- EventEmitter,
4
- inject,
5
- Input,
6
- OnInit,
7
- Output,
8
- signal,
9
- } from '@angular/core';
10
- import { FormsModule } from '@angular/forms';
11
- import {
12
- IonButton,
13
- IonButtons,
14
- IonIcon,
15
- IonItem,
16
- IonSelect,
17
- IonSelectOption,
18
- } from '@ionic/angular/standalone';
19
- import { ICountry, CountriesLoaderService } from '../country-selector';
20
-
21
- @Component({
22
- selector: 'sneat-country-input',
23
- templateUrl: './country-input.component.html',
24
- imports: [
25
- FormsModule,
26
- IonItem,
27
- IonSelect,
28
- IonSelectOption,
29
- IonButtons,
30
- IonButton,
31
- IonIcon,
32
- ],
33
- })
34
- export class CountryInputComponent implements OnInit {
35
- private readonly countriesLoader = inject(CountriesLoaderService);
36
-
37
- @Input() canReset = true;
38
- @Input() label = 'Country';
39
- @Input() countryID = '';
40
- @Output() countryIDChange = new EventEmitter<string>();
41
-
42
- readonly countries = signal<readonly ICountry[]>([]);
43
-
44
- ngOnInit(): void {
45
- // Load countries data
46
- this.countriesLoader.getCountries().then((countries) => {
47
- this.countries.set(countries);
48
- });
49
- }
50
-
51
- // constructor(
52
- // // private readonly countrySelectorService: CountrySelectorService,
53
- // ) {
54
- // }
55
-
56
- public onCountryChanged(): void {
57
- // console.log('CountryInputComponent.onCountryChanged()', this.countryID);
58
- this.countryIDChange.emit(this.countryID);
59
- }
60
-
61
- reset(event: Event): void {
62
- event.preventDefault();
63
- event.stopPropagation();
64
- this.countryID = '';
65
- this.countryIDChange.emit('');
66
- }
67
-
68
- // protected openCountrySelector(): void {
69
- // // const options: ISelectorOptions<ICountry> = {
70
- // // items: of(countries),
71
- // // };
72
- // // this.countrySelectorService
73
- // // .selectSingleInModal(options)
74
- // // .then();
75
- // }
76
- }