@yomotech/view-toolkit 0.0.31 → 0.0.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.
Files changed (72) hide show
  1. package/ng-package.json +7 -0
  2. package/package.json +38 -49
  3. package/src/lib/app-version.ts +2 -0
  4. package/src/lib/components/autocomplete/autocomplete.css +0 -0
  5. package/src/lib/components/autocomplete/autocomplete.html +23 -0
  6. package/src/lib/components/autocomplete/autocomplete.ts +71 -0
  7. package/src/lib/components/button/button.css +0 -0
  8. package/src/lib/components/button/button.html +1 -0
  9. package/src/lib/components/button/button.ts +11 -0
  10. package/src/lib/components/date/date.css +0 -0
  11. package/src/lib/components/date/date.html +1 -0
  12. package/src/lib/components/date/date.ts +11 -0
  13. package/src/lib/components/dropdown/dropdown.css +0 -0
  14. package/src/lib/components/dropdown/dropdown.html +1 -0
  15. package/src/lib/components/dropdown/dropdown.ts +11 -0
  16. package/src/lib/components/error-message/error-message.css +0 -0
  17. package/src/lib/components/error-message/error-message.html +1 -0
  18. package/src/lib/components/error-message/error-message.ts +11 -0
  19. package/src/lib/components/label/label.css +0 -0
  20. package/src/lib/components/label/label.html +7 -0
  21. package/src/lib/components/label/label.ts +33 -0
  22. package/src/lib/components/string/string.css +0 -0
  23. package/src/lib/components/string/string.html +4 -0
  24. package/src/lib/components/string/string.ts +22 -0
  25. package/src/lib/components/textbox/textbox.css +0 -0
  26. package/src/lib/components/textbox/textbox.html +7 -0
  27. package/src/lib/components/textbox/textbox.ts +33 -0
  28. package/src/lib/components/time/time.css +0 -0
  29. package/src/lib/components/time/time.html +1 -0
  30. package/src/lib/components/time/time.ts +11 -0
  31. package/src/lib/containers/card/card.component.css +0 -0
  32. package/src/lib/containers/card/card.component.html +450 -0
  33. package/src/lib/containers/card/card.component.ts +474 -0
  34. package/src/lib/containers/form/form.component.css +101 -0
  35. package/src/lib/containers/form/form.component.html +305 -0
  36. package/src/lib/containers/form/form.component.ts +333 -0
  37. package/src/lib/containers/grid/grid.component.css +0 -0
  38. package/src/lib/containers/grid/grid.component.html +212 -0
  39. package/src/lib/containers/grid/grid.component.ts +228 -0
  40. package/src/lib/containers/header-menu/header-menu.component.css +0 -0
  41. package/src/lib/containers/header-menu/header-menu.component.html +72 -0
  42. package/src/lib/containers/header-menu/header-menu.component.ts +105 -0
  43. package/src/lib/containers/logs/logs.component.css +160 -0
  44. package/src/lib/containers/logs/logs.component.html +89 -0
  45. package/src/lib/containers/logs/logs.component.ts +29 -0
  46. package/src/lib/containers/model/model.component.css +0 -0
  47. package/src/lib/containers/model/model.component.html +351 -0
  48. package/src/lib/containers/model/model.component.ts +436 -0
  49. package/src/lib/containers/pagination/pagination.component.css +0 -0
  50. package/src/lib/containers/pagination/pagination.component.html +41 -0
  51. package/src/lib/containers/pagination/pagination.component.ts +100 -0
  52. package/src/lib/containers/side-menu/side-menu.component.css +173 -0
  53. package/src/lib/containers/side-menu/side-menu.component.html +126 -0
  54. package/src/lib/containers/side-menu/side-menu.component.ts +458 -0
  55. package/src/lib/services/app-version-reset.service.ts +59 -0
  56. package/src/lib/services/config.service.ts +144 -0
  57. package/src/lib/services/couchdb.ts +275 -0
  58. package/src/lib/services/mobile-keycloak.service.ts +116 -0
  59. package/src/lib/services/network-log.service.ts +27 -0
  60. package/src/lib/services/notification.service.ts +26 -0
  61. package/src/lib/services/request.service.ts +125 -0
  62. package/src/lib/services/utility.service.ts +600 -0
  63. package/src/lib/view-toolkit.module.ts +57 -0
  64. package/src/lib/view-toolkit.spec.ts +23 -0
  65. package/src/lib/view-toolkit.ts +15 -0
  66. package/src/public-api.ts +25 -0
  67. package/tsconfig.lib.json +17 -0
  68. package/tsconfig.lib.prod.json +11 -0
  69. package/tsconfig.spec.json +15 -0
  70. package/fesm2022/yomotech-view-toolkit.mjs +0 -3597
  71. package/fesm2022/yomotech-view-toolkit.mjs.map +0 -1
  72. package/types/yomotech-view-toolkit.d.ts +0 -648
@@ -0,0 +1,458 @@
1
+ import { Platform, PlatformModule } from '@angular/cdk/platform';
2
+ import { AfterViewInit, Component, ElementRef, EventEmitter, HostListener, Inject, Input, Output, SimpleChanges, ViewChild } from '@angular/core';
3
+ import { RequestService } from '../../services/request.service';
4
+ import { UtilityService } from '../../services/utility.service';
5
+ import { OKTA_AUTH, OktaAuthStateService } from '@okta/okta-angular';
6
+ import OktaAuth from '@okta/okta-auth-js';
7
+ import { jwtDecode } from 'jwt-decode';
8
+ import { DialogService, DynamicDialogModule } from 'primeng/dynamicdialog';
9
+ import { LogsComponent } from '../logs/logs.component';
10
+ import { NotificationService } from '../../services/notification.service';
11
+ import { Device } from '@capacitor/device';
12
+ import { de_DE, en_US, NzI18nService } from 'ng-zorro-antd/i18n';
13
+ import { MobileKeycloakService } from '../../services/mobile-keycloak.service';
14
+ import { OAuthService } from 'angular-oauth2-oidc';
15
+ import { CommonModule } from '@angular/common';
16
+ import { NzMenuModule } from 'ng-zorro-antd/menu';
17
+ import { NzIconModule } from 'ng-zorro-antd/icon';
18
+ import { NzTooltipModule } from 'ng-zorro-antd/tooltip';
19
+ import { NzButtonModule } from 'ng-zorro-antd/button';
20
+ import { Couchdb } from '../../services/couchdb';
21
+
22
+
23
+ @Component({
24
+ standalone: true,
25
+ selector: 'vl-side-menu',
26
+ templateUrl: './side-menu.component.html',
27
+ styleUrl: './side-menu.component.css',
28
+ imports: [
29
+ CommonModule,
30
+ PlatformModule,
31
+ // NG-ZORRO
32
+ NzMenuModule,
33
+ NzIconModule,
34
+ NzTooltipModule,
35
+ NzButtonModule,
36
+ // PrimeNG
37
+ DynamicDialogModule
38
+ ]
39
+ })
40
+ export class SideMenuComponent implements AfterViewInit {
41
+ isCollapsed: boolean = false;
42
+ isMobile: boolean = false;
43
+ projectsLayoutSchema: any;
44
+ loginUser: any = {};
45
+ isLogined: boolean = false;
46
+ loginedUserInfo: any = {};
47
+ menuItemsCopy: any = {};
48
+ settingMenu: any = {};
49
+ setLanguage: boolean = false;
50
+ tenantKey: any = '';
51
+ tenantName: any = '';
52
+ @Input() menuItems: any[] = [];
53
+ @Input() userInfo: any = {};
54
+ @Input() settings: any = {};
55
+ @Input() projects: any;
56
+ @Input() environment: any;
57
+ @Input() projectSeleted: any;
58
+ @Output() languageChange: EventEmitter<any> = new EventEmitter();
59
+ @Output() invokeMenu: EventEmitter<any> = new EventEmitter();
60
+ @Output() menuToggle: EventEmitter<any> = new EventEmitter();
61
+ @Output() invokeProject: EventEmitter<any> = new EventEmitter();
62
+ @Output() errorMessage: EventEmitter<any> = new EventEmitter();
63
+ @Output() deleteProject: EventEmitter<any> = new EventEmitter();
64
+
65
+ PRIME_DE = {
66
+ firstDayOfWeek: 1,
67
+ dayNames: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
68
+ dayNamesShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
69
+ dayNamesMin: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
70
+ monthNames: [
71
+ 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
72
+ 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'
73
+ ],
74
+ monthNamesShort: [
75
+ 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun',
76
+ 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'
77
+ ],
78
+ today: 'Heute',
79
+ clear: 'Löschen',
80
+ dateFormat: 'yy-mm-dd',
81
+ weekHeader: 'KW'
82
+ };
83
+
84
+ PRIME_EN = {
85
+ firstDayOfWeek: 0,
86
+ dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
87
+ dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
88
+ dayNamesMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
89
+ monthNames: [
90
+ 'January', 'February', 'March', 'April', 'May', 'June',
91
+ 'July', 'August', 'September', 'October', 'November', 'December'
92
+ ],
93
+ monthNamesShort: [
94
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
95
+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
96
+ ],
97
+ today: 'Today',
98
+ clear: 'Clear',
99
+ dateFormat: 'yy-mm-dd',
100
+ weekHeader: 'Wk'
101
+ };
102
+
103
+
104
+ @ViewChild('sideMenu', { static: true })
105
+ sideMenu!: ElementRef;
106
+
107
+ constructor(
108
+ private i18n: NzI18nService,
109
+ private mobileKeycloakService: MobileKeycloakService,
110
+ private couchdbService: Couchdb,
111
+ private oauthService: OAuthService,
112
+ private platform: Platform,
113
+ private requestService: RequestService,
114
+ private utilityService: UtilityService,
115
+ private dialogService: DialogService,
116
+ private oktaAuthService: OktaAuthStateService,
117
+ private notificationService: NotificationService,
118
+ @Inject(OKTA_AUTH) private oktaAuth: OktaAuth) { }
119
+
120
+ @HostListener('document:click', ['$event'])
121
+ onDocumentClick(event: MouseEvent) {
122
+ const path = event.composedPath() as HTMLElement[];
123
+ const clickedInsideMenu = path.some(
124
+ el => el === this.sideMenu?.nativeElement
125
+ );
126
+ const clickedToggle = path.some(
127
+ el =>
128
+ el instanceof HTMLElement &&
129
+ el.classList?.contains('side-toggle-handle')
130
+ );
131
+ if (!clickedInsideMenu && !clickedToggle && this.isMobile) {
132
+ console.log('OUTSIDE CLICK');
133
+ let btn = document.getElementById('toggle-id');
134
+ if (btn && !this.isCollapsed) {
135
+ btn.click();
136
+ }
137
+ }
138
+ }
139
+
140
+ toggleCollapsed(): void {
141
+ if (this.isMobile) {
142
+ this.isCollapsed = !this.isCollapsed;
143
+ const sideMenu = document.querySelector('.side-menu');
144
+ if (sideMenu) {
145
+ sideMenu.classList.toggle('open', !this.isCollapsed);
146
+ }
147
+ } else {
148
+ this.isCollapsed = !this.isCollapsed;
149
+ }
150
+ }
151
+
152
+ async ngOnInit() {
153
+ if (this.platform.ANDROID || this.platform.IOS) {
154
+ this.isCollapsed = true;
155
+ this.isMobile = true;
156
+ this.tenantKey = await this.utilityService.getLocalStorage('tenantKey');
157
+ this.tenantName = await this.utilityService.getLocalStorage('tenantName');
158
+ } else {
159
+ this.tenantKey = await this.utilityService.getStorage('tenantKey');
160
+ this.tenantName = await this.utilityService.getStorage('tenantName');
161
+ }
162
+ }
163
+
164
+ ngOnChanges(changes: SimpleChanges): void {
165
+ this.setLoginUser();
166
+ if (changes['menuItems'] && this.menuItems?.length) {
167
+ this.menuItemsCopy = JSON.parse(JSON.stringify(this.menuItems));
168
+ this.setProjectSetting();
169
+ this.setSettingImages();
170
+ }
171
+ }
172
+
173
+ async setProjectSetting() {
174
+ const tasks: Promise<void>[] = [];
175
+ this.menuItems.forEach((menuItem: any) => {
176
+ if (menuItem?.label?.caption === "Setting" && menuItem?.submenu?.length) {
177
+ menuItem?.submenu.forEach((subMenu: any) => {
178
+ if (subMenu?.label?.caption === "Languages" && subMenu?.submenu?.length) {
179
+ subMenu?.submenu.forEach((childMenu: any) => {
180
+ tasks.push((async () => {
181
+ try {
182
+ let projectName = `${this.tenantName}_${this.projectSeleted}`
183
+ const image = await this.couchdbService.getFileContentFromCouchDb(
184
+ projectName,
185
+ childMenu.icon
186
+ );
187
+ childMenu.icon = this.getMediaSrc(image);
188
+ } catch (err) {
189
+ console.error("Failed to fetch icon:", err);
190
+ }
191
+ })());
192
+ })
193
+ }
194
+ })
195
+ }
196
+ })
197
+ await Promise.all(tasks);
198
+ }
199
+
200
+ async ngAfterViewInit(): Promise<void> {
201
+ let mobileLang = await this.getDeviceLanguage()
202
+ if (mobileLang) {
203
+ this.changeLanguage(mobileLang + '.json');
204
+ }
205
+ setTimeout(async () => {
206
+ this.initializeProjects();
207
+ await this.setLoginUser();
208
+ }, 1000);
209
+
210
+ }
211
+
212
+ async getDeviceLanguage(): Promise<string> {
213
+ const info = await Device.getLanguageCode();
214
+ return info.value; // e.g. 'en', 'ur', 'de'
215
+ }
216
+
217
+ async setLoginUser() {
218
+ try {
219
+ if (this.environment?.login?.type === 'oktaAuth') {
220
+ if (this.platform.ANDROID || this.platform.IOS) {
221
+ const logined: any = await this.utilityService.getLocalStorage('loginedUser');
222
+ if (logined?.token) {
223
+ this.requestService.getLoginUser(logined.token).subscribe({
224
+ next: (userInfo: any) => {
225
+ this.loginUser = { ...this.userInfo, ...logined };
226
+ this.setLoginedUser(this.loginUser);
227
+ },
228
+ error: (err) => {
229
+ console.error('Failed to fetch login user (mobile):', err);
230
+ }
231
+ });
232
+ }
233
+ } else {
234
+ this.oktaAuthService.authState$.subscribe({
235
+ next: async (result) => {
236
+ if (result.isAuthenticated) {
237
+ try {
238
+ const oktaWebUser = await this.oktaAuth.getUser();
239
+ const webLoginedUser = { ...this.userInfo, ...oktaWebUser };
240
+ this.loginUser = webLoginedUser;
241
+ this.setLoginedUser(this.loginUser);
242
+ } catch (err) {
243
+ console.error('Failed to fetch Okta web user:', err);
244
+ }
245
+ }
246
+ },
247
+ error: (err) => {
248
+ console.error('Okta auth state subscription error:', err);
249
+ }
250
+ });
251
+ }
252
+ } else if (this.environment?.login?.type === 'jwtToken' && this.userInfo?.jwt) {
253
+ const userInfo = this.getUserInfoFromToken(this.userInfo.jwt);
254
+ this.loginUser = userInfo;
255
+ this.setLoginedUser(this.loginUser);
256
+ } else if (this.environment?.login?.type === 'keycloak' && this.userInfo?.name) {
257
+ this.loginUser = this.userInfo;
258
+ this.setLoginedUser(this.loginUser);
259
+ }
260
+ } catch (error) {
261
+ console.error('Error in setLoginUser:', error);
262
+ }
263
+ }
264
+
265
+
266
+
267
+ getUserInfoFromToken(token: string) {
268
+ try {
269
+ const decoded: any = jwtDecode(token);
270
+
271
+ return {
272
+ sub: decoded.sub,
273
+ name: decoded.name || 'User is undefined',
274
+ role: decoded.role || 'Role is undefined',
275
+ email: decoded.email || decoded.sub,
276
+ iat: decoded.iat,
277
+ exp: decoded.exp
278
+ };
279
+ } catch (err) {
280
+ return null;
281
+ }
282
+ }
283
+
284
+ async setSettingImages() {
285
+ if (this.settings && this.settings.length > 0) {
286
+
287
+
288
+ const tasks: Promise<void>[] = [];
289
+ console.log('this.settings: ', this.settings);
290
+
291
+ for (const menu of this.settings?.submenu) {
292
+ if (menu?.submenu?.length) {
293
+ for (const childMenu of menu.submenu) {
294
+ if (childMenu.options && childMenu.options.setImageUrl) {
295
+ tasks.push((async () => {
296
+ try {
297
+ let projectName = `${this.tenantName}_${this.projectSeleted}`
298
+ const image = await this.couchdbService.getFileContentFromCouchDb(
299
+ projectName,
300
+ childMenu.icon
301
+ );
302
+ childMenu.icon = this.getMediaSrc(image);
303
+ } catch (err) {
304
+ console.error("Failed to fetch icon:", err);
305
+ }
306
+ })());
307
+ }
308
+ }
309
+ }
310
+ }
311
+ await Promise.all(tasks);
312
+ }
313
+ this.settingMenu = JSON.parse(JSON.stringify(this.settings));
314
+ }
315
+
316
+ getMediaSrc(file: any): string {
317
+ if (!file) return '';
318
+
319
+ // Best case: service already returns full data URL
320
+ if (file.src) {
321
+ return file.src;
322
+ }
323
+
324
+ // If service returns raw base64 + mimeType
325
+ if (file.base64) {
326
+ const mimeType = file.mimeType || 'image/png';
327
+ return `data:${mimeType};base64,${file.base64}`;
328
+ }
329
+
330
+ // If service returns old dataUrl format
331
+ if (file.dataUrl) {
332
+ return file.dataUrl;
333
+ }
334
+
335
+ return '';
336
+ }
337
+
338
+ isUrl(value: string): boolean {
339
+ return /^https?:\/\//.test(value) || value.startsWith('blob:');
340
+ }
341
+
342
+ async setLoginedUser(user: any) {
343
+ if (user?.name) {
344
+ user['image'] = "assets/user.png";
345
+ this.loginedUserInfo = user;
346
+ let matchMenu = this.menuItems.find((menu: any) => menu?.options?.action && menu?.options?.action === "logout");
347
+ if (matchMenu) {
348
+ this.loginedUserInfo.actions = [matchMenu]
349
+ }
350
+ this.isLogined = this.loginedUserInfo?.name ? true : false;
351
+ }
352
+ }
353
+
354
+ initializeProjects() {
355
+ this.projectsLayoutSchema = this.projects;
356
+ }
357
+
358
+ async invokeNavigate(menu: any, parentMenu?: any) {
359
+ if (menu.options.showAllProjects) {
360
+ this.utilityService.showAllProjects();
361
+ } else if (menu.options.changeLang) {
362
+ this.changeLanguage(menu.options.data_url);
363
+ } else if (menu.options.changeProject) {
364
+ this.navigateToProject(menu);
365
+ } else if (menu.options.logs) {
366
+ this.openLogsTable();
367
+ } else if (menu.options.terms) {
368
+ this.notificationService.info("Term Not Apply")
369
+ } else if (menu.options.projectPrivacy) {
370
+ this.notificationService.warning("Project Privacy Not Apply")
371
+ } else if (menu.options.projectVersion) {
372
+ this.notificationService.warning("Project Version Not Apply")
373
+ } else if (menu.options.action == 'login' && this.environment?.login?.type == "keycloak") {
374
+ if (this.platform.ANDROID || this.platform.IOS) {
375
+ let login = await this.mobileKeycloakService.login();
376
+ } else {
377
+ this.oauthService.initLoginFlow();
378
+ }
379
+ } else {
380
+ this.toggleCollapsed();
381
+ this.invokeMenu.emit(menu);
382
+ }
383
+ }
384
+
385
+ openLogsTable() {
386
+ let logsModal = this.dialogService.open(LogsComponent, {
387
+ width: '700px',
388
+ data: {}
389
+ });
390
+
391
+ // logsModal.onClose.subscribe((res: any) => {
392
+ // if (res) {
393
+ // console.log('res789: ', res);
394
+ // }
395
+ // });
396
+ }
397
+
398
+ deleteMenuItem(subChild: any, index: any, event: any) {
399
+ event.stopPropagation();
400
+ this.settings.submenu[1].submenu.splice(index, 1);
401
+ this.deleteProject.emit(subChild);
402
+ }
403
+
404
+ navigateToProject(project: any) {
405
+ this.invokeProject.emit(project);
406
+ }
407
+
408
+ async changeLanguage(lang: any) {
409
+ if (lang) {
410
+ if (lang === 'de.json') {
411
+ // NG-Zorro
412
+ this.i18n.setLocale(de_DE);
413
+ // PrimeNG 🔥
414
+ // this.primengConfig.setTranslation(this.PRIME_DE);
415
+ } else {
416
+ this.i18n.setLocale(en_US);
417
+ // this.primengConfig.setTranslation(this.PRIME_EN);
418
+ }
419
+ const selectedLanguage = await this.couchdbService.getFileContentFromCouchDb(
420
+ `${this.tenantName}_${this.projectSeleted}`,
421
+ `languages/${lang}`
422
+ );
423
+ const errorMessages = await this.couchdbService.getFileContentFromCouchDb(
424
+ `${this.tenantName}_${this.projectSeleted}`,
425
+ `languages/errorMessage_${lang}`
426
+ );
427
+ this.languageChange.emit({ selectedLanguage: selectedLanguage, errorMessages: errorMessages });
428
+ this.setLanguage = true;
429
+ this.menuItemsCopy.forEach((menu: any, index: any) => {
430
+ if (menu.label && menu.label.caption && selectedLanguage[menu.label.caption]) {
431
+ this.menuItems[index].label.caption = selectedLanguage[menu.label.caption]
432
+ }
433
+ if (menu?.submenu?.length) {
434
+ menu?.submenu.forEach((subMenuInfo: any, subIndex: any) => {
435
+ if (subMenuInfo.label && subMenuInfo.label.caption && selectedLanguage[subMenuInfo.label.caption]) {
436
+ this.menuItems[index].submenu[subIndex].label.caption = selectedLanguage[subMenuInfo.label.caption];
437
+ }
438
+ if (subMenuInfo?.submenu?.length) {
439
+ subMenuInfo.submenu.forEach((childMenu: any, childIndex: any) => {
440
+ if (childMenu.label && childMenu.label.caption && selectedLanguage[childMenu.label.caption]) {
441
+ this.menuItems[index].submenu[subIndex].submenu[childIndex].label.caption = selectedLanguage[childMenu.label.caption];
442
+ }
443
+ });
444
+ }
445
+ });
446
+ }
447
+ })
448
+ if (this.settingMenu?.label?.caption) {
449
+ this.settingMenu.label.caption = selectedLanguage[this.settings.label.caption]
450
+ }
451
+ this.settings?.submenu?.forEach((menu: any, index: any) => {
452
+ if (menu.label && menu.label.caption && selectedLanguage[menu.label.caption] && this.settingMenu?.submenu[index] && this.settingMenu.submenu[index]?.label) {
453
+ this.settingMenu.submenu[index].label.caption = selectedLanguage[menu.label.caption];
454
+ }
455
+ });
456
+ }
457
+ }
458
+ }
@@ -0,0 +1,59 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Preferences } from '@capacitor/preferences';
3
+ import { APP_VERSION } from '../app-version';
4
+ import { Platform } from '@angular/cdk/platform';
5
+
6
+ const VERSION_KEY = 'APP_VERSION';
7
+
8
+
9
+ @Injectable({
10
+ providedIn: 'root'
11
+ })
12
+ export class AppVersionResetService {
13
+
14
+ constructor(
15
+ private platform: Platform) {
16
+ }
17
+
18
+
19
+ async run(): Promise<void> {
20
+ if (this.platform.ANDROID || this.platform.IOS) {
21
+ await this.clearNativeIfChanged();
22
+ // this.clearWebIfChanged();
23
+ // return;
24
+ }
25
+ }
26
+
27
+ private async clearNativeIfChanged(): Promise<void> {
28
+ const { value: savedVersion } = await Preferences.get({ key: VERSION_KEY });
29
+ if (savedVersion === APP_VERSION) return;
30
+ console.log(`🧹 Clearing Capacitor Preferences (new build ${APP_VERSION})`);
31
+ await Preferences.clear();
32
+ this.clearWebStores();
33
+ await Preferences.set({ key: VERSION_KEY, value: APP_VERSION });
34
+ }
35
+
36
+ // private clearWebIfChanged(): void {
37
+ // const savedVersion = sessionStorage.getItem(VERSION_KEY) || localStorage.getItem(VERSION_KEY);
38
+ // if (savedVersion === APP_VERSION) return;
39
+ // this.clearWebStores();
40
+ // localStorage.setItem(VERSION_KEY, APP_VERSION);
41
+ // sessionStorage.setItem(VERSION_KEY, APP_VERSION);
42
+ // }
43
+
44
+ private clearWebStores(): void {
45
+ try { localStorage.clear(); } catch { }
46
+ try { sessionStorage.clear(); } catch { }
47
+ try {
48
+ if (typeof document !== 'undefined' && document.cookie) {
49
+ document.cookie.split(';').forEach((c) => {
50
+ const eqPos = c.indexOf('=');
51
+ const name = eqPos > -1 ? c.substring(0, eqPos).trim() : c.trim();
52
+ if (name) {
53
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
54
+ }
55
+ });
56
+ }
57
+ } catch { }
58
+ }
59
+ }
@@ -0,0 +1,144 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { UtilityService } from './utility.service';
3
+ import { Platform } from '@angular/cdk/platform';
4
+ import { Couchdb } from './couchdb';
5
+
6
+ @Injectable({
7
+ providedIn: 'root'
8
+ })
9
+ export class ConfigService {
10
+ private config: any;
11
+ private skipOkta = false;
12
+ private keycloakConfig: any;
13
+
14
+ constructor(private couchdbService: Couchdb, private utilityService: UtilityService, private platform: Platform) { }
15
+
16
+ async loadOktaConfig(projectName: string): Promise<void> {
17
+ try {
18
+ let tenantKey: any = "";
19
+ let tenantName: any = "";
20
+ if (this.platform.ANDROID || this.platform.IOS) {
21
+ tenantKey = await this.utilityService.getLocalStorage('tenantKey');
22
+ tenantName = await this.utilityService.getLocalStorage('tenantName');
23
+ } else {
24
+ tenantKey = await this.utilityService.getStorage('tenantKey');
25
+ tenantName = await this.utilityService.getStorage('tenantName');
26
+ }
27
+ if (tenantName) {
28
+ this.config = await this.couchdbService.getFileContentFromCouchDb(
29
+ `${tenantName}_${projectName}`,
30
+ 'environments/environment.json'
31
+ );
32
+ } else {
33
+ this.config = await this.couchdbService.getFileContentFromCouchDb(
34
+ `${projectName}`,
35
+ 'environments/environment.json'
36
+ );
37
+ }
38
+
39
+ if (this.platform.ANDROID || this.platform.IOS) {
40
+ if (this.config.environment.login.mobile) {
41
+ this.setConfiguration(this.config.environment.login.mobile);
42
+ } else {
43
+ this.setConfiguration(null);
44
+ }
45
+ } else {
46
+ if (this.config.environment.login.web) {
47
+ this.setConfiguration(this.config.environment.login.web);
48
+ } else {
49
+ this.setConfiguration(null);
50
+ }
51
+ }
52
+
53
+ } catch (err) {
54
+ console.error('Error loading config:', err);
55
+ }
56
+ }
57
+
58
+ setConfiguration(config: any) {
59
+ if (config) {
60
+ this.config = config;
61
+ } else {
62
+ this.config = {
63
+ issuer: 'http://dummy',
64
+ clientId: 'dummy',
65
+ redirectUri: 'http://dummy',
66
+ pkce: true,
67
+ };
68
+ }
69
+ }
70
+
71
+ skipOktaConfig() {
72
+ this.skipOkta = true;
73
+ }
74
+
75
+ get oktaConfig() {
76
+ if (this.skipOkta) {
77
+ return null;
78
+ }
79
+ return this.config;
80
+ }
81
+
82
+ async loadKeycloakConfig(projectName: string): Promise<void> {
83
+ let tenantKey: any = "";
84
+ let tenantName: any = "";
85
+ if (this.platform.ANDROID || this.platform.IOS) {
86
+ tenantKey = await this.utilityService.getLocalStorage('tenantKey');
87
+ tenantName = await this.utilityService.getLocalStorage('tenantName');
88
+ } else {
89
+ tenantKey = await this.utilityService.getStorage('tenantKey');
90
+ tenantName = await this.utilityService.getStorage('tenantName');
91
+ }
92
+ let env: any = {};
93
+ if (tenantName) {
94
+ env = await this.couchdbService.getFileContentFromCouchDb(
95
+ `${tenantName}_${projectName}`,
96
+ 'environments/environment.json'
97
+ );
98
+ } else {
99
+ env = await this.couchdbService.getFileContentFromCouchDb(
100
+ `${projectName}`,
101
+ 'environments/environment.json'
102
+ );
103
+ }
104
+ if (env?.environment?.login.type === "keycloak") {
105
+ if (this.platform.ANDROID || this.platform.IOS) {
106
+ this.keycloakConfig = {
107
+ issuer: "https://keycloak-poc.wilken.de/realms/p5",
108
+ clientId: "mobile",
109
+ redirectUri: "de.yomotech:/login/callback",
110
+ logoutRedirectUri: "de.yomotech:/login/callback",
111
+ scope: "openid profile email",
112
+ responseType: "code"
113
+ }
114
+ } else {
115
+ this.keycloakConfig = {
116
+ issuer: env?.environment?.login?.web?.issuer ?? 'http://dummy',
117
+ clientId: env?.environment?.login?.web?.clientId ?? 'dummy',
118
+ redirectUri: window.location.origin,
119
+ responseType: 'code',
120
+ scope: 'openid profile email',
121
+ showDebugInformation: true
122
+ };
123
+ }
124
+ } else {
125
+ this.keycloakConfig = {};
126
+ }
127
+ }
128
+
129
+ getKeycloakConfig() {
130
+ return this.keycloakConfig;
131
+ }
132
+
133
+ getKeycloakMobileConfig() {
134
+ if (!this.keycloakConfig) return null;
135
+ return {
136
+ issuer: this.keycloakConfig?.issuer,
137
+ clientId: this.keycloakConfig?.clientId,
138
+ redirectUri: this.keycloakConfig.redirectUri,
139
+ logoutRedirectUri: this.keycloakConfig.logoutRedirectUri,
140
+ scope: this.keycloakConfig.scope,
141
+ responseType: this.keycloakConfig.responseType
142
+ };
143
+ }
144
+ }