@sneat/core 0.1.3 → 0.1.6

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 (161) hide show
  1. package/esm2022/index.js +2 -0
  2. package/esm2022/index.js.map +1 -0
  3. package/esm2022/lib/analytics.interface.js +3 -0
  4. package/esm2022/lib/analytics.interface.js.map +1 -0
  5. package/esm2022/lib/animations/form-animations.js +8 -0
  6. package/esm2022/lib/animations/form-animations.js.map +1 -0
  7. package/esm2022/lib/animations/index.js +3 -0
  8. package/esm2022/lib/animations/index.js.map +1 -0
  9. package/esm2022/lib/animations/list-animations.js +29 -0
  10. package/esm2022/lib/animations/list-animations.js.map +1 -0
  11. package/esm2022/lib/app.service.js +3 -0
  12. package/esm2022/lib/app.service.js.map +1 -0
  13. package/esm2022/lib/core-models.js +2 -0
  14. package/esm2022/lib/core-models.js.map +1 -0
  15. package/esm2022/lib/directives/index.js +2 -0
  16. package/esm2022/lib/directives/index.js.map +1 -0
  17. package/esm2022/lib/directives/sneat-select-all-on-focus.directive.js +42 -0
  18. package/esm2022/lib/directives/sneat-select-all-on-focus.directive.js.map +1 -0
  19. package/esm2022/lib/environment-config.js +4 -0
  20. package/esm2022/lib/environment-config.js.map +1 -0
  21. package/esm2022/lib/eq.js +2 -0
  22. package/esm2022/lib/eq.js.map +1 -0
  23. package/esm2022/lib/exclude-undefined.js +43 -0
  24. package/esm2022/lib/exclude-undefined.js.map +1 -0
  25. package/esm2022/lib/form-field.js +2 -0
  26. package/esm2022/lib/form-field.js.map +1 -0
  27. package/esm2022/lib/index.js +22 -0
  28. package/esm2022/lib/index.js.map +1 -0
  29. package/esm2022/lib/interfaces.js +11 -0
  30. package/esm2022/lib/interfaces.js.map +1 -0
  31. package/esm2022/lib/location-href.js +6 -0
  32. package/esm2022/lib/location-href.js.map +1 -0
  33. package/esm2022/lib/logging/interfaces.js +3 -0
  34. package/esm2022/lib/logging/interfaces.js.map +1 -0
  35. package/esm2022/lib/logging.js +16 -0
  36. package/esm2022/lib/logging.js.map +1 -0
  37. package/esm2022/lib/nav/index.js +3 -0
  38. package/esm2022/lib/nav/index.js.map +1 -0
  39. package/esm2022/lib/nav/nav-context.js +7 -0
  40. package/esm2022/lib/nav/nav-context.js.map +1 -0
  41. package/esm2022/lib/nav/routing-state.js +29 -0
  42. package/esm2022/lib/nav/routing-state.js.map +1 -0
  43. package/esm2022/lib/services/index.js +4 -0
  44. package/esm2022/lib/services/index.js.map +1 -0
  45. package/esm2022/lib/services/ng-module-preloader.service.js +108 -0
  46. package/esm2022/lib/services/ng-module-preloader.service.js.map +1 -0
  47. package/esm2022/lib/services/sneat-nav.service.js +41 -0
  48. package/esm2022/lib/services/sneat-nav.service.js.map +1 -0
  49. package/esm2022/lib/services/top-menu.service.js +25 -0
  50. package/esm2022/lib/services/top-menu.service.js.map +1 -0
  51. package/esm2022/lib/sneat-enum-keys.js +2 -0
  52. package/esm2022/lib/sneat-enum-keys.js.map +1 -0
  53. package/esm2022/lib/sneat-extensions.js +38 -0
  54. package/esm2022/lib/sneat-extensions.js.map +1 -0
  55. package/esm2022/lib/store.js +42 -0
  56. package/esm2022/lib/store.js.map +1 -0
  57. package/esm2022/lib/team-type.js +2 -0
  58. package/esm2022/lib/team-type.js.map +1 -0
  59. package/esm2022/lib/types/age-group.js +2 -0
  60. package/esm2022/lib/types/age-group.js.map +1 -0
  61. package/{src/lib/types/gender.ts → esm2022/lib/types/gender.js} +1 -7
  62. package/esm2022/lib/types/gender.js.map +1 -0
  63. package/esm2022/lib/types/index.js +3 -0
  64. package/esm2022/lib/types/index.js.map +1 -0
  65. package/esm2022/lib/utils/datetimes.js +39 -0
  66. package/esm2022/lib/utils/datetimes.js.map +1 -0
  67. package/esm2022/lib/utils/index.js +2 -0
  68. package/esm2022/lib/utils/index.js.map +1 -0
  69. package/esm2022/sneat-core.js +5 -0
  70. package/esm2022/sneat-core.js.map +1 -0
  71. package/lib/analytics.interface.d.ts +12 -0
  72. package/lib/animations/form-animations.d.ts +1 -0
  73. package/lib/animations/list-animations.d.ts +3 -0
  74. package/lib/app.service.d.ts +9 -0
  75. package/{src/lib/core-models.ts → lib/core-models.d.ts} +4 -6
  76. package/lib/directives/sneat-select-all-on-focus.directive.d.ts +7 -0
  77. package/lib/environment-config.d.ts +37 -0
  78. package/lib/eq.d.ts +1 -0
  79. package/lib/exclude-undefined.d.ts +6 -0
  80. package/lib/form-field.d.ts +4 -0
  81. package/lib/interfaces.d.ts +53 -0
  82. package/lib/location-href.d.ts +1 -0
  83. package/lib/logging/interfaces.d.ts +12 -0
  84. package/lib/logging.d.ts +12 -0
  85. package/lib/nav/nav-context.d.ts +4 -0
  86. package/lib/nav/routing-state.d.ts +8 -0
  87. package/lib/services/ng-module-preloader.service.d.ts +18 -0
  88. package/lib/services/sneat-nav.service.d.ts +12 -0
  89. package/lib/services/top-menu.service.d.ts +10 -0
  90. package/lib/sneat-enum-keys.d.ts +1 -0
  91. package/lib/sneat-extensions.d.ts +7 -0
  92. package/lib/store.d.ts +14 -0
  93. package/lib/team-type.d.ts +2 -0
  94. package/lib/types/gender.d.ts +6 -0
  95. package/lib/utils/datetimes.d.ts +7 -0
  96. package/package.json +14 -2
  97. package/sneat-core.d.ts +5 -0
  98. package/tsconfig.lib.prod.tsbuildinfo +1 -0
  99. package/eslint.config.js +0 -7
  100. package/ng-package.json +0 -7
  101. package/project.json +0 -38
  102. package/src/lib/analytics.interface.ts +0 -34
  103. package/src/lib/animations/form-animations.spec.ts +0 -26
  104. package/src/lib/animations/form-animations.ts +0 -11
  105. package/src/lib/animations/list-animations.spec.ts +0 -50
  106. package/src/lib/animations/list-animations.ts +0 -44
  107. package/src/lib/app.service.ts +0 -33
  108. package/src/lib/constants.spec.ts +0 -20
  109. package/src/lib/constants.ts +0 -1
  110. package/src/lib/directives/sneat-select-all-on-focus.directive.spec.ts +0 -142
  111. package/src/lib/directives/sneat-select-all-on-focus.directive.ts +0 -36
  112. package/src/lib/environment-config.ts +0 -54
  113. package/src/lib/eq.spec.ts +0 -24
  114. package/src/lib/eq.ts +0 -1
  115. package/src/lib/exclude-undefined.spec.ts +0 -165
  116. package/src/lib/exclude-undefined.ts +0 -47
  117. package/src/lib/form-field.ts +0 -5
  118. package/src/lib/interfaces.spec.ts +0 -116
  119. package/src/lib/interfaces.ts +0 -85
  120. package/src/lib/location-href.spec.ts +0 -53
  121. package/src/lib/location-href.ts +0 -9
  122. package/src/lib/logging/interfaces.ts +0 -19
  123. package/src/lib/logging.spec.ts +0 -132
  124. package/src/lib/logging.ts +0 -33
  125. package/src/lib/nav/nav-context.ts +0 -16
  126. package/src/lib/nav/routing-state.spec.ts +0 -65
  127. package/src/lib/nav/routing-state.ts +0 -26
  128. package/src/lib/services/ng-module-preloader.service.spec.ts +0 -72
  129. package/src/lib/services/ng-module-preloader.service.ts +0 -125
  130. package/src/lib/services/sneat-nav.service.spec.ts +0 -95
  131. package/src/lib/services/sneat-nav.service.ts +0 -46
  132. package/src/lib/services/top-menu.service.spec.ts +0 -42
  133. package/src/lib/services/top-menu.service.ts +0 -19
  134. package/src/lib/sneat-enum-keys.ts +0 -2
  135. package/src/lib/sneat-extensions.spec.ts +0 -127
  136. package/src/lib/sneat-extensions.ts +0 -49
  137. package/src/lib/store.spec.ts +0 -156
  138. package/src/lib/store.ts +0 -54
  139. package/src/lib/team-type.spec.ts +0 -8
  140. package/src/lib/team-type.ts +0 -13
  141. package/src/lib/testing/base-test-setup.ts +0 -247
  142. package/src/lib/testing/test-setup-light.ts +0 -1
  143. package/src/lib/testing/test-setup.ts +0 -70
  144. package/src/lib/types/gender.spec.ts +0 -42
  145. package/src/lib/utils/datetimes.spec.ts +0 -144
  146. package/src/lib/utils/datetimes.ts +0 -51
  147. package/src/test-setup.ts +0 -3
  148. package/tsconfig.json +0 -13
  149. package/tsconfig.lib.json +0 -19
  150. package/tsconfig.lib.prod.json +0 -7
  151. package/tsconfig.spec.json +0 -31
  152. package/vite.config.mts +0 -10
  153. /package/{src/index.ts → index.d.ts} +0 -0
  154. /package/{src/lib/animations/index.ts → lib/animations/index.d.ts} +0 -0
  155. /package/{src/lib/directives/index.ts → lib/directives/index.d.ts} +0 -0
  156. /package/{src/lib/index.ts → lib/index.d.ts} +0 -0
  157. /package/{src/lib/nav/index.ts → lib/nav/index.d.ts} +0 -0
  158. /package/{src/lib/services/index.ts → lib/services/index.d.ts} +0 -0
  159. /package/{src/lib/types/age-group.ts → lib/types/age-group.d.ts} +0 -0
  160. /package/{src/lib/types/index.ts → lib/types/index.d.ts} +0 -0
  161. /package/{src/lib/utils/index.ts → lib/utils/index.d.ts} +0 -0
@@ -1,65 +0,0 @@
1
- import { TestBed } from '@angular/core/testing';
2
- import { NavigationEnd, Router, Event } from '@angular/router';
3
- import { Subject } from 'rxjs';
4
- import { RoutingState } from './routing-state';
5
-
6
- describe('RoutingState', () => {
7
- let eventsSubject: Subject<Event>;
8
-
9
- beforeEach(() => {
10
- eventsSubject = new Subject();
11
- TestBed.configureTestingModule({
12
- providers: [
13
- RoutingState,
14
- {
15
- provide: Router,
16
- useValue: { events: eventsSubject },
17
- },
18
- ],
19
- });
20
- });
21
-
22
- it('should be created', () => {
23
- const service = TestBed.inject(RoutingState);
24
- expect(service).toBeTruthy();
25
- });
26
-
27
- it('should return false when no history exists', () => {
28
- const service = TestBed.inject(RoutingState);
29
- expect(service.hasHistory()).toBe(false);
30
- });
31
-
32
- it('should return false after one navigation', () => {
33
- const service = TestBed.inject(RoutingState);
34
- const navEnd = new NavigationEnd(1, '/home', '/home');
35
- eventsSubject.next(navEnd);
36
- expect(service.hasHistory()).toBe(false);
37
- });
38
-
39
- it('should return true after two navigations', () => {
40
- const service = TestBed.inject(RoutingState);
41
-
42
- const navEnd1 = new NavigationEnd(1, '/home', '/home');
43
- eventsSubject.next(navEnd1);
44
-
45
- const navEnd2 = new NavigationEnd(2, '/about', '/about');
46
- eventsSubject.next(navEnd2);
47
-
48
- expect(service.hasHistory()).toBe(true);
49
- });
50
-
51
- it('should handle multiple navigations', () => {
52
- const service = TestBed.inject(RoutingState);
53
-
54
- const navEnd1 = new NavigationEnd(1, '/home', '/home');
55
- eventsSubject.next(navEnd1);
56
-
57
- const navEnd2 = new NavigationEnd(2, '/about', '/about');
58
- eventsSubject.next(navEnd2);
59
-
60
- const navEnd3 = new NavigationEnd(3, '/contact', '/contact');
61
- eventsSubject.next(navEnd3);
62
-
63
- expect(service.hasHistory()).toBe(true);
64
- });
65
- });
@@ -1,26 +0,0 @@
1
- import { Injectable, inject } from '@angular/core';
2
- import { NavigationEnd, Router } from '@angular/router';
3
-
4
- @Injectable({ providedIn: 'root' })
5
- export class RoutingState {
6
- private history: string[] = [];
7
-
8
- constructor() {
9
- const router = inject(Router);
10
-
11
- router.events.subscribe({
12
- next: (event) => {
13
- if (event instanceof NavigationEnd) {
14
- this.history = [...this.history, event.urlAfterRedirects];
15
- if (this.history.length > 2) {
16
- this.history.slice(this.history.length - 2, this.history.length);
17
- }
18
- }
19
- },
20
- });
21
- }
22
-
23
- public hasHistory(): boolean {
24
- return this.history.length > 1;
25
- }
26
- }
@@ -1,72 +0,0 @@
1
- import { TestBed } from '@angular/core/testing';
2
- // import { describe, beforeEach, it, expect } from 'vitest';
3
-
4
- import { NgModulePreloaderService } from './ng-module-preloader.service';
5
-
6
- describe('NgModulePreloaderService', () => {
7
- beforeEach(() => TestBed.configureTestingModule({}));
8
-
9
- it('should be created', () => {
10
- const service: NgModulePreloaderService = TestBed.inject(
11
- NgModulePreloaderService,
12
- );
13
- expect(service).toBeTruthy();
14
- });
15
-
16
- it('should add preload configs', () => {
17
- const service: NgModulePreloaderService = TestBed.inject(
18
- NgModulePreloaderService,
19
- );
20
- class MockModule {}
21
- service.addPreloadConfigs({
22
- id: 'test',
23
- path: 'path/to/test',
24
- type: MockModule,
25
- });
26
- // @ts-expect-error accessing private property for testing
27
- expect(service.configs['test']).toEqual({
28
- path: 'path/to/test',
29
- type: MockModule,
30
- });
31
- });
32
-
33
- it('should mark as preloaded', () => {
34
- const service: NgModulePreloaderService = TestBed.inject(
35
- NgModulePreloaderService,
36
- );
37
- service.markAsPreloaded('test-path');
38
- // @ts-expect-error accessing private property for testing
39
- expect(service.preloaded).toContain('test-path');
40
- });
41
-
42
- it('should warn when preload is called', () => {
43
- const service: NgModulePreloaderService = TestBed.inject(
44
- NgModulePreloaderService,
45
- );
46
- const warnSpy = vi
47
- .spyOn(console, 'warn')
48
- .mockImplementation(() => undefined);
49
- service.preload(['path1']);
50
- expect(warnSpy).toHaveBeenCalledWith(
51
- expect.stringContaining('Preloading is disabled'),
52
- );
53
- warnSpy.mockRestore();
54
- });
55
-
56
- it('should only warn once when preload is called multiple times', () => {
57
- const service: NgModulePreloaderService = TestBed.inject(
58
- NgModulePreloaderService,
59
- );
60
- const warnSpy = vi
61
- .spyOn(console, 'warn')
62
- .mockImplementation(() => undefined);
63
-
64
- service.preload(['path1']);
65
- service.preload(['path2']);
66
- service.preload(['path3']);
67
-
68
- // Should only warn once
69
- expect(warnSpy).toHaveBeenCalledTimes(1);
70
- warnSpy.mockRestore();
71
- });
72
- });
@@ -1,125 +0,0 @@
1
- import { Injectable, Type } from '@angular/core';
2
-
3
- export type PreloadPages =
4
- | 'assets'
5
- | 'contacts'
6
- | 'members'
7
- | 'real-estates'
8
- | 'budget';
9
-
10
- @Injectable({
11
- providedIn: 'root',
12
- })
13
- export class NgModulePreloaderService {
14
- private readonly preloaded: string[] = [];
15
-
16
- /*
17
- 'applicants': './pages/commune/contact/contacts/commune-contacts.page.module#CommuneContactsPageModule',
18
- 'assets': './pages/commune/asset/assets/assets.module#AssetsPageModule',
19
- 'commune-overview': './pages/commune/overview/commune-overview.module#CommuneOverviewPageModule',
20
- 'bills': '',
21
- 'budget': './pages/commune/budget/budget.module#BudgetPageModule',
22
- 'staff': './pages/commune/members/staff/staff.module#StaffPageModule',
23
- 'member': './pages/commune/member/member/commune-member.module#CommuneMemberPageModule',
24
- 'member-new': './pages/commune/member/member-new/member-new.module#MemberNewPageModule',
25
- 'members': './pages/commune/members/members/commune-members.module#CommuneMembersPageModule',
26
- 'group': './pages/commune/member-group/member-group/member-group.module#MemberGrpupPageModule',
27
- 'group-new': './pages/commune/member-group/member-group-new/member-group-new.module#MemberGroupNewPageModule',
28
- 'groups': './pages/commune/member-group/member-groups/member-groups.module#MemberGroupsPageModule',
29
- 'contact': './pages/commune/contact/contact/commune-contact.module#CommuneContactPageModule',
30
- 'contact-new': './pages/commune/contact/contact-new/contact-new.module#ContactNewPageModule',
31
- 'contacts': './pages/commune/contact/contacts/commune-contacts.page.module#CommuneContactsPageModule',
32
- 'document': './pages/commune/document/document/commune-document.module#CommuneDocumentPageModule',
33
- 'document-new': './pages/commune/document/document-new/document-new.module#DocumentNewPageModule',
34
- 'documents': './pages/commune/document/documents/commune-documents.module#CommuneDocumentsPageModule',
35
- 'landlords': './pages/commune/contact/contacts/commune-contacts.page.module#CommuneContactsPageModule',
36
- 'lists': './shared/listus/commune/list/lists/lists.module#ListsPageModule',
37
- 'pupils': './pages/commune/members/pupils/pupils.module#PupilsPageModule',
38
- 'real-estates': './pages/commune/asset/real-estate/real-estate.module#RealEstatePageModule',
39
- 'schedule': './pages/commune/calendar/schedule/schedule-page.module#SchedulePageModule',
40
- 'tenants': './pages/commune/contact/contacts/commune-contacts.page.module#CommuneContactsPageModule',
41
- 'terms': './pages/commune/term/terms/terms.module#TermsPageModule',
42
- 'tasks': './pages/commune/todo/tasks/tasks-page.module#TasksPageModule',
43
- */
44
- private readonly configs: Record<
45
- string,
46
- { path: string; type: Type<unknown> }
47
- > = {}; // Use addPreloadConfigs
48
-
49
- private warned = false;
50
-
51
- /*
52
- * https://blog.angularindepth.com/as-busy-as-a-bee-lazy-loading-in-the-angular-cli-d2812141637f
53
- * https://blog.angularindepth.com/here-is-what-you-need-to-know-about-dynamic-components-in-angular-ac1e96167f9e
54
- */
55
- // constructor(
56
- // // private readonly injector: Injector,
57
- // // private loader: NgModuleFactoryLoader,
58
- // ) {
59
- // }
60
-
61
- public addPreloadConfigs(
62
- ...configs: {
63
- id: string;
64
- path: string;
65
- type: Type<unknown>;
66
- module?: string;
67
- }[]
68
- ): void {
69
- configs.forEach((config) => {
70
- this.configs[config.id] = { path: config.path, type: config.type };
71
- });
72
- }
73
-
74
- public markAsPreloaded(path: string): void {
75
- this.preloaded.push(path);
76
- }
77
-
78
- public preload(paths: string[], ms = 1000): void {
79
- if (!this.warned) {
80
- this.warned = true;
81
- console.warn(
82
- `Preloading is disabled until migrated to Ivy (delay=${ms}ms)`,
83
- );
84
- }
85
- return; // TODO: Enable preloading once migrated to Angular Ivy
86
- // setTimeout(
87
- // () => {
88
- // paths = paths.filter(p => !this.preloaded.includes(p));
89
- // if (!paths.length) {
90
- // return;
91
- // }
92
- // console.log('preloading:', paths);
93
- // paths.forEach(p => {
94
- // if (this.preloaded.includes(p)) {
95
- // return;
96
- // }
97
- // const config = this.configs[p];
98
- // if (!config) {
99
- // console.error('Unknown preload id:', p);
100
- // return;
101
- // }
102
- // this.loader.load(config.path)
103
- // .then((factory) => {
104
- // console.log('preloaded:', factory);
105
- // this.preloaded.push(p);
106
- // if (config.type) {
107
- // try {
108
- // const module = factory.create(this.injector);
109
- // const cf = module.componentFactoryResolver.resolveComponentFactory(config.type);
110
- // const cr = cf.create(this.injector);
111
- // cr.destroy();
112
- // } catch (e) {
113
- // console.error(`Failed to create or destroy preloaded component ${config.path}:`, e);
114
- // }
115
- // }
116
- // })
117
- // .catch(err => {
118
- // console.error('Failed to preload NG module:', err);
119
- // });
120
- // });
121
- // },
122
- // ms,
123
- // );
124
- }
125
- }
@@ -1,95 +0,0 @@
1
- import { TestBed } from '@angular/core/testing';
2
- import { NavigationEnd, Router, Event } from '@angular/router';
3
- import { Location } from '@angular/common';
4
- import { NavController } from '@ionic/angular/standalone';
5
- import { Subject } from 'rxjs';
6
- import { SneatNavService } from './sneat-nav.service';
7
-
8
- describe('SneatNavService', () => {
9
- beforeEach(() => {
10
- TestBed.configureTestingModule({
11
- providers: [
12
- SneatNavService,
13
- {
14
- provide: Router,
15
- useValue: { events: new Subject() },
16
- },
17
- { provide: Location, useValue: { back: vi.fn() } },
18
- { provide: NavController, useValue: { pop: vi.fn() } },
19
- ],
20
- });
21
- });
22
-
23
- it('should be created', () => {
24
- expect(TestBed.inject(SneatNavService)).toBeTruthy();
25
- });
26
-
27
- it('should navigateByUrl when no previous page exists', () => {
28
- const service = TestBed.inject(SneatNavService);
29
- const router = TestBed.inject(Router);
30
- router.navigateByUrl = vi.fn().mockReturnValue(Promise.resolve(true));
31
-
32
- service.goBack('/home');
33
-
34
- expect(router.navigateByUrl).toHaveBeenCalledWith('/home', undefined);
35
- });
36
-
37
- it('should call navController.pop when previous page exists', async () => {
38
- const router = TestBed.inject(Router);
39
- const eventsSubject = router.events as Subject<Event>;
40
- const service = TestBed.inject(SneatNavService);
41
-
42
- // Simulate navigation end
43
- const navEnd = new NavigationEnd(1, '/prev', '/prev');
44
- eventsSubject.next(navEnd);
45
-
46
- const navController = TestBed.inject(NavController);
47
- navController.pop = vi.fn().mockReturnValue(Promise.resolve(true));
48
-
49
- service.goBack('/home');
50
-
51
- expect(navController.pop).toHaveBeenCalled();
52
- });
53
-
54
- it('should call location.back when navController.pop fails', async () => {
55
- const router = TestBed.inject(Router);
56
- const eventsSubject = router.events as Subject<Event>;
57
- const service = TestBed.inject(SneatNavService);
58
-
59
- // Simulate navigation end
60
- const navEnd = new NavigationEnd(1, '/prev', '/prev');
61
- eventsSubject.next(navEnd);
62
-
63
- const navController = TestBed.inject(NavController);
64
- navController.pop = vi.fn().mockReturnValue(Promise.resolve(false));
65
- const location = TestBed.inject(Location);
66
-
67
- service.goBack('/home');
68
-
69
- // Wait for promise
70
- await new Promise((resolve) => setTimeout(resolve, 0));
71
-
72
- expect(location.back).toHaveBeenCalled();
73
- });
74
-
75
- it('should handle navigation error when no previous page exists', async () => {
76
- const service = TestBed.inject(SneatNavService);
77
- const router = TestBed.inject(Router);
78
- const consoleErrorSpy = vi
79
- .spyOn(console, 'error')
80
- .mockImplementation(() => undefined);
81
- const error = new Error('Navigation failed');
82
- router.navigateByUrl = vi.fn().mockReturnValue(Promise.reject(error));
83
-
84
- service.goBack('/home');
85
-
86
- // Wait for promise to reject
87
- await new Promise((resolve) => setTimeout(resolve, 0));
88
-
89
- expect(consoleErrorSpy).toHaveBeenCalledWith(
90
- 'SneatNavService.goBack() - failed to navigate',
91
- error,
92
- );
93
- consoleErrorSpy.mockRestore();
94
- });
95
- });
@@ -1,46 +0,0 @@
1
- import { Location } from '@angular/common';
2
- import { Injectable, inject } from '@angular/core';
3
- import {
4
- NavigationBehaviorOptions,
5
- NavigationEnd,
6
- Router,
7
- UrlTree,
8
- } from '@angular/router';
9
- import { NavController } from '@ionic/angular/standalone';
10
-
11
- @Injectable({
12
- providedIn: 'root',
13
- })
14
- export class SneatNavService {
15
- private readonly router = inject(Router);
16
- private readonly location = inject(Location);
17
- private readonly navController = inject(NavController);
18
-
19
- private previous?: NavigationEnd;
20
-
21
- constructor() {
22
- const router = this.router;
23
-
24
- router.events.subscribe((event) => {
25
- if (event instanceof NavigationEnd) {
26
- this.previous = event;
27
- }
28
- });
29
- }
30
-
31
- goBack(url: string | UrlTree, extras?: NavigationBehaviorOptions): void {
32
- if (this.previous) {
33
- this.navController.pop().then((isPopped) => {
34
- if (!isPopped) {
35
- this.location.back();
36
- }
37
- });
38
- } else {
39
- this.router
40
- .navigateByUrl(url, extras)
41
- .catch((err) =>
42
- console.error('SneatNavService.goBack() - failed to navigate', err),
43
- );
44
- }
45
- }
46
- }
@@ -1,42 +0,0 @@
1
- import { TestBed } from '@angular/core/testing';
2
-
3
- import { TopMenuService } from './top-menu.service';
4
-
5
- describe('TopMenuService', () => {
6
- let service: TopMenuService;
7
-
8
- beforeEach(() => {
9
- TestBed.configureTestingModule({});
10
- service = TestBed.inject(TopMenuService);
11
- });
12
-
13
- it('should be created', () => {
14
- expect(service).toBeTruthy();
15
- });
16
-
17
- it('should update visibility when visibilityChanged is called', () => {
18
- const mockEvent = {
19
- detail: { visible: true },
20
- } as unknown as CustomEvent;
21
-
22
- let isVisible: boolean | undefined;
23
- let isHidden: boolean | undefined;
24
-
25
- service.isTopMenuVisible.subscribe((v) => (isVisible = v));
26
- service.isTopMenuHidden.subscribe((v) => (isHidden = v));
27
-
28
- service.visibilityChanged(mockEvent);
29
-
30
- expect(isVisible).toBe(true);
31
- expect(isHidden).toBe(false);
32
-
33
- const mockEventHidden = {
34
- detail: { visible: false },
35
- } as unknown as CustomEvent;
36
-
37
- service.visibilityChanged(mockEventHidden);
38
-
39
- expect(isVisible).toBe(false);
40
- expect(isHidden).toBe(true);
41
- });
42
- });
@@ -1,19 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { BehaviorSubject } from 'rxjs';
3
-
4
- @Injectable({
5
- providedIn: 'root',
6
- })
7
- export class TopMenuService {
8
- private $isTopMenuVisible = new BehaviorSubject<boolean>(false);
9
- private $isTopMenuHidden = new BehaviorSubject<boolean>(true);
10
-
11
- public readonly isTopMenuVisible = this.$isTopMenuVisible.asObservable();
12
- public readonly isTopMenuHidden = this.$isTopMenuHidden.asObservable();
13
-
14
- public readonly visibilityChanged = (event: Event): void => {
15
- const visible = !!(event as CustomEvent).detail['visible'];
16
- this.$isTopMenuVisible.next(visible);
17
- this.$isTopMenuHidden.next(!visible);
18
- };
19
- }
@@ -1,2 +0,0 @@
1
- // https://stackoverflow.com/questions/50376977/generic-type-to-get-enum-keys-as-union-string-in-typescript
2
- export type EnumAsUnionOfKeys<TEnum> = keyof TEnum;
@@ -1,127 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import {
3
- ISneatExtension,
4
- defaultFamilyExtension,
5
- defaultFamilyMemberExtensions,
6
- } from './sneat-extensions';
7
-
8
- describe('Sneat Extensions', () => {
9
- describe('defaultFamilyExtension', () => {
10
- it('should be an array', () => {
11
- expect(Array.isArray(defaultFamilyExtension)).toBe(true);
12
- });
13
-
14
- it('should have 4 extensions', () => {
15
- expect(defaultFamilyExtension).toHaveLength(4);
16
- });
17
-
18
- it('should contain assets extension', () => {
19
- const assets = defaultFamilyExtension.find((ext) => ext.id === 'assets');
20
- expect(assets).toBeDefined();
21
- expect(assets?.title).toBe('Assets');
22
- expect(assets?.emoji).toBe('🏡');
23
- });
24
-
25
- it('should contain calendarium extension', () => {
26
- const calendarium = defaultFamilyExtension.find(
27
- (ext) => ext.id === 'calendarium',
28
- );
29
- expect(calendarium).toBeDefined();
30
- expect(calendarium?.title).toBe('Calendar');
31
- expect(calendarium?.emoji).toBe('🗓️');
32
- });
33
-
34
- it('should contain documents extension', () => {
35
- const documents = defaultFamilyExtension.find(
36
- (ext) => ext.id === 'documents',
37
- );
38
- expect(documents).toBeDefined();
39
- expect(documents?.title).toBe('Documents');
40
- expect(documents?.emoji).toBe('📄');
41
- });
42
-
43
- it('should contain sizes extension', () => {
44
- const sizes = defaultFamilyExtension.find((ext) => ext.id === 'sizes');
45
- expect(sizes).toBeDefined();
46
- expect(sizes?.title).toBe('Sizes');
47
- expect(sizes?.emoji).toBe('📏');
48
- });
49
-
50
- it('should have all valid ISneatExtension objects', () => {
51
- defaultFamilyExtension.forEach((ext: ISneatExtension) => {
52
- expect(ext.id).toBeDefined();
53
- expect(typeof ext.id).toBe('string');
54
- expect(ext.title).toBeDefined();
55
- expect(typeof ext.title).toBe('string');
56
- expect(ext.emoji).toBeDefined();
57
- expect(typeof ext.emoji).toBe('string');
58
- });
59
- });
60
- });
61
-
62
- describe('defaultFamilyMemberExtensions', () => {
63
- it('should be an array', () => {
64
- expect(Array.isArray(defaultFamilyMemberExtensions)).toBe(true);
65
- });
66
-
67
- it('should have 4 extensions', () => {
68
- expect(defaultFamilyMemberExtensions).toHaveLength(4);
69
- });
70
-
71
- it('should contain assets extension', () => {
72
- const assets = defaultFamilyMemberExtensions.find(
73
- (ext) => ext.id === 'assets',
74
- );
75
- expect(assets).toBeDefined();
76
- expect(assets?.title).toBe('Assets');
77
- expect(assets?.emoji).toBe('🏡');
78
- });
79
-
80
- it('should contain calendarium extension', () => {
81
- const calendarium = defaultFamilyMemberExtensions.find(
82
- (ext) => ext.id === 'calendarium',
83
- );
84
- expect(calendarium).toBeDefined();
85
- expect(calendarium?.title).toBe('Calendar');
86
- expect(calendarium?.emoji).toBe('🗓️');
87
- });
88
-
89
- it('should contain documents extension', () => {
90
- const documents = defaultFamilyMemberExtensions.find(
91
- (ext) => ext.id === 'documents',
92
- );
93
- expect(documents).toBeDefined();
94
- expect(documents?.title).toBe('Documents');
95
- expect(documents?.emoji).toBe('📄');
96
- });
97
-
98
- it('should contain sizes extension', () => {
99
- const sizes = defaultFamilyMemberExtensions.find(
100
- (ext) => ext.id === 'sizes',
101
- );
102
- expect(sizes).toBeDefined();
103
- expect(sizes?.title).toBe('Sizes');
104
- expect(sizes?.emoji).toBe('📏');
105
- });
106
-
107
- it('should have all valid ISneatExtension objects', () => {
108
- defaultFamilyMemberExtensions.forEach((ext: ISneatExtension) => {
109
- expect(ext.id).toBeDefined();
110
- expect(typeof ext.id).toBe('string');
111
- expect(ext.title).toBeDefined();
112
- expect(typeof ext.title).toBe('string');
113
- expect(ext.emoji).toBeDefined();
114
- expect(typeof ext.emoji).toBe('string');
115
- });
116
- });
117
-
118
- it('should have same extensions as defaultFamilyExtension', () => {
119
- expect(defaultFamilyMemberExtensions.length).toBe(
120
- defaultFamilyExtension.length,
121
- );
122
- defaultFamilyExtension.forEach((ext) => {
123
- expect(defaultFamilyMemberExtensions).toContainEqual(ext);
124
- });
125
- });
126
- });
127
- });
@@ -1,49 +0,0 @@
1
- export interface ISneatExtension {
2
- id: string;
3
- title: string;
4
- emoji: string;
5
- }
6
-
7
- const assetsExtension: ISneatExtension = {
8
- id: 'assets',
9
- title: 'Assets',
10
- emoji: '🏡',
11
- };
12
-
13
- // const contactsExtension: ISneatExtension = {
14
- // id: 'contacts',
15
- // title: 'Contacts',
16
- // emoji: '📇'
17
- // }
18
-
19
- const documentsExtension: ISneatExtension = {
20
- id: 'documents',
21
- title: 'Documents',
22
- emoji: '📄',
23
- };
24
-
25
- const sizesExtension: ISneatExtension = {
26
- id: 'sizes',
27
- title: 'Sizes',
28
- emoji: '📏',
29
- };
30
-
31
- const calendariumExtension: ISneatExtension = {
32
- id: 'calendarium',
33
- title: 'Calendar',
34
- emoji: '🗓️',
35
- };
36
-
37
- export const defaultFamilyExtension: ISneatExtension[] = [
38
- assetsExtension,
39
- calendariumExtension,
40
- documentsExtension,
41
- sizesExtension,
42
- ];
43
-
44
- export const defaultFamilyMemberExtensions: ISneatExtension[] = [
45
- assetsExtension,
46
- calendariumExtension,
47
- documentsExtension,
48
- sizesExtension,
49
- ];