@yomotech/view-toolkit 0.0.3 → 0.0.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 (34) hide show
  1. package/fesm2022/yomotech-view-toolkit.mjs +1893 -0
  2. package/fesm2022/yomotech-view-toolkit.mjs.map +1 -0
  3. package/package.json +47 -36
  4. package/types/yomotech-view-toolkit.d.ts +301 -0
  5. package/ng-package.json +0 -7
  6. package/src/lib/app-version.ts +0 -2
  7. package/src/lib/containers/card/card.component.css +0 -0
  8. package/src/lib/containers/card/card.component.html +0 -449
  9. package/src/lib/containers/card/card.component.ts +0 -471
  10. package/src/lib/containers/form/form.component.css +0 -0
  11. package/src/lib/containers/form/form.component.html +0 -1
  12. package/src/lib/containers/form/form.component.ts +0 -12
  13. package/src/lib/containers/grid/grid.component.css +0 -0
  14. package/src/lib/containers/grid/grid.component.html +0 -1
  15. package/src/lib/containers/grid/grid.component.ts +0 -12
  16. package/src/lib/containers/pagination/pagination.component.css +0 -0
  17. package/src/lib/containers/pagination/pagination.component.html +0 -1
  18. package/src/lib/containers/pagination/pagination.component.ts +0 -12
  19. package/src/lib/services/app-version-reset.service.ts +0 -59
  20. package/src/lib/services/config.service.ts +0 -128
  21. package/src/lib/services/couchdb.ts +0 -224
  22. package/src/lib/services/mobile-keycloak.service.ts +0 -116
  23. package/src/lib/services/network-log.service.ts +0 -27
  24. package/src/lib/services/notification.service.ts +0 -26
  25. package/src/lib/services/pouchdb.service.ts +0 -183
  26. package/src/lib/services/request.service.ts +0 -125
  27. package/src/lib/services/utility.service.ts +0 -593
  28. package/src/lib/view-toolkit.module.ts +0 -25
  29. package/src/lib/view-toolkit.spec.ts +0 -23
  30. package/src/lib/view-toolkit.ts +0 -15
  31. package/src/public-api.ts +0 -22
  32. package/tsconfig.lib.json +0 -17
  33. package/tsconfig.lib.prod.json +0 -11
  34. package/tsconfig.spec.json +0 -15
@@ -0,0 +1,1893 @@
1
+ import * as i7 from '@angular/common';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { Component, Injectable, EventEmitter, NgZone, Output, Input, NgModule } from '@angular/core';
5
+ import * as i8 from '@angular/forms';
6
+ import { FormsModule } from '@angular/forms';
7
+ import * as i1 from '@angular/common/http';
8
+ import { HttpHeaders } from '@angular/common/http';
9
+ import { CapacitorHttp, Capacitor } from '@capacitor/core';
10
+ import * as i9 from 'ng-zorro-antd/icon';
11
+ import { NzIconModule } from 'ng-zorro-antd/icon';
12
+ import * as i11 from 'ng-zorro-antd/button';
13
+ import { NzButtonModule } from 'ng-zorro-antd/button';
14
+ import * as i14 from 'ng-zorro-antd/date-picker';
15
+ import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
16
+ import * as i4 from 'ng-zorro-antd/modal';
17
+ import { NzModalModule } from 'ng-zorro-antd/modal';
18
+ import * as i10 from 'primeng/datepicker';
19
+ import { DatePickerModule } from 'primeng/datepicker';
20
+ import { Preferences } from '@capacitor/preferences';
21
+ import { loadStripe } from '@stripe/stripe-js';
22
+ import { lastValueFrom } from 'rxjs';
23
+ import * as i1$1 from '@angular/cdk/platform';
24
+ import * as i5 from 'angular-oauth2-oidc';
25
+ import * as i12 from 'ng-zorro-antd/core/transition-patch';
26
+ import * as i13 from 'ng-zorro-antd/core/wave';
27
+ import { App } from '@capacitor/app';
28
+ import { Browser } from '@capacitor/browser';
29
+ import { OAuth2Client } from '@byteowls/capacitor-oauth2';
30
+ import * as i1$2 from 'ngx-toastr';
31
+ import PouchDB from 'pouchdb';
32
+ import JSZip from 'jszip';
33
+
34
+ class GridComponent {
35
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: GridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
36
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: GridComponent, isStandalone: true, selector: "vt-grid", ngImport: i0, template: "<p>grid works!</p>\r\n", styles: [""] });
37
+ }
38
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: GridComponent, decorators: [{
39
+ type: Component,
40
+ args: [{ selector: 'vt-grid', imports: [], standalone: true, template: "<p>grid works!</p>\r\n" }]
41
+ }] });
42
+
43
+ class RequestService {
44
+ http;
45
+ pageSize = 0;
46
+ constructor(http) {
47
+ this.http = http;
48
+ }
49
+ getAllProject() {
50
+ return this.http.get("../assets/main/layout_schema.json");
51
+ }
52
+ getEnvironmet(selectedProject) {
53
+ return this.http.get(`../../assets/projects/${selectedProject}/environments/environment.json`);
54
+ }
55
+ getSectionInfo(url, envUrl, passToken = false, selectedProject = '', userInfo = null) {
56
+ if (envUrl) {
57
+ if (passToken && selectedProject) {
58
+ return this.http.get(envUrl + url, {
59
+ headers: this.createAuthorizationHeader(userInfo),
60
+ });
61
+ }
62
+ else {
63
+ return this.http.get(envUrl + url);
64
+ }
65
+ }
66
+ else {
67
+ return this.http.get(url);
68
+ }
69
+ ;
70
+ }
71
+ getMainLayout(selectedProject) {
72
+ return this.http.get(`../assets/projects/${selectedProject}/main/layout_schema.json`);
73
+ }
74
+ getInfo(url) {
75
+ return this.http.get(url);
76
+ }
77
+ dynamicCall(method = "get", body = null, url, passToken = false, selectedProject = '', userInfo = null) {
78
+ switch (method.toLowerCase()) {
79
+ case 'get':
80
+ if (passToken && selectedProject) {
81
+ return this.http.get(url, {
82
+ headers: this.createAuthorizationHeader(userInfo),
83
+ });
84
+ }
85
+ else {
86
+ return this.http.get(url);
87
+ }
88
+ case 'post':
89
+ if (passToken && selectedProject) {
90
+ return this.http.post(url, body, {
91
+ headers: this.createAuthorizationHeader(userInfo),
92
+ });
93
+ }
94
+ else {
95
+ return this.http.post(url, body);
96
+ }
97
+ case 'put':
98
+ if (passToken && selectedProject) {
99
+ return this.http.put(url, body, {
100
+ headers: this.createAuthorizationHeader(userInfo),
101
+ });
102
+ }
103
+ else {
104
+ return this.http.put(url, body);
105
+ }
106
+ case 'delete':
107
+ if (passToken && selectedProject) {
108
+ return this.http.delete(url, {
109
+ headers: this.createAuthorizationHeader(userInfo),
110
+ });
111
+ }
112
+ else {
113
+ return this.http.delete(url);
114
+ }
115
+ ;
116
+ case 'patch':
117
+ return this.http.patch(url, body);
118
+ default:
119
+ throw new Error(`Unsupported HTTP method: ${method}`);
120
+ }
121
+ }
122
+ createAuthorizationHeader(userInfo, tokenExist = false) {
123
+ let authHeaders = new HttpHeaders();
124
+ let token = tokenExist ? userInfo : userInfo && userInfo.jwt ? userInfo.jwt : userInfo?.authToken ? userInfo?.authToken : '';
125
+ return authHeaders.set('Authorization', 'Bearer ' + token);
126
+ }
127
+ getLoginUser(token) {
128
+ return this.http.get("https://dev-78992019.okta.com/oauth2/default/v1/userinfo", {
129
+ headers: this.createAuthorizationHeader(token, true),
130
+ });
131
+ }
132
+ saveDb(token, userInfo, order = {}) {
133
+ if (token) {
134
+ const headers = new HttpHeaders({
135
+ 'Authorization': `Bearer ${token}`,
136
+ 'Accept': 'application/json'
137
+ });
138
+ let url2 = `${userInfo.p5_backend_url}/assetsmobileservice/Zeiterfassung/registerTimeRecording?company=${userInfo.p5_group}/${userInfo.p5_client}/${userInfo.p5_plant ? userInfo.p5_plant : " "}&appVersion=1&resourceNo=${userInfo.p5_resource_no}`;
139
+ console.log('userInfo: ', userInfo);
140
+ this.http.post(url2, order, { headers }).subscribe({
141
+ next: res => {
142
+ console.log('Save-res: ', res);
143
+ }
144
+ });
145
+ }
146
+ }
147
+ getSaveOrder(token, userInfo, fromDate, toDate) {
148
+ // if (token) {
149
+ const headers = new HttpHeaders({
150
+ 'Authorization': `Bearer ${token}`,
151
+ 'Accept': 'application/json'
152
+ });
153
+ let url = `${userInfo.p5_backend_url}/assetsmobileservice/Zeiterfassung/requestBookedTimeRecording?resourceNo=${userInfo.p5_resource_no}&workDayFrom=${fromDate}&workDayTo=${toDate}&company=${userInfo.p5_group}/${userInfo.p5_client}/${userInfo.p5_plant ? userInfo.p5_plant : " "}&appVersion=1`;
154
+ return this.http.post(url, {}, { headers });
155
+ // }
156
+ }
157
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RequestService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
158
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RequestService, providedIn: 'root' });
159
+ }
160
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RequestService, decorators: [{
161
+ type: Injectable,
162
+ args: [{
163
+ providedIn: 'root'
164
+ }]
165
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
166
+
167
+ // import { Couchdb } from './couchdb';
168
+ class UtilityService {
169
+ platform;
170
+ requestService;
171
+ stripe = null;
172
+ constructor(platform,
173
+ // private couchdbService: Couchdb,
174
+ requestService) {
175
+ this.platform = platform;
176
+ this.requestService = requestService;
177
+ }
178
+ getScope(scope) {
179
+ let propertyScope = "";
180
+ let start = scope?.indexOf("#/") + 2;
181
+ let end = scope?.indexOf("/", start);
182
+ if (start && end) {
183
+ propertyScope = scope.substring(start, end);
184
+ }
185
+ return propertyScope;
186
+ }
187
+ getProperty(scope, itemInfo) {
188
+ const property = scope?.reference ? scope?.reference.split('/').pop() : '';
189
+ return { key: property, productSchema: itemInfo.propertySchema[property] };
190
+ }
191
+ async setStorage(key, value) {
192
+ if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
193
+ await Preferences.set({ key, value });
194
+ }
195
+ else {
196
+ sessionStorage.setItem(key, value);
197
+ }
198
+ }
199
+ async getStorage(key) {
200
+ if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
201
+ const { value } = await Preferences.get({ key });
202
+ return value;
203
+ }
204
+ else {
205
+ const storage = sessionStorage.getItem(key);
206
+ return storage;
207
+ }
208
+ }
209
+ async setLocalStorage(key, value) {
210
+ const stringValue = JSON.stringify(value);
211
+ if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
212
+ await Preferences.set({ key, value: stringValue });
213
+ }
214
+ else {
215
+ localStorage.setItem(key, stringValue);
216
+ }
217
+ }
218
+ async removeLocalStorage(keyName) {
219
+ if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
220
+ await Preferences.remove({ key: keyName });
221
+ }
222
+ else {
223
+ localStorage.removeItem(keyName);
224
+ }
225
+ }
226
+ async removeStorage(key) {
227
+ if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
228
+ await Preferences.remove({ key });
229
+ }
230
+ else {
231
+ sessionStorage.removeItem(key);
232
+ }
233
+ }
234
+ async getLocalStorage(key) {
235
+ if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
236
+ const { value } = await Preferences.get({ key });
237
+ return value ? JSON.parse(value) : null;
238
+ }
239
+ else {
240
+ const value = localStorage.getItem(key);
241
+ return value ? JSON.parse(value) : null;
242
+ }
243
+ }
244
+ async showAllProjects() {
245
+ await this.removeStorage('selectedProject');
246
+ window.location.reload();
247
+ }
248
+ parseBodyObject(obj) {
249
+ const jsonString = JSON.stringify(obj);
250
+ const replacedString = jsonString.replace(/{{(.*?)}}/g, (match, expression) => {
251
+ try {
252
+ return new Function(`return ${expression.trim()};`).call(this);
253
+ }
254
+ catch (error) {
255
+ console.error(`Error evaluating expression: ${expression}`, error);
256
+ return match;
257
+ }
258
+ });
259
+ return JSON.parse(replacedString);
260
+ }
261
+ getTotalPrice(tableitemInfo) {
262
+ const total = tableitemInfo.data.reduce((total, item) => {
263
+ if (item.quantity && !isNaN(item.quantity)) {
264
+ return total + (item.unitPrice * item.quantity);
265
+ }
266
+ return total;
267
+ }, 0);
268
+ return total.toFixed(2);
269
+ }
270
+ getTotalQuantity(tableitemInfo) {
271
+ let quantity = 0;
272
+ tableitemInfo.data.forEach((cartItem) => {
273
+ if (cartItem.quantity) {
274
+ quantity = cartItem.quantity + quantity;
275
+ }
276
+ });
277
+ return quantity;
278
+ }
279
+ replacePaginationParams(url, currentPage, pageSize) {
280
+ if (url.includes('{{pageNumber}}')) {
281
+ url = url.replace(/{{pageNumber}}/g, currentPage.toString());
282
+ }
283
+ if (url.includes('{{pageSize}}') && pageSize !== undefined) {
284
+ url = url.replace(/{{pageSize}}/g, pageSize.toString());
285
+ }
286
+ return url;
287
+ }
288
+ customButton(option, propertySchema, projectSeleted, environment) {
289
+ if (option.url) {
290
+ let body = {};
291
+ if (option.propertyKey) {
292
+ body = Object.keys(propertySchema[option.propertyKey]).reduce((acc, key) => {
293
+ acc[key] = propertySchema[option.propertyKey][key]?.value;
294
+ return acc;
295
+ }, {});
296
+ }
297
+ let url = environment?.apiUrl + option.url;
298
+ this.requestService.dynamicCall(option.method, body, url, option.passToken, projectSeleted).subscribe((res) => {
299
+ window.location.reload();
300
+ });
301
+ }
302
+ }
303
+ setDefaultUser(item, userInfo, environment) {
304
+ let schema = item;
305
+ let role = "default";
306
+ if (environment?.login?.type === "keycloak") {
307
+ if (userInfo?.name && item.options?.userRoleMapping) {
308
+ schema = item.options[item.options?.userRoleMapping[role]];
309
+ }
310
+ }
311
+ else if (environment?.login?.type === "jwtToken") {
312
+ if (item.options?.loginResponse && item.options?.loginResponse.storageType == "sessionStorage") {
313
+ if (userInfo) {
314
+ role = userInfo[item.options?.loginResponse.role]?.toLowerCase();
315
+ }
316
+ schema = item.options[item.options?.userRoleMapping[role]];
317
+ }
318
+ }
319
+ return schema;
320
+ }
321
+ setTableData(data, options = {}, tableitemInfo, projectSeleted) {
322
+ if (options?.pagination?.pageSize && options?.pagination?.scrollable) {
323
+ tableitemInfo.pageSize = options?.pagination?.pageSize;
324
+ }
325
+ let records;
326
+ if (options.dataKey) {
327
+ records = data[options.dataKey];
328
+ }
329
+ else if (options.key && data?._embedded) {
330
+ records = data?._embedded[options.key];
331
+ }
332
+ else {
333
+ if (!data?._embedded?.products && !Array.isArray(data)) {
334
+ records = [data];
335
+ }
336
+ else {
337
+ records = data?._embedded?.products;
338
+ }
339
+ }
340
+ tableitemInfo.totalRecords = data?.totalPages ? data?.totalPages : data?.page?.totalElements;
341
+ tableitemInfo.data = records.map((record) => ({
342
+ ...record,
343
+ ...(record.hasOwnProperty('imageUrl') && record.imageUrl
344
+ ? { imageUrl: `${projectSeleted}/pages/images/` + record.imageUrl.split('/').pop() }
345
+ : {})
346
+ }));
347
+ return tableitemInfo;
348
+ }
349
+ setOktaWebCredential(environment, projectName) {
350
+ return {
351
+ logo: `favicon.ico`,
352
+ baseUrl: environment.login.web.issuer.split('/oauth2')[0],
353
+ clientId: environment.login.web.clientId,
354
+ redirectUri: environment.login.web.redirectUri,
355
+ authParams: {
356
+ pkce: true,
357
+ issuer: environment.login.web.issuer,
358
+ scopes: environment.login.web.scopes
359
+ }
360
+ };
361
+ }
362
+ setOktaMobileCredential(environment) {
363
+ return {
364
+ appId: environment.login.mobile.clientId,
365
+ authorizationBaseUrl: environment.login.mobile.authorizationBaseUrl,
366
+ accessTokenEndpoint: environment.login.mobile.accessTokenEndpoint,
367
+ redirectUrl: environment.login.mobile.redirectUrl,
368
+ scope: environment.login.mobile.scope,
369
+ responseType: environment.login.mobile.responseType,
370
+ pkceEnabled: environment.login.mobile.pkceEnabled
371
+ };
372
+ }
373
+ async setupStripePaymentForm(environment, form, onCardChange) {
374
+ let hasCreditCard = false;
375
+ if (form.layoutSchema?.formSections) {
376
+ form.layoutSchema.formSections.forEach((formSection) => {
377
+ if (formSection.formFields?.length > 0) {
378
+ const foundCreditCard = formSection.formFields.some((formField) => {
379
+ const scopeKey = this.getScope(formField.scope?.reference);
380
+ return form.propertySchema[scopeKey] &&
381
+ form.propertySchema[scopeKey][formField.scope?.reference.split('/').pop()]?.type === 'carditCard';
382
+ });
383
+ if (foundCreditCard) {
384
+ hasCreditCard = true;
385
+ return;
386
+ }
387
+ }
388
+ });
389
+ }
390
+ if (hasCreditCard) {
391
+ this.stripe = await loadStripe(environment.stripePublishableKey);
392
+ const elements = this.stripe.elements();
393
+ const cardElement = elements.create('card', { hidePostalCode: true });
394
+ cardElement.mount('#card-element');
395
+ cardElement.on('change', (event) => {
396
+ if (event.complete) {
397
+ onCardChange('');
398
+ }
399
+ else if (event.error) {
400
+ onCardChange(event.error.message);
401
+ }
402
+ });
403
+ }
404
+ }
405
+ async formData(form, environment, cartInfo) {
406
+ if (form.layoutSchema?.formSections) {
407
+ for (const formSection of form.layoutSchema.formSections) {
408
+ if (formSection.formFields?.length > 0) {
409
+ for (const formField of formSection.formFields) {
410
+ const scope = this.getScope(formField.scope?.reference);
411
+ const fieldKey = formField.scope?.reference.split('/').pop();
412
+ const field = form.propertySchema?.[scope]?.[fieldKey];
413
+ if (!field)
414
+ continue;
415
+ // Checkbox logic with copy action
416
+ if (field.type === 'checkbox' && formField.option?.innerAction?.action === 'copy') {
417
+ const fromSchema = form.propertySchema[formField.option.innerAction.from];
418
+ const toSchema = form.propertySchema[formField.option.innerAction.to];
419
+ const keys = Object.keys(fromSchema);
420
+ keys.forEach((key) => {
421
+ if (toSchema[key]) {
422
+ const sourceValue = fromSchema?.[key]?.value;
423
+ toSchema[key].value = sourceValue || '';
424
+ }
425
+ });
426
+ }
427
+ // Dropdown logic (async data fetching)
428
+ if (field.type === 'dropdown' && formField.option?.data_url) {
429
+ try {
430
+ const res = await lastValueFrom(this.requestService.getInfo(environment.apiUrl + formField.option.data_url));
431
+ const key = Object.keys(res._embedded || {})[0];
432
+ if (key) {
433
+ field.data = res._embedded[key];
434
+ }
435
+ }
436
+ catch (err) {
437
+ console.error('Failed to load dropdown data', err);
438
+ }
439
+ }
440
+ // Cart info logic for string fields
441
+ if (field.type === 'string' && formField?.option?.cartInfo) {
442
+ if (field.value?.toString()?.includes('{{quantity}}')) {
443
+ field.value = cartInfo.quantity;
444
+ }
445
+ else if (field.value?.toString()?.includes('{{totalPrice}}')) {
446
+ field.value = cartInfo.totalPrice;
447
+ }
448
+ }
449
+ }
450
+ }
451
+ }
452
+ }
453
+ }
454
+ async processData(data, options, tenantName) {
455
+ if (options.dataKey) {
456
+ data = data[options.dataKey];
457
+ }
458
+ else {
459
+ if (!data?._embedded?.products && !Array.isArray(data)) {
460
+ data = [data];
461
+ }
462
+ else {
463
+ data = data?._embedded?.products;
464
+ }
465
+ }
466
+ const transformed = await Promise.all(data.map(async (record) => {
467
+ let imageUrl = record.imageUrl;
468
+ const imagePath = `pages/images/` +
469
+ record?.imageUrl?.split('/').pop();
470
+ if (tenantName &&
471
+ record?.imageUrl &&
472
+ options.setImageUrl) {
473
+ try {
474
+ imageUrl = "";
475
+ // imageUrl = await this.couchdbService.getFileContentFromCouchDb(
476
+ // `${tenantName}_${options.projectSelected}`,
477
+ // imagePath
478
+ // );
479
+ }
480
+ catch (err) {
481
+ console.warn(`Failed to fetch image from CouchDB for ${imagePath}`, err);
482
+ imageUrl = '';
483
+ }
484
+ }
485
+ return {
486
+ ...record,
487
+ ...(imageUrl ? { imageUrl } : {}),
488
+ ...(imagePath ? { imagePath } : {}),
489
+ };
490
+ }));
491
+ return transformed;
492
+ }
493
+ async setTableDataImages(records, tenantName, projectSelected) {
494
+ const transformed = await Promise.all(records.map(async (record) => {
495
+ let imageUrl = record.imageUrl;
496
+ const imagePath = record?.imagePath ? record?.imagePath : `pages/images/` +
497
+ record?.imageUrl?.split('/').pop();
498
+ if (tenantName &&
499
+ record?.imageUrl &&
500
+ record.hasOwnProperty('imageUrl')) {
501
+ try {
502
+ imageUrl = "";
503
+ // imageUrl = await this.couchdbService.getFileContentFromCouchDb(
504
+ // `${tenantName}_${projectSelected}`,
505
+ // imagePath
506
+ // );
507
+ }
508
+ catch (err) {
509
+ console.warn(`Failed to fetch image from CouchDB for ${imagePath}`, err);
510
+ imageUrl = '';
511
+ }
512
+ }
513
+ return {
514
+ ...record,
515
+ ...(imageUrl ? { imageUrl } : {}),
516
+ };
517
+ }));
518
+ return transformed;
519
+ }
520
+ // set date in localstorage
521
+ normalizeDatesForStorage(obj) {
522
+ const normalized = {};
523
+ Object.entries(obj).forEach(([key, value]) => {
524
+ if (this.isDateLike(value)) {
525
+ const date = value instanceof Date ? value : new Date(value);
526
+ normalized[key] = this.toLocalISOString(date);
527
+ }
528
+ else {
529
+ normalized[key] = value;
530
+ }
531
+ });
532
+ return normalized;
533
+ }
534
+ isDateLike(value) {
535
+ if (!value)
536
+ return false;
537
+ // Actual Date object
538
+ if (value instanceof Date && !isNaN(value.getTime())) {
539
+ return true;
540
+ }
541
+ // ISO string (UTC or local)
542
+ if (typeof value === 'string') {
543
+ return false;
544
+ }
545
+ return false;
546
+ }
547
+ toLocalISOString(date) {
548
+ const tzOffset = date.getTimezoneOffset() * 60000;
549
+ return new Date(date.getTime() - tzOffset)
550
+ .toISOString()
551
+ .slice(0, 19);
552
+ }
553
+ // restore date Field from localstorage
554
+ restoreDatesFromStorage(records, propertySchema) {
555
+ if (!Array.isArray(records))
556
+ return records;
557
+ if (!propertySchema)
558
+ return records;
559
+ return records.map(record => {
560
+ const restored = { ...record };
561
+ Object.keys(propertySchema).forEach(scopeKey => {
562
+ const schemaGroup = propertySchema[scopeKey];
563
+ if (!schemaGroup)
564
+ return;
565
+ Object.keys(schemaGroup).forEach(fieldKey => {
566
+ const fieldSchema = schemaGroup[fieldKey];
567
+ const value = restored[fieldKey];
568
+ if (!value || typeof value !== 'string')
569
+ return;
570
+ // ✅ DATE or TIME fields only
571
+ if (fieldSchema.type === 'date' || fieldSchema.type === 'time') {
572
+ restored[fieldKey] = this.parseLocalISODate(value);
573
+ }
574
+ });
575
+ });
576
+ return restored;
577
+ });
578
+ }
579
+ parseLocalISODate(value) {
580
+ // Remove Z to avoid UTC shift
581
+ const clean = value.replace('Z', '');
582
+ const [datePart, timePart = '00:00:00.000'] = clean.split('T');
583
+ const [y, m, d] = datePart.split('-').map(Number);
584
+ const [hh = 0, mm = 0, ss = 0, ms = 0] = timePart.split(/[:.]/).map(Number);
585
+ return new Date(y, m - 1, d, hh, mm, ss, ms);
586
+ }
587
+ // savecard conversion
588
+ convertToDailyLogs(cardOrCards) {
589
+ // Normalize input to array
590
+ const cards = Array.isArray(cardOrCards) ? cardOrCards : [cardOrCards];
591
+ const results = [];
592
+ for (const card of cards) {
593
+ const fromDate = new Date(card.fromDate);
594
+ const toDate = new Date(card.toDate);
595
+ const fromTime = new Date(card.workDayTimeFrom);
596
+ const toTime = new Date(card.workDayTimeTo);
597
+ // Normalize dates to midnight
598
+ const startDay = new Date(fromDate);
599
+ startDay.setHours(0, 0, 0, 0);
600
+ const endDay = new Date(toDate);
601
+ endDay.setHours(0, 0, 0, 0);
602
+ let currentDay = new Date(startDay);
603
+ while (currentDay <= endDay) {
604
+ const isFirstDay = this.isSameDay(currentDay, fromDate);
605
+ const isLastDay = this.isSameDay(currentDay, toDate);
606
+ const isSameDay = isFirstDay && isLastDay;
607
+ let workFrom;
608
+ let workTo;
609
+ // SAME DAY
610
+ if (isSameDay) {
611
+ workFrom = this.applyTimeToDay(currentDay, fromTime);
612
+ workTo = this.applyTimeToDay(currentDay, toTime);
613
+ }
614
+ // FIRST DAY
615
+ else if (isFirstDay) {
616
+ workFrom = this.applyTimeToDay(currentDay, fromTime);
617
+ workTo = this.endOfDay(currentDay);
618
+ }
619
+ // LAST DAY
620
+ else if (isLastDay) {
621
+ workFrom = this.startOfDay(currentDay);
622
+ workTo = this.applyTimeToDay(currentDay, toTime);
623
+ }
624
+ // MIDDLE DAY
625
+ else {
626
+ workFrom = this.startOfDay(currentDay);
627
+ workTo = this.endOfDay(currentDay);
628
+ }
629
+ results.push({
630
+ comment: card.comments || "",
631
+ onCallDuty: false,
632
+ timeCredit: false,
633
+ workDay: this.toLocalISO(currentDay, 0, 0),
634
+ workDayTimeFrom: this.toLocalISO(workFrom),
635
+ workDayTimeTo: this.toLocalISO(workTo),
636
+ workOrderNo: card.workOrderNo,
637
+ workType: "A"
638
+ });
639
+ currentDay.setDate(currentDay.getDate() + 1);
640
+ }
641
+ }
642
+ return results;
643
+ }
644
+ applyTimeToDay(day, time) {
645
+ const d = new Date(day);
646
+ d.setHours(time.getHours(), time.getMinutes(), 0, 0);
647
+ return d;
648
+ }
649
+ startOfDay(d) {
650
+ const x = new Date(d);
651
+ x.setHours(0, 0, 0, 0);
652
+ return x;
653
+ }
654
+ endOfDay(d) {
655
+ const x = new Date(d);
656
+ x.setHours(23, 59, 0, 0);
657
+ return x;
658
+ }
659
+ isSameDay(a, b) {
660
+ return (a.getFullYear() === b.getFullYear() &&
661
+ a.getMonth() === b.getMonth() &&
662
+ a.getDate() === b.getDate());
663
+ }
664
+ toLocalISO(date, hour, minute) {
665
+ const d = new Date(date);
666
+ if (hour !== undefined && minute !== undefined) {
667
+ d.setHours(hour, minute, 0, 0);
668
+ }
669
+ const pad = (n) => String(n).padStart(2, '0');
670
+ const year = d.getFullYear();
671
+ const month = pad(d.getMonth() + 1);
672
+ const day = pad(d.getDate());
673
+ const hrs = pad(d.getHours());
674
+ const mins = pad(d.getMinutes());
675
+ const offset = -d.getTimezoneOffset();
676
+ const sign = offset >= 0 ? '+' : '-';
677
+ const offH = pad(Math.floor(Math.abs(offset) / 60));
678
+ const offM = pad(Math.abs(offset) % 60);
679
+ return `${year}-${month}-${day}T${hrs}:${mins}:00${sign}${offH}:${offM}`;
680
+ }
681
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UtilityService, deps: [{ token: i1$1.Platform }, { token: RequestService }], target: i0.ɵɵFactoryTarget.Injectable });
682
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UtilityService, providedIn: 'root' });
683
+ }
684
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UtilityService, decorators: [{
685
+ type: Injectable,
686
+ args: [{
687
+ providedIn: 'root'
688
+ }]
689
+ }], ctorParameters: () => [{ type: i1$1.Platform }, { type: RequestService }] });
690
+
691
+ class CardComponent {
692
+ utilityService;
693
+ platform;
694
+ http;
695
+ cdr;
696
+ zone;
697
+ modalService;
698
+ oauthService;
699
+ requestService;
700
+ itemInfo = {};
701
+ currentPage = 0;
702
+ pageSize = 5;
703
+ selectedLanguageInfo = {};
704
+ pages = [];
705
+ cardButtonClick = new EventEmitter();
706
+ cardHeaderButtonClick = new EventEmitter();
707
+ linkDetails = new EventEmitter();
708
+ imageDetails = new EventEmitter();
709
+ onPageSizeChange = new EventEmitter();
710
+ onPageChange = new EventEmitter();
711
+ cardPerRow = "col-12 md:col-6 lg:col-";
712
+ isLoading = false;
713
+ layoutSchemaCopy = {};
714
+ headerSchemaCopy = {};
715
+ footerSchemaCopy = {};
716
+ constructor(utilityService, platform, http, cdr, zone, modalService, oauthService, requestService) {
717
+ this.utilityService = utilityService;
718
+ this.platform = platform;
719
+ this.http = http;
720
+ this.cdr = cdr;
721
+ this.zone = zone;
722
+ this.modalService = modalService;
723
+ this.oauthService = oauthService;
724
+ this.requestService = requestService;
725
+ }
726
+ ngOnInit() {
727
+ if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
728
+ this.cardPerRow = "col-";
729
+ }
730
+ else {
731
+ this.cardPerRow = "col-12 md:col-6 lg:col-";
732
+ }
733
+ }
734
+ ngOnChanges(changes) {
735
+ if (changes['itemInfo']) {
736
+ if (this.itemInfo.layoutSchema) {
737
+ this.layoutSchemaCopy = JSON.parse(JSON.stringify(this.itemInfo.layoutSchema));
738
+ }
739
+ if (this.itemInfo.header) {
740
+ this.headerSchemaCopy = JSON.parse(JSON.stringify(this.itemInfo.header));
741
+ }
742
+ if (this.itemInfo.footer) {
743
+ this.footerSchemaCopy = JSON.parse(JSON.stringify(this.itemInfo.footer));
744
+ }
745
+ }
746
+ if ((changes['selectedLanguageInfo'] || this.selectedLanguageInfo) && this.selectedLanguageInfo.selectedLanguage) {
747
+ this.itemInfo.footer = this.updatebuttonLanguage(this.footerSchemaCopy, this.selectedLanguageInfo.selectedLanguage);
748
+ this.itemInfo.header = this.updatebuttonLanguage(this.headerSchemaCopy, this.selectedLanguageInfo.selectedLanguage);
749
+ this.itemInfo.layoutSchema = this.updateLayoutLanguage(this.layoutSchemaCopy, this.selectedLanguageInfo.selectedLanguage);
750
+ }
751
+ }
752
+ safeUpdate(fn) {
753
+ if (NgZone.isInAngularZone()) {
754
+ fn();
755
+ this.cdr.markForCheck();
756
+ }
757
+ else {
758
+ this.zone.run(() => {
759
+ fn();
760
+ this.cdr.markForCheck();
761
+ });
762
+ }
763
+ }
764
+ forceNumericKeyboard(event) {
765
+ const input = event?.target;
766
+ if (input && input.tagName === 'INPUT') {
767
+ input.setAttribute('inputmode', 'numeric'); // Android
768
+ input.setAttribute('pattern', '[0-9:]*'); // iOS
769
+ input.setAttribute('type', 'tel'); // strongest signal
770
+ }
771
+ }
772
+ onDateTyping(event) {
773
+ const input = event.target;
774
+ if (!input)
775
+ return;
776
+ let digits = input.value.replace(/\D/g, '');
777
+ digits = digits.substring(0, 8);
778
+ let formatted = '';
779
+ if (digits.length <= 4) {
780
+ formatted = digits;
781
+ }
782
+ else if (digits.length <= 6) {
783
+ formatted = `${digits.slice(0, 4)}-${digits.slice(4)}`;
784
+ }
785
+ else {
786
+ formatted = `${digits.slice(0, 4)}-${digits.slice(4, 6)}-${digits.slice(6)}`;
787
+ }
788
+ input.value = formatted;
789
+ }
790
+ updatebuttonLanguage(schema, translations) {
791
+ const cloned = JSON.parse(JSON.stringify(schema));
792
+ const walk = (obj) => {
793
+ if (!obj || typeof obj !== 'object')
794
+ return;
795
+ // ✅ Replace direct caption (e.g. button.caption)
796
+ if (typeof obj.caption === 'string') {
797
+ const original = obj.caption;
798
+ obj.caption = translations[original] ?? original;
799
+ }
800
+ // ✅ Replace modalTitle if present
801
+ if (typeof obj.modalTitle === 'string') {
802
+ const original = obj.modalTitle;
803
+ obj.modalTitle = translations[original] ?? original;
804
+ }
805
+ // 🔁 Recurse
806
+ Object.keys(obj).forEach((key) => {
807
+ const value = obj[key];
808
+ if (typeof value === 'object') {
809
+ walk(value);
810
+ }
811
+ });
812
+ };
813
+ walk(cloned);
814
+ return cloned;
815
+ }
816
+ updateLayoutLanguage(schema, translations) {
817
+ // Deep clone to avoid mutating original schema
818
+ const cloned = JSON.parse(JSON.stringify(schema));
819
+ const walk = (obj) => {
820
+ if (!obj || typeof obj !== 'object')
821
+ return;
822
+ // ✅ If label.caption exists → translate it
823
+ if (obj.label && typeof obj.label.caption === 'string') {
824
+ const originalCaption = obj.label.caption;
825
+ obj.label.caption =
826
+ translations[originalCaption] ?? originalCaption;
827
+ }
828
+ // 🔁 Recurse into object properties
829
+ Object.keys(obj).forEach((key) => {
830
+ const value = obj[key];
831
+ if (typeof value === 'object') {
832
+ walk(value);
833
+ }
834
+ });
835
+ };
836
+ walk(cloned);
837
+ return cloned;
838
+ }
839
+ dateChangeEvent(filter, value) {
840
+ const scope = this.getScope(filter.scope.reference);
841
+ const field = filter.scope?.reference.split('/').pop();
842
+ this.itemInfo.propertySchema[scope][field].value = value;
843
+ this.applyDateFilter(this.extractFilterValues(this.itemInfo.propertySchema[scope]));
844
+ }
845
+ async applyDateFilter(filters) {
846
+ const from = filters.fromDateFilter ? new Date(filters.fromDateFilter) : null;
847
+ const to = filters.toDateFilter ? new Date(filters.toDateFilter) : null;
848
+ if (to && from) {
849
+ const formattedFrom = this.formatToOffsetISO(from);
850
+ const formattedTo = this.formatToOffsetISO(to);
851
+ const keycloakInfo = await this.utilityService.getLocalStorage('KeycloakInfo');
852
+ const logined = await this.utilityService.getLocalStorage('loginedUser');
853
+ this.safeUpdate(() => this.isLoading = true);
854
+ if (this.platform.ANDROID || this.platform.IOS) {
855
+ let saveOrder = await this.getSaveOrder(keycloakInfo?.token, keycloakInfo, formattedFrom, formattedTo);
856
+ this.itemInfo.data = saveOrder?.length > 0 ? saveOrder : [];
857
+ this.safeUpdate(() => this.isLoading = false);
858
+ }
859
+ else {
860
+ this.requestService.getSaveOrder(logined?.token, logined, formattedFrom, formattedTo).subscribe((saveOrders) => {
861
+ const updatedData = this.utilityService.restoreDatesFromStorage(saveOrders, this.itemInfo.propertySchema);
862
+ this.itemInfo.data = updatedData?.length > 0 ? updatedData : [];
863
+ this.safeUpdate(() => this.isLoading = false);
864
+ });
865
+ }
866
+ }
867
+ }
868
+ async getSaveOrder(token, userInfo, fromDate, toDate) {
869
+ if (!token) {
870
+ return;
871
+ }
872
+ const company = userInfo.p5_plant
873
+ ? `${userInfo.p5_group}/${userInfo.p5_client}/${userInfo.p5_plant}`
874
+ : `${userInfo.p5_group}/${userInfo.p5_client}/`;
875
+ const url = `${userInfo.p5_backend_url}/assetsmobileservice/Zeiterfassung/requestBookedTimeRecording`;
876
+ try {
877
+ const response = await CapacitorHttp.post({
878
+ url,
879
+ params: {
880
+ resourceNo: userInfo.p5_resource_no,
881
+ workDayFrom: fromDate,
882
+ workDayTo: toDate,
883
+ company,
884
+ appVersion: '1',
885
+ },
886
+ headers: {
887
+ Authorization: `Bearer ${token}`, // ✅ REQUIRED
888
+ Accept: 'application/json',
889
+ },
890
+ // ❗ NO BODY needed for this endpoint
891
+ });
892
+ console.log('getSaveOrder response:', response.data);
893
+ return response.data;
894
+ }
895
+ catch (error) {
896
+ console.error('Failed to fetch saved orders', error);
897
+ throw error;
898
+ }
899
+ }
900
+ formatToOffsetISO(date) {
901
+ if (!date)
902
+ return "";
903
+ const pad = (n, len = 2) => String(n).padStart(len, "0");
904
+ const year = date.getFullYear();
905
+ const month = pad(date.getMonth() + 1);
906
+ const day = pad(date.getDate());
907
+ const hours = pad(date.getHours());
908
+ const minutes = pad(date.getMinutes());
909
+ const seconds = pad(date.getSeconds());
910
+ const ms = pad(date.getMilliseconds(), 4); // 4-digit milliseconds
911
+ // timezone offset
912
+ const offset = -date.getTimezoneOffset(); // in minutes
913
+ const offSign = offset >= 0 ? "+" : "-";
914
+ const offHours = pad(Math.floor(Math.abs(offset) / 60));
915
+ const offMinutes = pad(Math.abs(offset) % 60);
916
+ return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}:${ms}${offSign}${offHours}:${offMinutes}`;
917
+ }
918
+ extractFilterValues(schema) {
919
+ return Object.keys(schema).reduce((acc, key) => {
920
+ if (key.includes('Filter') && schema[key]?.value !== undefined) {
921
+ acc[key] = schema[key].value;
922
+ }
923
+ return acc;
924
+ }, {});
925
+ }
926
+ invokeOnPageSizeChange(pageSize) {
927
+ this.onPageSizeChange.emit(pageSize);
928
+ }
929
+ invokeGoToPage(page) {
930
+ this.onPageChange.emit(page);
931
+ }
932
+ invokeOnCardHeader(element) {
933
+ this.cardHeaderButtonClick.emit(element);
934
+ }
935
+ invokeOnCardFooter(element) {
936
+ // this.cardHeaderButtonClick.emit(element);
937
+ this.d4_SaveAll();
938
+ }
939
+ async invokeButtonClick(layout, record, recordIndex) {
940
+ if (layout?.option?.action === "delete" && layout?.option?.storageType == "localstorage") {
941
+ if (layout?.option?.deleteMessage) {
942
+ this.showConfirm(layout?.option, recordIndex);
943
+ }
944
+ }
945
+ else if (layout?.option?.action === "save" && layout?.option?.storageType === "database") {
946
+ const final_array = this.utilityService.convertToDailyLogs(record);
947
+ await this.saveToDb(final_array, recordIndex, layout.option.data_url);
948
+ }
949
+ else {
950
+ this.cardButtonClick.emit({ layout: layout, record: record, recordIndex: recordIndex });
951
+ }
952
+ }
953
+ showConfirm(option, recordIndex) {
954
+ this.modalService.confirm({
955
+ nzTitle: this.selectedLanguageInfo && this.selectedLanguageInfo?.selectedLanguage['Confirm'] ? this.selectedLanguageInfo.selectedLanguage['Confirm'] : 'Confirm',
956
+ nzContent: this.selectedLanguageInfo && this.selectedLanguageInfo?.selectedLanguage[option.deleteMessage] ? this.selectedLanguageInfo.selectedLanguage[option.deleteMessage] : option.deleteMessage,
957
+ nzOkText: this.selectedLanguageInfo && this.selectedLanguageInfo?.selectedLanguage['Delete'] ? this.selectedLanguageInfo.selectedLanguage['Delete'] : 'Delete',
958
+ nzCancelText: this.selectedLanguageInfo && this.selectedLanguageInfo?.selectedLanguage['Cancel'] ? this.selectedLanguageInfo.selectedLanguage['Cancel'] : 'Cancel',
959
+ nzOnOk: () => this.deleteRecord(recordIndex, option.data_url)
960
+ });
961
+ }
962
+ async d4_SaveAll() {
963
+ let allOrders = [];
964
+ for (let i = 0; i < this.itemInfo.data.length; i++) {
965
+ const element = this.itemInfo.data[i];
966
+ const dailyLogs = this.utilityService.convertToDailyLogs(element);
967
+ if (Array.isArray(dailyLogs)) {
968
+ allOrders.push(...dailyLogs);
969
+ }
970
+ }
971
+ await this.saveToDb(allOrders, null, true);
972
+ }
973
+ deleteRecord(recordIndex, data_url) {
974
+ this.itemInfo.data.splice(recordIndex, 1);
975
+ this.utilityService.setLocalStorage('timeRecords', JSON.stringify(this.itemInfo.data));
976
+ }
977
+ deleteAllRecord() {
978
+ this.itemInfo.data = [];
979
+ this.utilityService.setLocalStorage('timeRecords', JSON.stringify(this.itemInfo.data));
980
+ }
981
+ async saveToDb(orders, orderIndex, data_url, deleteAll = false) {
982
+ this.safeUpdate(() => this.isLoading = true);
983
+ const token = this.oauthService.getAccessToken(); // whatever you have
984
+ const logined = await this.utilityService.getLocalStorage('loginedUser');
985
+ const keycloakInfo = await this.utilityService.getLocalStorage('KeycloakInfo');
986
+ let saveobject = {
987
+ ressourceNo: logined?.p5_resource_no ? logined.p5_resource_no : keycloakInfo?.p5_resource_no,
988
+ returnTimeRecordingLine: orders
989
+ };
990
+ if (this.platform.ANDROID || this.platform.IOS) {
991
+ const res = await this.mobileSaveDb(keycloakInfo.token, keycloakInfo, saveobject, orderIndex, data_url, deleteAll);
992
+ }
993
+ else {
994
+ this.webSaveDb(token, logined, saveobject, orderIndex, data_url, deleteAll);
995
+ }
996
+ }
997
+ webSaveDb(token, userInfo, order = {}, orderIndex, dataUrl, deleteAll = false) {
998
+ if (token) {
999
+ const headers = new HttpHeaders({
1000
+ 'Authorization': `Bearer ${token}`,
1001
+ 'Accept': 'application/json'
1002
+ });
1003
+ let url2 = `${userInfo.p5_backend_url}/assetsmobileservice/Zeiterfassung/registerTimeRecording?company=${userInfo.p5_group}/${userInfo.p5_client}/${userInfo.p5_plant ? userInfo.p5_plant : " "}&appVersion=1&resourceNo=${userInfo.p5_resource_no}`;
1004
+ this.http.post(url2, order, { headers }).subscribe({
1005
+ next: res => {
1006
+ this.safeUpdate(() => this.isLoading = false);
1007
+ if (orderIndex && orderIndex > -1) {
1008
+ this.deleteRecord(orderIndex, dataUrl);
1009
+ }
1010
+ else {
1011
+ this.deleteAllRecord();
1012
+ }
1013
+ }
1014
+ });
1015
+ }
1016
+ }
1017
+ async mobileSaveDb(token, userInfo, order = {}, orderIndex, dataUrl, deleteAll = false) {
1018
+ if (!token) {
1019
+ console.log("NO-token", token);
1020
+ return;
1021
+ }
1022
+ const company = userInfo.p5_plant
1023
+ ? `${userInfo.p5_group}/${userInfo.p5_client}/${userInfo.p5_plant}`
1024
+ : `${userInfo.p5_group}/${userInfo.p5_client}/`;
1025
+ const url = `${userInfo.p5_backend_url}/assetsmobileservice/Zeiterfassung/registerTimeRecording`;
1026
+ try {
1027
+ const response = await CapacitorHttp.post({
1028
+ url,
1029
+ params: {
1030
+ company,
1031
+ appVersion: '1',
1032
+ resourceNo: userInfo.p5_resource_no,
1033
+ },
1034
+ headers: {
1035
+ Authorization: `Bearer ${token}`,
1036
+ Accept: 'application/json',
1037
+ 'Content-Type': 'application/json',
1038
+ },
1039
+ data: order,
1040
+ });
1041
+ if (orderIndex != null && orderIndex > -1) {
1042
+ this.deleteRecord(orderIndex, dataUrl);
1043
+ }
1044
+ else {
1045
+ this.deleteAllRecord();
1046
+ }
1047
+ this.safeUpdate(() => this.isLoading = false);
1048
+ return response.data;
1049
+ }
1050
+ catch (error) {
1051
+ this.safeUpdate(() => this.isLoading = false);
1052
+ console.error('Failed to save time recording', error);
1053
+ throw error;
1054
+ }
1055
+ }
1056
+ showLinkDetails(option, record) {
1057
+ this.linkDetails.emit({ option: option, record: record });
1058
+ }
1059
+ showImageDetails(option, record) {
1060
+ this.imageDetails.emit({ option: option, record: record });
1061
+ }
1062
+ getProperty(scope) {
1063
+ const property = scope ? scope.split('/').pop() : '';
1064
+ return { key: property, productSchema: this.itemInfo.propertySchema[this.getScope(scope)][property] };
1065
+ }
1066
+ getStyleWithoutClasses(styleObject) {
1067
+ if (!styleObject) {
1068
+ return { classes: '', style: {} };
1069
+ }
1070
+ const { classes, ...styleWithoutClasses } = styleObject;
1071
+ return { classes: classes && classes.length > 0 ? classes[0] : '', style: styleWithoutClasses };
1072
+ }
1073
+ getScope(scope) {
1074
+ let propertyScope = "";
1075
+ let start = scope?.indexOf("#/") + 2;
1076
+ let end = scope?.indexOf("/", start);
1077
+ if (start && end) {
1078
+ propertyScope = scope.substring(start, end);
1079
+ }
1080
+ return propertyScope;
1081
+ }
1082
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CardComponent, deps: [{ token: UtilityService }, { token: i1$1.Platform }, { token: i1.HttpClient }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i4.NzModalService }, { token: i5.OAuthService }, { token: RequestService }], target: i0.ɵɵFactoryTarget.Component });
1083
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: CardComponent, isStandalone: true, selector: "vt-card", inputs: { itemInfo: "itemInfo", currentPage: "currentPage", pageSize: "pageSize", selectedLanguageInfo: "selectedLanguageInfo", pages: "pages" }, outputs: { cardButtonClick: "cardButtonClick", cardHeaderButtonClick: "cardHeaderButtonClick", linkDetails: "linkDetails", imageDetails: "imageDetails", onPageSizeChange: "onPageSizeChange", onPageChange: "onPageChange" }, usesOnChanges: true, ngImport: i0, template: "<!-- Loader Spinner -->\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<span *ngIf=\"this.selectedLanguageInfo?.selectedLanguage\">\r\n <!-- top pagination on card -->\r\n <div *ngIf=\"itemInfo?.layoutSchema?.pagination?.pageSize && itemInfo?.layoutSchema?.pagination?.top\">\r\n <!-- <app-pagination [itemInfo]=\"itemInfo\" [pageSize]=\"pageSize\" [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\" (onGoToPage)=\"invokeGoToPage($event)\">\r\n </app-pagination> -->\r\n </div>\r\n <div *ngIf=\"itemInfo?.header?.elements\" [style]=\"getStyleWithoutClasses(itemInfo?.header?.style).style\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.header?.style).classes\">\r\n <span *ngFor=\"let element of itemInfo.header?.elements; let c = index\">\r\n <ng-container\r\n [ngSwitch]=\"element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\" [class]=\"element.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"element.label?.caption\" [style]=\"getStyleWithoutClasses(element.label?.style).style\"\r\n [class]=\"element.label?.style?.classes?.[0]\">\r\n {{ element.label.caption }}\r\n </span>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"mb-3\">\r\n <span *ngIf=\"element.option.protected\" [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <!-- <app-string [formField]=\"element\" [modalItemInfo]=\"itemInfo\">\r\n </app-string> -->\r\n </span>\r\n <div *ngIf=\"!element.option.protected\"\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : ''\"\r\n [ngClass]=\"element?.style?.classes[0]\" [style]=\"getStyleWithoutClasses(element?.style).style\">\r\n <label [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{ element.label?.value\r\n ?\r\n element.label?.value : element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <p-datepicker (ngModelChange)=\"dateChangeEvent(element, $event)\" [showIcon]=\"true\" type=\"number\"\r\n inputmode=\"numeric\"\r\n [dateFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].format : 'yy-mm-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n (onFocus)=\"forceNumericKeyboard($event)\" (onInput)=\"onDateTyping($event)\"\r\n [class]=\"element?.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.scope?.style).style\">\r\n </p-datepicker>\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\" [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardHeader(element)\">\r\n <button nz-button [style]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container *ngIf=\"!element.caption; else textContent\">\r\n <i nz-icon [nzType]=\"element.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ element.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </span>\r\n </div>\r\n <div [class]=\"itemInfo.class\" [style]=\"itemInfo.style\">\r\n <div *ngFor=\"let record of itemInfo.data; let k = index\"\r\n [ngClass]=\"itemInfo.layoutSchema.pagination ? itemInfo.layoutSchema.pagination ? cardPerRow + itemInfo.layoutSchema?.stylePerCard?.elementPerRow[k % itemInfo.layoutSchema?.stylePerCard?.elementPerRow.length] : '' : ''\">\r\n <div [class]=\"itemInfo.layoutSchema?.stylePerCard?.classes[0]\">\r\n <div *ngFor=\"let layout of itemInfo.layoutSchema.cards\">\r\n <ng-container\r\n [ngSwitch]=\"layout?.scope?.reference && itemInfo.propertySchema[getScope(layout.scope?.reference)] ? itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.type : layout?.type == 'HorizontalLayout' ? 'HorizontalLayout' : 'default'\">\r\n <!-- Image Control -->\r\n <div *ngSwitchCase=\"'image'\" [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <!-- <img [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"layout?.option?.src ? layout?.option?.src : record[layout.scope?.reference.split('/').pop()]\"\r\n alt=\"{{ layout.label ? layout.label : getProperty(layout.scope?.reference).productSchema.caption }}\"\r\n (click)=\"showImageDetails(layout.option, record)\" /> -->\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\" [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\" [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\" [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\" [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\" [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\" [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\" [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3 *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{ record[layout.scope?.reference.split('/').pop()] | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\" [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <button [style]=\"getStyleWithoutClasses(layout?.style).style\"\r\n [class]=\"layout.option.protected ? 'disabled-button' : getStyleWithoutClasses(layout?.style).classes\"\r\n (click)=\"invokeButtonClick(layout, record, k)\">\r\n <ng-container *ngIf=\"!layout.caption; else textContent\">\r\n <i nz-icon [nzType]=\"layout.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ layout.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n\r\n <!-- HorizontalLayout Control -->\r\n <div *ngSwitchCase=\"'HorizontalLayout'\">\r\n <div [class]=\"getStyleWithoutClasses(layout?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.style).style\">\r\n <ng-container *ngFor=\"let innerLayout of layout.elements\">\r\n <ng-container\r\n [ngSwitch]=\"innerLayout.scope?.reference && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] ? itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n <!-- Image Control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <!-- <img [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [src]=\"innerLayout?.option?.src ? innerLayout?.option?.src : record[innerLayout.scope?.reference.split('/').pop()]\"\r\n alt=\"{{ innerLayout.label ? innerLayout.label : getProperty(innerLayout.scope?.reference).productSchema.caption }}\"\r\n (click)=\"showImageDetails(innerLayout.option, record)\" /> -->\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"innerLayout.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"innerLayout.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"innerLayout.label?.style?.classes?.[0]\">\r\n {{ innerLayout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3 *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container *ngIf=\"innerLayout.option?.dateFormat; else checkTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.dateFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template #checkTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.timeFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template #normalValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?? '--'\r\n }}\r\n </ng-template>\r\n\r\n </h3>\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3 *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] &&itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n {{ record[innerLayout.scope?.reference.split('/').pop()] | currency:\r\n innerLayout.option?.currency ?\r\n innerLayout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [class]=\"innerLayout.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"innerLayout.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"innerLayout.label?.style?.classes?.[0]\">\r\n {{ innerLayout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3 *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container *ngIf=\"innerLayout.option?.dateFormat; else checkTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.dateFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template #checkTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.timeFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template #normalValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?? '--'\r\n }}\r\n </ng-template>\r\n\r\n </h3>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [class]=\"innerLayout.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"innerLayout.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"innerLayout.label?.style?.classes?.[0]\">\r\n {{ innerLayout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3 *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container *ngIf=\"innerLayout.option?.dateFormat; else checkTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.dateFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template #checkTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.timeFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template #normalValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?? '--'\r\n }}\r\n </ng-template>\r\n\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button nz-button [style]=\"getStyleWithoutClasses(innerLayout?.style).style\"\r\n [class]=\"innerLayout.option?.visible ? innerLayout.option.protected ? 'disabled-button' : getStyleWithoutClasses(innerLayout?.style).classes : 'hidden'\"\r\n (click)=\"invokeButtonClick(innerLayout, record, k)\">\r\n <ng-container *ngIf=\"!innerLayout.caption; else textContent\">\r\n <i nz-icon [nzType]=\"innerLayout.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ innerLayout.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div *ngIf=\"itemInfo?.footer?.elements && itemInfo?.data && itemInfo?.data.length\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.footer?.style).classes\">\r\n <span *ngFor=\"let element of itemInfo.footer?.elements; let c = index\">\r\n <ng-container\r\n [ngSwitch]=\"element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"element.option.protected\" [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <h5>{{\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\">\r\n <div [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{ element.label?.value\r\n ?\r\n element.label?.value : element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-date-picker [required]=\"element.option.required\" [name]=\"element.scope?.reference\"\r\n [nzDisabled]=\"element?.option?.disabled\"\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [nzFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format : 'yyyy-MM-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\"></nz-date-picker>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\" [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardFooter(element)\">\r\n <button nz-button [style]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container *ngIf=\"!element.caption; else textContent\">\r\n <i nz-icon [nzType]=\"element.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ element.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </span>\r\n </div>\r\n <!-- bottom pagination on card -->\r\n <!-- <div *ngIf=\"itemInfo?.layoutSchema?.pagination && itemInfo?.layoutSchema?.pagination?.bottom\">\r\n <app-pagination [itemInfo]=\"itemInfo\" [pageSize]=\"pageSize\" [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\" (onGoToPage)=\"invokeGoToPage($event)\">\r\n </app-pagination>\r\n </div> -->\r\n</span>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i7.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i9.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i10.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i11.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i12.ɵNzTransitionPatchDirective, selector: "[nz-button], [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i13.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzDatePickerModule }, { kind: "component", type: i14.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzInline", "nzAllowClear", "nzAutoFocus", "nzDisabled", "nzInputReadOnly", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzVariant", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "ngmodule", type: NzModalModule }, { kind: "pipe", type: i7.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i7.DatePipe, name: "date" }] });
1084
+ }
1085
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CardComponent, decorators: [{
1086
+ type: Component,
1087
+ args: [{ selector: 'vt-card', imports: [
1088
+ CommonModule,
1089
+ FormsModule,
1090
+ NzIconModule,
1091
+ DatePickerModule,
1092
+ NzButtonModule,
1093
+ NzDatePickerModule,
1094
+ NzModalModule,
1095
+ // StringComponent,
1096
+ // PaginationComponent
1097
+ ], standalone: true, template: "<!-- Loader Spinner -->\r\n<div *ngIf=\"isLoading\" class=\"loader-overlay\">\r\n <div class=\"spinner\"></div>\r\n</div>\r\n<span *ngIf=\"this.selectedLanguageInfo?.selectedLanguage\">\r\n <!-- top pagination on card -->\r\n <div *ngIf=\"itemInfo?.layoutSchema?.pagination?.pageSize && itemInfo?.layoutSchema?.pagination?.top\">\r\n <!-- <app-pagination [itemInfo]=\"itemInfo\" [pageSize]=\"pageSize\" [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\" (onGoToPage)=\"invokeGoToPage($event)\">\r\n </app-pagination> -->\r\n </div>\r\n <div *ngIf=\"itemInfo?.header?.elements\" [style]=\"getStyleWithoutClasses(itemInfo?.header?.style).style\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.header?.style).classes\">\r\n <span *ngFor=\"let element of itemInfo.header?.elements; let c = index\">\r\n <ng-container\r\n [ngSwitch]=\"element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\" [class]=\"element.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"element.label?.caption\" [style]=\"getStyleWithoutClasses(element.label?.style).style\"\r\n [class]=\"element.label?.style?.classes?.[0]\">\r\n {{ element.label.caption }}\r\n </span>\r\n </div>\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"mb-3\">\r\n <span *ngIf=\"element.option.protected\" [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <!-- <app-string [formField]=\"element\" [modalItemInfo]=\"itemInfo\">\r\n </app-string> -->\r\n </span>\r\n <div *ngIf=\"!element.option.protected\"\r\n [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : ''\"\r\n [ngClass]=\"element?.style?.classes[0]\" [style]=\"getStyleWithoutClasses(element?.style).style\">\r\n <label [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{ element.label?.value\r\n ?\r\n element.label?.value : element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n <p-datepicker (ngModelChange)=\"dateChangeEvent(element, $event)\" [showIcon]=\"true\" type=\"number\"\r\n inputmode=\"numeric\"\r\n [dateFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].format : 'yy-mm-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n (onFocus)=\"forceNumericKeyboard($event)\" (onInput)=\"onDateTyping($event)\"\r\n [class]=\"element?.scope?.style?.classes[0]\"\r\n [style]=\"getStyleWithoutClasses(element?.scope?.style).style\">\r\n </p-datepicker>\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\" [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardHeader(element)\">\r\n <button nz-button [style]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container *ngIf=\"!element.caption; else textContent\">\r\n <i nz-icon [nzType]=\"element.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ element.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </span>\r\n </div>\r\n <div [class]=\"itemInfo.class\" [style]=\"itemInfo.style\">\r\n <div *ngFor=\"let record of itemInfo.data; let k = index\"\r\n [ngClass]=\"itemInfo.layoutSchema.pagination ? itemInfo.layoutSchema.pagination ? cardPerRow + itemInfo.layoutSchema?.stylePerCard?.elementPerRow[k % itemInfo.layoutSchema?.stylePerCard?.elementPerRow.length] : '' : ''\">\r\n <div [class]=\"itemInfo.layoutSchema?.stylePerCard?.classes[0]\">\r\n <div *ngFor=\"let layout of itemInfo.layoutSchema.cards\">\r\n <ng-container\r\n [ngSwitch]=\"layout?.scope?.reference && itemInfo.propertySchema[getScope(layout.scope?.reference)] ? itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.type : layout?.type == 'HorizontalLayout' ? 'HorizontalLayout' : 'default'\">\r\n <!-- Image Control -->\r\n <div *ngSwitchCase=\"'image'\" [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <!-- <img [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\"\r\n [src]=\"layout?.option?.src ? layout?.option?.src : record[layout.scope?.reference.split('/').pop()]\"\r\n alt=\"{{ layout.label ? layout.label : getProperty(layout.scope?.reference).productSchema.caption }}\"\r\n (click)=\"showImageDetails(layout.option, record)\" /> -->\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\" [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\" [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\" [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\" [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\" [class]=\"layout.option?.visible ? 'card-field-wrapper' : 'hidden'\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"layout?.label?.caption\" [class]=\"layout.label?.style?.classes?.[0]\">\r\n {{ layout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <p *ngIf=\"layout.option?.protected && layout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n (click)=\"showLinkDetails(layout.option, record)\">\r\n {{\r\n record?.[layout.scope?.reference.split('/').pop()]\r\n ?? itemInfo.propertySchema[\r\n getScope(layout.scope?.reference)\r\n ]?.[layout.scope?.reference.split('/').pop()]?.default\r\n ?? '--'\r\n }}\r\n </p>\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\" [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <h3 *ngIf=\"itemInfo.propertySchema[getScope(layout.scope?.reference)] && itemInfo.propertySchema[getScope(layout.scope?.reference)][layout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(layout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.scope?.style).style\">\r\n {{ record[layout.scope?.reference.split('/').pop()] | currency: layout.option?.currency\r\n ?\r\n layout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\" [class]=\"layout.option?.visible ? 'row' : 'hidden'\">\r\n <button [style]=\"getStyleWithoutClasses(layout?.style).style\"\r\n [class]=\"layout.option.protected ? 'disabled-button' : getStyleWithoutClasses(layout?.style).classes\"\r\n (click)=\"invokeButtonClick(layout, record, k)\">\r\n <ng-container *ngIf=\"!layout.caption; else textContent\">\r\n <i nz-icon [nzType]=\"layout.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ layout.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n\r\n <!-- HorizontalLayout Control -->\r\n <div *ngSwitchCase=\"'HorizontalLayout'\">\r\n <div [class]=\"getStyleWithoutClasses(layout?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(layout?.style).style\">\r\n <ng-container *ngFor=\"let innerLayout of layout.elements\">\r\n <ng-container\r\n [ngSwitch]=\"innerLayout.scope?.reference && itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] ? itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n <!-- Image Control -->\r\n <div *ngSwitchCase=\"'image'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <!-- <img [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n [src]=\"innerLayout?.option?.src ? innerLayout?.option?.src : record[innerLayout.scope?.reference.split('/').pop()]\"\r\n alt=\"{{ innerLayout.label ? innerLayout.label : getProperty(innerLayout.scope?.reference).productSchema.caption }}\"\r\n (click)=\"showImageDetails(innerLayout.option, record)\" /> -->\r\n </div>\r\n\r\n <!-- String Control -->\r\n <div *ngSwitchCase=\"'string'\"\r\n [class]=\"innerLayout.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"innerLayout.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"innerLayout.label?.style?.classes?.[0]\">\r\n {{ innerLayout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3 *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container *ngIf=\"innerLayout.option?.dateFormat; else checkTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.dateFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template #checkTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.timeFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template #normalValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?? '--'\r\n }}\r\n </ng-template>\r\n\r\n </h3>\r\n </div>\r\n\r\n <!-- number Control -->\r\n <div *ngSwitchCase=\"'number'\"\r\n [class]=\"innerLayout.option?.visible ? 'row' : 'hidden'\">\r\n <h3 *ngIf=\"itemInfo.propertySchema[getScope(innerLayout.scope?.reference)] &&itemInfo.propertySchema[getScope(innerLayout.scope?.reference)][innerLayout.scope?.reference.split('/').pop()]?.format.currency\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\">\r\n {{ record[innerLayout.scope?.reference.split('/').pop()] | currency:\r\n innerLayout.option?.currency ?\r\n innerLayout.option.currency\r\n :\r\n 'USD' }}\r\n </h3>\r\n </div>\r\n\r\n <!-- Date Control -->\r\n <div *ngSwitchCase=\"'date'\"\r\n [class]=\"innerLayout.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"innerLayout.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"innerLayout.label?.style?.classes?.[0]\">\r\n {{ innerLayout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3 *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container *ngIf=\"innerLayout.option?.dateFormat; else checkTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.dateFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template #checkTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.timeFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template #normalValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?? '--'\r\n }}\r\n </ng-template>\r\n\r\n </h3>\r\n </div>\r\n\r\n <!-- Time Control -->\r\n <div *ngSwitchCase=\"'time'\"\r\n [class]=\"innerLayout.option?.visible ? 'card-field-wrapper' : 'hidden'\">\r\n\r\n <!-- LABEL -->\r\n <span *ngIf=\"innerLayout.label?.caption\"\r\n [style]=\"getStyleWithoutClasses(innerLayout.label?.style).style\"\r\n [class]=\"innerLayout.label?.style?.classes?.[0]\">\r\n {{ innerLayout.label.caption }}\r\n </span>\r\n\r\n <!-- VALUE -->\r\n <h3 *ngIf=\"innerLayout.option?.protected && innerLayout.option?.visible\"\r\n [class]=\"getStyleWithoutClasses(innerLayout?.scope?.style).classes\"\r\n [style]=\"getStyleWithoutClasses(innerLayout?.scope?.style).style\"\r\n (click)=\"showLinkDetails(innerLayout.option, record)\">\r\n\r\n <!-- DATE FORMAT -->\r\n <ng-container *ngIf=\"innerLayout.option?.dateFormat; else checkTime\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.dateFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n\r\n <!-- TIME FORMAT -->\r\n <ng-template #checkTime>\r\n <ng-container\r\n *ngIf=\"innerLayout.option?.timeFormat; else normalValue\">\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ? (record[innerLayout.scope?.reference.split('/').pop()] | date:\r\n innerLayout.option.timeFormat)\r\n : '--'\r\n }}\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- NORMAL STRING -->\r\n <ng-template #normalValue>\r\n {{\r\n record?.[innerLayout.scope?.reference.split('/').pop()]\r\n ?? '--'\r\n }}\r\n </ng-template>\r\n\r\n </h3>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\">\r\n <button nz-button [style]=\"getStyleWithoutClasses(innerLayout?.style).style\"\r\n [class]=\"innerLayout.option?.visible ? innerLayout.option.protected ? 'disabled-button' : getStyleWithoutClasses(innerLayout?.style).classes : 'hidden'\"\r\n (click)=\"invokeButtonClick(innerLayout, record, k)\">\r\n <ng-container *ngIf=\"!innerLayout.caption; else textContent\">\r\n <i nz-icon [nzType]=\"innerLayout.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ innerLayout.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div *ngIf=\"itemInfo?.footer?.elements && itemInfo?.data && itemInfo?.data.length\"\r\n [class]=\"getStyleWithoutClasses(itemInfo?.footer?.style).classes\">\r\n <span *ngFor=\"let element of itemInfo.footer?.elements; let c = index\">\r\n <ng-container\r\n [ngSwitch]=\"element.scope?.reference && itemInfo.propertySchema[getScope(element.scope?.reference)] ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.type : 'default'\">\r\n\r\n <!-- Date control -->\r\n <div *ngSwitchCase=\"'date'\" class=\"form-group mb-3\">\r\n <span *ngIf=\"element.option.protected\" [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">\r\n <h5>{{\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}\r\n </h5>\r\n </span>\r\n <div *ngIf=\"!element.option.protected\">\r\n <div [class]=\"element?.layout == 'horizontal' ? 'horizontal-layout' : 'row'\">\r\n <label [style]=\"getStyleWithoutClasses(element?.label?.style).style\"\r\n [class]=\"element?.label?.style?.classes[0]\">{{ element.label?.value\r\n ?\r\n element.label?.value : element.label?.caption ?\r\n element.label?.caption :\r\n itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.caption\r\n }}</label>\r\n\r\n <nz-date-picker [required]=\"element.option.required\" [name]=\"element.scope?.reference\"\r\n [nzDisabled]=\"element?.option?.disabled\"\r\n (ngModelChange)=\"dateChangeEvent(element, $event)\"\r\n [nzFormat]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format ? itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()]?.format : 'yyyy-MM-dd'\"\r\n [(ngModel)]=\"itemInfo.propertySchema[getScope(element.scope?.reference)][element.scope?.reference.split('/').pop()].value\"\r\n [style]=\"getStyleWithoutClasses(element?.style).style\"></nz-date-picker>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Button Control -->\r\n <div *ngSwitchCase=\"'default'\" [class]=\"element.option?.visible ? 'row' : 'hidden'\"\r\n (click)=\"invokeOnCardFooter(element)\">\r\n <button nz-button [style]=\"getStyleWithoutClasses(element.style).style\"\r\n [class]=\"element.option.protected ? 'disabled-button' : getStyleWithoutClasses(element.style).classes\">\r\n <ng-container *ngIf=\"!element.caption; else textContent\">\r\n <i nz-icon [nzType]=\"element.icon\" nzTheme=\"outline\"></i>\r\n </ng-container>\r\n <ng-template #textContent>\r\n {{ element.caption }}\r\n </ng-template>\r\n </button>\r\n </div>\r\n </ng-container>\r\n </span>\r\n </div>\r\n <!-- bottom pagination on card -->\r\n <!-- <div *ngIf=\"itemInfo?.layoutSchema?.pagination && itemInfo?.layoutSchema?.pagination?.bottom\">\r\n <app-pagination [itemInfo]=\"itemInfo\" [pageSize]=\"pageSize\" [currentPage]=\"currentPage\" [pages]=\"pages\"\r\n (pageSizeChange)=\"invokeOnPageSizeChange($event)\" (onGoToPage)=\"invokeGoToPage($event)\">\r\n </app-pagination>\r\n </div> -->\r\n</span>" }]
1098
+ }], ctorParameters: () => [{ type: UtilityService }, { type: i1$1.Platform }, { type: i1.HttpClient }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i4.NzModalService }, { type: i5.OAuthService }, { type: RequestService }], propDecorators: { itemInfo: [{
1099
+ type: Input
1100
+ }], currentPage: [{
1101
+ type: Input
1102
+ }], pageSize: [{
1103
+ type: Input
1104
+ }], selectedLanguageInfo: [{
1105
+ type: Input
1106
+ }], pages: [{
1107
+ type: Input
1108
+ }], cardButtonClick: [{
1109
+ type: Output
1110
+ }], cardHeaderButtonClick: [{
1111
+ type: Output
1112
+ }], linkDetails: [{
1113
+ type: Output
1114
+ }], imageDetails: [{
1115
+ type: Output
1116
+ }], onPageSizeChange: [{
1117
+ type: Output
1118
+ }], onPageChange: [{
1119
+ type: Output
1120
+ }] } });
1121
+
1122
+ class FormComponent {
1123
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: FormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1124
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: FormComponent, isStandalone: true, selector: "vt-form", ngImport: i0, template: "<p>form works!</p>\r\n", styles: [""] });
1125
+ }
1126
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: FormComponent, decorators: [{
1127
+ type: Component,
1128
+ args: [{ selector: 'vt-form', imports: [], standalone: true, template: "<p>form works!</p>\r\n" }]
1129
+ }] });
1130
+
1131
+ class PaginationComponent {
1132
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1133
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: PaginationComponent, isStandalone: true, selector: "vt-pagination", ngImport: i0, template: "<p>pagination works!</p>\r\n", styles: [""] });
1134
+ }
1135
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: PaginationComponent, decorators: [{
1136
+ type: Component,
1137
+ args: [{ selector: 'vt-pagination', imports: [], standalone: true, template: "<p>pagination works!</p>\r\n" }]
1138
+ }] });
1139
+
1140
+ // lib/view-toolkit.module.ts
1141
+ class ViewToolkitModule {
1142
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ViewToolkitModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1143
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.2", ngImport: i0, type: ViewToolkitModule, imports: [CommonModule,
1144
+ CardComponent,
1145
+ FormComponent,
1146
+ GridComponent,
1147
+ PaginationComponent], exports: [CardComponent,
1148
+ FormComponent,
1149
+ GridComponent,
1150
+ PaginationComponent] });
1151
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ViewToolkitModule, imports: [CommonModule,
1152
+ CardComponent] });
1153
+ }
1154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ViewToolkitModule, decorators: [{
1155
+ type: NgModule,
1156
+ args: [{
1157
+ imports: [
1158
+ CommonModule,
1159
+ CardComponent,
1160
+ FormComponent,
1161
+ GridComponent,
1162
+ PaginationComponent
1163
+ ],
1164
+ exports: [
1165
+ CardComponent,
1166
+ FormComponent,
1167
+ GridComponent,
1168
+ PaginationComponent
1169
+ ]
1170
+ }]
1171
+ }] });
1172
+
1173
+ // AUTO-GENERATED. Do not edit.
1174
+ const APP_VERSION = '1.0.204';
1175
+
1176
+ const VERSION_KEY = 'APP_VERSION';
1177
+ class AppVersionResetService {
1178
+ platform;
1179
+ constructor(platform) {
1180
+ this.platform = platform;
1181
+ }
1182
+ async run() {
1183
+ if (this.platform.ANDROID || this.platform.IOS) {
1184
+ await this.clearNativeIfChanged();
1185
+ // this.clearWebIfChanged();
1186
+ // return;
1187
+ }
1188
+ }
1189
+ async clearNativeIfChanged() {
1190
+ const { value: savedVersion } = await Preferences.get({ key: VERSION_KEY });
1191
+ if (savedVersion === APP_VERSION)
1192
+ return;
1193
+ console.log(`🧹 Clearing Capacitor Preferences (new build ${APP_VERSION})`);
1194
+ await Preferences.clear();
1195
+ this.clearWebStores();
1196
+ await Preferences.set({ key: VERSION_KEY, value: APP_VERSION });
1197
+ }
1198
+ // private clearWebIfChanged(): void {
1199
+ // const savedVersion = sessionStorage.getItem(VERSION_KEY) || localStorage.getItem(VERSION_KEY);
1200
+ // if (savedVersion === APP_VERSION) return;
1201
+ // this.clearWebStores();
1202
+ // localStorage.setItem(VERSION_KEY, APP_VERSION);
1203
+ // sessionStorage.setItem(VERSION_KEY, APP_VERSION);
1204
+ // }
1205
+ clearWebStores() {
1206
+ try {
1207
+ localStorage.clear();
1208
+ }
1209
+ catch { }
1210
+ try {
1211
+ sessionStorage.clear();
1212
+ }
1213
+ catch { }
1214
+ try {
1215
+ if (typeof document !== 'undefined' && document.cookie) {
1216
+ document.cookie.split(';').forEach((c) => {
1217
+ const eqPos = c.indexOf('=');
1218
+ const name = eqPos > -1 ? c.substring(0, eqPos).trim() : c.trim();
1219
+ if (name) {
1220
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
1221
+ }
1222
+ });
1223
+ }
1224
+ }
1225
+ catch { }
1226
+ }
1227
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AppVersionResetService, deps: [{ token: i1$1.Platform }], target: i0.ɵɵFactoryTarget.Injectable });
1228
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AppVersionResetService, providedIn: 'root' });
1229
+ }
1230
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AppVersionResetService, decorators: [{
1231
+ type: Injectable,
1232
+ args: [{
1233
+ providedIn: 'root'
1234
+ }]
1235
+ }], ctorParameters: () => [{ type: i1$1.Platform }] });
1236
+
1237
+ class Couchdb {
1238
+ utilityService;
1239
+ couchDbBaseUrl = 'https://couchdb.yomotech.de';
1240
+ constructor(utilityService) {
1241
+ this.utilityService = utilityService;
1242
+ }
1243
+ async getTenantDatabases(tenantKey) {
1244
+ if (!tenantKey || !tenantKey.trim()) {
1245
+ throw new Error('Missing tenantKey');
1246
+ }
1247
+ const response = await fetch(`https://couchdb.yomotech.de/tenant-dbs`, {
1248
+ method: 'GET',
1249
+ headers: {
1250
+ Accept: 'application/json',
1251
+ 'X-Tenant-Key': tenantKey.trim(),
1252
+ },
1253
+ });
1254
+ const data = await this.parseJsonOrText(response);
1255
+ if (!response.ok) {
1256
+ throw new Error(`GET /tenant-dbs -> ${response.status} ${this.stringifyErrorDetails(data)}`);
1257
+ }
1258
+ return data;
1259
+ }
1260
+ async parseJsonOrText(response) {
1261
+ const rawText = await response.text();
1262
+ if (!rawText)
1263
+ return null;
1264
+ try {
1265
+ return JSON.parse(rawText);
1266
+ }
1267
+ catch {
1268
+ return rawText;
1269
+ }
1270
+ }
1271
+ stringifyErrorDetails(data) {
1272
+ if (typeof data === 'string')
1273
+ return data;
1274
+ try {
1275
+ return JSON.stringify(data);
1276
+ }
1277
+ catch {
1278
+ return 'Unknown error';
1279
+ }
1280
+ }
1281
+ async getFileContentFromCouchDb(couchDbName, filePath) {
1282
+ try {
1283
+ const dbName = couchDbName;
1284
+ console.log('dbName: ', dbName);
1285
+ console.log('filePath: ', filePath);
1286
+ const docId = filePath?.trim();
1287
+ if (!docId) {
1288
+ console.error('Missing file path');
1289
+ return null;
1290
+ }
1291
+ const response = await fetch(this.getDocumentUrl(dbName, docId), {
1292
+ method: 'GET',
1293
+ headers: await this.getReadHeaders(),
1294
+ });
1295
+ const doc = await this.parseJsonOrText(response);
1296
+ if (!response.ok) {
1297
+ console.error(`Failed to fetch file "${docId}" from "${dbName}": ${response.status}`, doc);
1298
+ return null;
1299
+ }
1300
+ if (!doc?.data) {
1301
+ console.error(`Document "${docId}" does not contain file data`);
1302
+ return null;
1303
+ }
1304
+ // do not decode images as utf8 text
1305
+ if (this.isImageFile(doc.name || doc.path || docId, doc.contentType)) {
1306
+ return {
1307
+ type: 'base64file',
1308
+ mimeType: doc.contentType || this.getImageMimeType(docId),
1309
+ base64: doc.data,
1310
+ };
1311
+ }
1312
+ const decodedContent = this.fromBase64(doc.data);
1313
+ if (this.isJsonFile(doc.name || doc.path || docId, doc.contentType)) {
1314
+ try {
1315
+ return JSON.parse(decodedContent);
1316
+ }
1317
+ catch (jsonError) {
1318
+ console.error(`Failed to parse JSON for file "${docId}"`, jsonError);
1319
+ return decodedContent;
1320
+ }
1321
+ }
1322
+ return decodedContent;
1323
+ }
1324
+ catch (error) {
1325
+ console.error(`Unexpected error while fetching file "${filePath}" from "${couchDbName}"`, error);
1326
+ return null;
1327
+ }
1328
+ }
1329
+ isImageFile(fileNameOrPath, contentType) {
1330
+ const lower = (fileNameOrPath || '').toLowerCase();
1331
+ return (lower.endsWith('.png') ||
1332
+ lower.endsWith('.jpg') ||
1333
+ lower.endsWith('.jpeg') ||
1334
+ lower.endsWith('.ico') ||
1335
+ lower.endsWith('.svg') ||
1336
+ (contentType || '').startsWith('image/'));
1337
+ }
1338
+ getImageMimeType(fileNameOrPath) {
1339
+ const lower = (fileNameOrPath || '').toLowerCase();
1340
+ if (lower.endsWith('.png'))
1341
+ return 'image/png';
1342
+ if (lower.endsWith('.jpg') || lower.endsWith('.jpeg'))
1343
+ return 'image/jpeg';
1344
+ if (lower.endsWith('.ico'))
1345
+ return 'image/x-icon';
1346
+ if (lower.endsWith('.svg'))
1347
+ return 'image/svg+xml';
1348
+ return 'image/png';
1349
+ }
1350
+ fromBase64(base64) {
1351
+ try {
1352
+ return decodeURIComponent(escape(atob(base64)));
1353
+ }
1354
+ catch {
1355
+ return atob(base64);
1356
+ }
1357
+ }
1358
+ isJsonFile(fileNameOrPath, contentType) {
1359
+ const lower = (fileNameOrPath || '').toLowerCase();
1360
+ return lower.endsWith('.json') || contentType === 'application/json';
1361
+ }
1362
+ getDocumentUrl(dbName, docId) {
1363
+ return `${this.getDbUrl(dbName)}/${encodeURIComponent(docId)}`;
1364
+ }
1365
+ getDbUrl(dbName) {
1366
+ return `${this.couchDbBaseUrl}/${dbName}`;
1367
+ }
1368
+ async getReadHeaders() {
1369
+ return {
1370
+ Accept: 'application/json',
1371
+ ...(await this.buildTenantHeaders()),
1372
+ };
1373
+ }
1374
+ async buildTenantHeaders() {
1375
+ let tenantKey = await this.utilityService.getStorage('tenantKey');
1376
+ let tenantName = await this.utilityService.getStorage('tenantName');
1377
+ if (typeof tenantKey !== 'string' || !tenantKey.trim()) {
1378
+ return {
1379
+ 'X-Tenant-Key': tenantKey.trim(),
1380
+ };
1381
+ }
1382
+ else if (typeof tenantName !== 'string' || !tenantName.trim()) {
1383
+ return {
1384
+ 'X-Tenant': tenantName.trim(),
1385
+ };
1386
+ }
1387
+ throw new Error('Missing tenantKey');
1388
+ }
1389
+ async getImageSrcFromCouchDb(couchDbName, filePath) {
1390
+ const dbName = couchDbName;
1391
+ const docId = filePath?.trim();
1392
+ if (!docId) {
1393
+ throw new Error('Missing file path');
1394
+ }
1395
+ const response = await fetch(this.getDocumentUrl(dbName, docId), {
1396
+ method: 'GET',
1397
+ headers: await this.getReadHeaders(),
1398
+ });
1399
+ const doc = await this.parseJsonOrText(response);
1400
+ if (!response.ok) {
1401
+ throw new Error(`Failed to fetch image "${docId}" from "${dbName}": ${response.status} ${this.stringifyErrorDetails(doc)}`);
1402
+ }
1403
+ if (!doc?.data) {
1404
+ throw new Error(`Document "${docId}" does not contain image data`);
1405
+ }
1406
+ const mimeType = doc.contentType || 'image/png';
1407
+ return `data:${mimeType};base64,${doc.data}`;
1408
+ }
1409
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Couchdb, deps: [{ token: UtilityService }], target: i0.ɵɵFactoryTarget.Injectable });
1410
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Couchdb, providedIn: 'root' });
1411
+ }
1412
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Couchdb, decorators: [{
1413
+ type: Injectable,
1414
+ args: [{
1415
+ providedIn: 'root',
1416
+ }]
1417
+ }], ctorParameters: () => [{ type: UtilityService }] });
1418
+
1419
+ class ConfigService {
1420
+ couchdbService;
1421
+ utilityService;
1422
+ platform;
1423
+ config;
1424
+ skipOkta = false;
1425
+ keycloakConfig;
1426
+ constructor(couchdbService, utilityService, platform) {
1427
+ this.couchdbService = couchdbService;
1428
+ this.utilityService = utilityService;
1429
+ this.platform = platform;
1430
+ }
1431
+ async loadOktaConfig(projectName) {
1432
+ try {
1433
+ let tenantKey = "";
1434
+ let tenantName = "";
1435
+ if (this.platform.ANDROID || this.platform.IOS) {
1436
+ tenantKey = await this.utilityService.getLocalStorage('tenantKey');
1437
+ tenantName = await this.utilityService.getLocalStorage('tenantName');
1438
+ }
1439
+ else {
1440
+ tenantKey = await this.utilityService.getStorage('tenantKey');
1441
+ tenantName = await this.utilityService.getStorage('tenantName');
1442
+ }
1443
+ this.config = await this.couchdbService.getFileContentFromCouchDb(`${tenantName}_${projectName}`, 'environments/environment.json');
1444
+ if (this.platform.ANDROID || this.platform.IOS) {
1445
+ if (this.config.environment.login.mobile) {
1446
+ this.setConfiguration(this.config.environment.login.mobile);
1447
+ }
1448
+ else {
1449
+ this.setConfiguration(null);
1450
+ }
1451
+ }
1452
+ else {
1453
+ if (this.config.environment.login.web) {
1454
+ this.setConfiguration(this.config.environment.login.web);
1455
+ }
1456
+ else {
1457
+ this.setConfiguration(null);
1458
+ }
1459
+ }
1460
+ }
1461
+ catch (err) {
1462
+ console.error('Error loading config:', err);
1463
+ }
1464
+ }
1465
+ setConfiguration(config) {
1466
+ if (config) {
1467
+ this.config = config;
1468
+ }
1469
+ else {
1470
+ this.config = {
1471
+ issuer: 'http://dummy',
1472
+ clientId: 'dummy',
1473
+ redirectUri: 'http://dummy',
1474
+ pkce: true,
1475
+ };
1476
+ }
1477
+ }
1478
+ skipOktaConfig() {
1479
+ this.skipOkta = true;
1480
+ }
1481
+ get oktaConfig() {
1482
+ if (this.skipOkta) {
1483
+ return null;
1484
+ }
1485
+ return this.config;
1486
+ }
1487
+ async loadKeycloakConfig(projectName) {
1488
+ let tenantKey = "";
1489
+ let tenantName = "";
1490
+ if (this.platform.ANDROID || this.platform.IOS) {
1491
+ tenantKey = await this.utilityService.getLocalStorage('tenantKey');
1492
+ tenantName = await this.utilityService.getLocalStorage('tenantName');
1493
+ }
1494
+ else {
1495
+ tenantKey = await this.utilityService.getStorage('tenantKey');
1496
+ tenantName = await this.utilityService.getStorage('tenantName');
1497
+ }
1498
+ const env = await this.couchdbService.getFileContentFromCouchDb(`${tenantName}_${projectName}`, 'environments/environment.json');
1499
+ if (env?.environment?.login.type === "keycloak") {
1500
+ if (this.platform.ANDROID || this.platform.IOS) {
1501
+ this.keycloakConfig = {
1502
+ issuer: "https://keycloak-poc.wilken.de/realms/p5",
1503
+ clientId: "mobile",
1504
+ redirectUri: "de.yomotech:/login/callback",
1505
+ logoutRedirectUri: "de.yomotech:/login/callback",
1506
+ scope: "openid profile email",
1507
+ responseType: "code"
1508
+ };
1509
+ }
1510
+ else {
1511
+ this.keycloakConfig = {
1512
+ issuer: env?.environment?.login?.web?.issuer ?? 'http://dummy',
1513
+ clientId: env?.environment?.login?.web?.clientId ?? 'dummy',
1514
+ redirectUri: window.location.origin,
1515
+ responseType: 'code',
1516
+ scope: 'openid profile email',
1517
+ showDebugInformation: true
1518
+ };
1519
+ }
1520
+ }
1521
+ else {
1522
+ this.keycloakConfig = {};
1523
+ }
1524
+ }
1525
+ getKeycloakConfig() {
1526
+ return this.keycloakConfig;
1527
+ }
1528
+ getKeycloakMobileConfig() {
1529
+ if (!this.keycloakConfig)
1530
+ return null;
1531
+ return {
1532
+ issuer: this.keycloakConfig?.issuer,
1533
+ clientId: this.keycloakConfig?.clientId,
1534
+ redirectUri: this.keycloakConfig.redirectUri,
1535
+ logoutRedirectUri: this.keycloakConfig.logoutRedirectUri,
1536
+ scope: this.keycloakConfig.scope,
1537
+ responseType: this.keycloakConfig.responseType
1538
+ };
1539
+ }
1540
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ConfigService, deps: [{ token: Couchdb }, { token: UtilityService }, { token: i1$1.Platform }], target: i0.ɵɵFactoryTarget.Injectable });
1541
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ConfigService, providedIn: 'root' });
1542
+ }
1543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ConfigService, decorators: [{
1544
+ type: Injectable,
1545
+ args: [{
1546
+ providedIn: 'root'
1547
+ }]
1548
+ }], ctorParameters: () => [{ type: Couchdb }, { type: UtilityService }, { type: i1$1.Platform }] });
1549
+
1550
+ class MobileKeycloakService {
1551
+ config;
1552
+ http;
1553
+ utilityService;
1554
+ platform;
1555
+ tokens = null;
1556
+ constructor(config, http, utilityService, platform) {
1557
+ this.config = config;
1558
+ this.http = http;
1559
+ this.utilityService = utilityService;
1560
+ this.platform = platform;
1561
+ if (Capacitor.isNativePlatform()) {
1562
+ App.addListener('appUrlOpen', async (url) => {
1563
+ // Nothing to do here; capacitor-oauth2 resolves internally.
1564
+ // Keep listener to satisfy deep link expectations.
1565
+ });
1566
+ }
1567
+ }
1568
+ async login() {
1569
+ if (!Capacitor.isNativePlatform())
1570
+ return null;
1571
+ const cfg = this.config.getKeycloakMobileConfig();
1572
+ const discoveryUrl = `${cfg.issuer}/.well-known/openid-configuration`;
1573
+ const discovery = await (await fetch(discoveryUrl)).json();
1574
+ const result = await OAuth2Client.authenticate({
1575
+ appId: cfg.clientId, // <--- Keycloak clientId goes here
1576
+ authorizationBaseUrl: discovery.authorization_endpoint,
1577
+ accessTokenEndpoint: discovery.token_endpoint,
1578
+ responseType: 'code',
1579
+ redirectUrl: cfg.redirectUri,
1580
+ scope: cfg.scope,
1581
+ pkceEnabled: true,
1582
+ logsEnabled: true
1583
+ });
1584
+ console.log('result-KEyClaok: ', result);
1585
+ this.tokens = {
1586
+ access_token: result?.access_token_response?.access_token ? result?.access_token_response?.access_token : result.access_token,
1587
+ refresh_token: result?.access_token_response?.refresh_token,
1588
+ id_token: result?.access_token_response?.id_token,
1589
+ expires_in: result?.access_token_response?.expires_at ? result?.access_token_response?.expires_at : result?.access_token_response?.expires_in,
1590
+ token_type: result?.access_token_response?.token_type
1591
+ };
1592
+ let keycloakLoginUser = "";
1593
+ if (this.tokens.access_token) {
1594
+ keycloakLoginUser = await this.getUserInfo(this.tokens.access_token, cfg.issuer);
1595
+ console.log('keycloakLoginUser: ', keycloakLoginUser);
1596
+ if (keycloakLoginUser) {
1597
+ this.tokens['issuer'] = cfg.issuer;
1598
+ this.utilityService.setLocalStorage("KeycloakInfo", this.tokens);
1599
+ if (this.platform.ANDROID || this.platform.IOS) {
1600
+ window.location.reload();
1601
+ }
1602
+ }
1603
+ }
1604
+ return keycloakLoginUser;
1605
+ }
1606
+ async getUserInfo(accessToken, issuer) {
1607
+ try {
1608
+ const headers = new HttpHeaders({
1609
+ Authorization: `Bearer ${accessToken}`,
1610
+ });
1611
+ const url = `${issuer}/protocol/openid-connect/userinfo`;
1612
+ return await this.http.get(url, { headers }).toPromise();
1613
+ }
1614
+ catch (err) {
1615
+ console.error('Error fetching user info:', err);
1616
+ throw err;
1617
+ }
1618
+ }
1619
+ getAccessToken() {
1620
+ return this.tokens?.access_token ?? null;
1621
+ }
1622
+ getRefreshToken() {
1623
+ return this.tokens?.refresh_token ?? null;
1624
+ }
1625
+ async logout() {
1626
+ const keycloakInfo = await this.utilityService.getLocalStorage('KeycloakInfo');
1627
+ const cfg = this.config.getKeycloakMobileConfig();
1628
+ const idToken = keycloakInfo?.keycloakInfo?.id_token;
1629
+ const accessToken = keycloakInfo?.keycloakInfo?.access_token;
1630
+ if (!idToken || !accessToken) {
1631
+ console.warn('No tokens found for logout');
1632
+ return;
1633
+ }
1634
+ const endSessionUrl = `${cfg.issuer}/protocol/openid-connect/logout` +
1635
+ `?id_token_hint=${encodeURIComponent(idToken)}` +
1636
+ `&client_id=${encodeURIComponent(cfg.clientId)}` +
1637
+ `&post_logout_redirect_uri=${encodeURIComponent(cfg.logoutRedirectUri)}`;
1638
+ console.log('Logout URL:', endSessionUrl);
1639
+ await Browser.open({ url: endSessionUrl });
1640
+ this.tokens = null;
1641
+ await this.utilityService.removeLocalStorage('KeycloakInfo');
1642
+ window.location.reload();
1643
+ }
1644
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MobileKeycloakService, deps: [{ token: ConfigService }, { token: i1.HttpClient }, { token: UtilityService }, { token: i1$1.Platform }], target: i0.ɵɵFactoryTarget.Injectable });
1645
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MobileKeycloakService, providedIn: 'root' });
1646
+ }
1647
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MobileKeycloakService, decorators: [{
1648
+ type: Injectable,
1649
+ args: [{
1650
+ providedIn: 'root'
1651
+ }]
1652
+ }], ctorParameters: () => [{ type: ConfigService }, { type: i1.HttpClient }, { type: UtilityService }, { type: i1$1.Platform }] });
1653
+
1654
+ class NetworkLogService {
1655
+ logs = [];
1656
+ addLog(log) {
1657
+ this.logs.unshift(log); // latest first
1658
+ localStorage.setItem('networkLogs', JSON.stringify(this.logs));
1659
+ }
1660
+ getLogsByDate(date) {
1661
+ return this.logs.filter(l => l.date === date);
1662
+ }
1663
+ getAll() {
1664
+ return [...this.logs];
1665
+ }
1666
+ clear() {
1667
+ this.logs = [];
1668
+ localStorage.removeItem('networkLogs');
1669
+ }
1670
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NetworkLogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1671
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NetworkLogService, providedIn: 'root' });
1672
+ }
1673
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NetworkLogService, decorators: [{
1674
+ type: Injectable,
1675
+ args: [{
1676
+ providedIn: 'root'
1677
+ }]
1678
+ }] });
1679
+
1680
+ class NotificationService {
1681
+ toastr;
1682
+ constructor(toastr) {
1683
+ this.toastr = toastr;
1684
+ }
1685
+ success(message, time = 5000) {
1686
+ this.toastr.success(message, "", { messageClass: 'toaster-font', titleClass: 'toaster-font', closeButton: true, timeOut: time });
1687
+ }
1688
+ info(message, time = 5000) {
1689
+ this.toastr.info(message, "", { messageClass: 'toaster-font', titleClass: 'toaster-font', closeButton: true, timeOut: time });
1690
+ }
1691
+ warning(message, time = 20000) {
1692
+ this.toastr.warning(message, "", { messageClass: 'toaster-font', titleClass: 'toaster-font', closeButton: true, timeOut: time });
1693
+ }
1694
+ error(error, time = 20000, message) {
1695
+ this.toastr.error(error, message, { messageClass: 'toaster-font', titleClass: 'toaster-font', closeButton: true, timeOut: time });
1696
+ }
1697
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NotificationService, deps: [{ token: i1$2.ToastrService }], target: i0.ɵɵFactoryTarget.Injectable });
1698
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NotificationService, providedIn: 'root' });
1699
+ }
1700
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NotificationService, decorators: [{
1701
+ type: Injectable,
1702
+ args: [{
1703
+ providedIn: 'root'
1704
+ }]
1705
+ }], ctorParameters: () => [{ type: i1$2.ToastrService }] });
1706
+
1707
+ class PouchdbService {
1708
+ db = new PouchDB("");
1709
+ async uploadAndStoreZip(zipFile, couchDbURl) {
1710
+ const zip = await JSZip.loadAsync(zipFile);
1711
+ const fileName = zipFile?.name?.replace('.zip', '');
1712
+ const envFilePath = `${fileName}/environments/environment.json`;
1713
+ const envFile = zip.file(envFilePath);
1714
+ if (envFile && !couchDbURl) {
1715
+ const envFileContent = await envFile.async('string');
1716
+ try {
1717
+ const jsonData = JSON.parse(envFileContent);
1718
+ if (jsonData?.environment?.couchdbUrl) {
1719
+ this.db = new PouchDB(jsonData.environment.couchdbUrl);
1720
+ }
1721
+ }
1722
+ catch (e) {
1723
+ console.error('Invalid JSON in environment.json:', e);
1724
+ }
1725
+ }
1726
+ else {
1727
+ this.db = new PouchDB(couchDbURl);
1728
+ }
1729
+ // Proceed to upload all files
1730
+ const savePromises = [];
1731
+ zip.forEach((relativePath, file) => {
1732
+ if (!file.dir) {
1733
+ savePromises.push(file.async('base64').then((content) => {
1734
+ const docId = relativePath.toString();
1735
+ console.log('docId: ', docId);
1736
+ return this.db.put({
1737
+ _id: docId,
1738
+ data: content,
1739
+ type: 'file',
1740
+ contentType: this.getMimeType(file.name)
1741
+ }).catch((err) => {
1742
+ if (err.status === 409) {
1743
+ return this.db.get(docId).then((existing) => {
1744
+ return this.db.put({
1745
+ ...existing,
1746
+ data: content,
1747
+ contentType: this.getMimeType(file.name)
1748
+ });
1749
+ });
1750
+ }
1751
+ throw err;
1752
+ });
1753
+ }));
1754
+ }
1755
+ });
1756
+ await Promise.all(savePromises);
1757
+ }
1758
+ async getFile(path, remoteDB) {
1759
+ try {
1760
+ if (remoteDB) {
1761
+ this.db = new PouchDB(remoteDB);
1762
+ }
1763
+ const doc = await this.db.get(path);
1764
+ return this.decodeBlob(doc);
1765
+ }
1766
+ catch (err) {
1767
+ if (err.status === 404 && remoteDB) {
1768
+ try {
1769
+ const remoteDoc = await this.db.get(path);
1770
+ return this.decodeBlob(remoteDoc);
1771
+ }
1772
+ catch (remoteErr) {
1773
+ throw remoteErr;
1774
+ }
1775
+ }
1776
+ else {
1777
+ throw err;
1778
+ }
1779
+ }
1780
+ }
1781
+ decodeBlob(doc) {
1782
+ const byteCharacters = atob(doc.data);
1783
+ const byteNumbers = new Array(byteCharacters.length).fill(0).map((_, i) => byteCharacters.charCodeAt(i));
1784
+ const byteArray = new Uint8Array(byteNumbers);
1785
+ return new Blob([byteArray], { type: doc.contentType });
1786
+ }
1787
+ async getTextFile(path, remotedbUrl) {
1788
+ const blob = await this.getFile(path, remotedbUrl);
1789
+ if (blob?.type && blob?.type === 'application/x-x509-ca-cert') {
1790
+ const base64Der = await this.blobToBase64(blob);
1791
+ return base64Der;
1792
+ }
1793
+ if (blob?.type && blob?.type.startsWith('image/')) {
1794
+ return URL.createObjectURL(blob);
1795
+ }
1796
+ else if (blob?.type && blob?.type === 'application/json') {
1797
+ const text = await blob.text();
1798
+ return JSON.parse(text);
1799
+ }
1800
+ else {
1801
+ return await blob.text();
1802
+ }
1803
+ }
1804
+ blobToBase64(blob) {
1805
+ return new Promise((resolve, reject) => {
1806
+ const reader = new FileReader();
1807
+ reader.onloadend = () => {
1808
+ const base64 = reader.result.split(',')[1];
1809
+ resolve(base64);
1810
+ };
1811
+ reader.onerror = reject;
1812
+ reader.readAsDataURL(blob);
1813
+ });
1814
+ }
1815
+ getMimeType(fileName) {
1816
+ const extension = fileName.split('.').pop()?.toLowerCase();
1817
+ const mimeMap = {
1818
+ 'json': 'application/json',
1819
+ 'css': 'text/css',
1820
+ 'scss': 'text/x-scss',
1821
+ 'jpg': 'image/jpeg',
1822
+ 'jpeg': 'image/jpeg',
1823
+ 'png': 'image/png',
1824
+ 'ico': 'image/x-icon',
1825
+ 'svg': 'image/svg+xml',
1826
+ 'html': 'text/html',
1827
+ 'js': 'application/javascript',
1828
+ 'ts': 'application/typescript',
1829
+ 'txt': 'text/plain',
1830
+ 'der': 'application/x-x509-ca-cert'
1831
+ };
1832
+ return mimeMap[extension || ''] || 'application/octet-stream';
1833
+ }
1834
+ async getAllDatabasesWithContent(couchdbBaseUrl) {
1835
+ const connStr = couchdbBaseUrl;
1836
+ const urlObj = new URL(connStr);
1837
+ const credentials = `${urlObj.username}:${urlObj.password}`;
1838
+ const originalPortMatch = connStr.match(/:(\d+)(?=\/|$)/);
1839
+ const port = originalPortMatch ? originalPortMatch[1] : "";
1840
+ const baseUrl = `${urlObj.protocol}//${urlObj.hostname}${port ? `:${port}` : ""}`;
1841
+ const authHeader = {
1842
+ 'Authorization': 'Basic ' + btoa(`${credentials}`)
1843
+ };
1844
+ const response = await fetch(`${baseUrl}/_all_dbs`, {
1845
+ headers: authHeader
1846
+ });
1847
+ if (!response.ok) {
1848
+ throw new Error(`Error fetching databases: ${response.statusText}`);
1849
+ }
1850
+ const dbNames = await response.json();
1851
+ const results = [];
1852
+ for (const dbName of dbNames) {
1853
+ try {
1854
+ const docsResponse = await fetch(`${baseUrl}/${dbName}/_all_docs?limit=1`, {
1855
+ headers: authHeader
1856
+ });
1857
+ if (!docsResponse.ok) {
1858
+ results.push({ databaseName: dbName, content: false });
1859
+ continue;
1860
+ }
1861
+ const docsData = await docsResponse.json();
1862
+ results.push({
1863
+ databaseName: dbName,
1864
+ content: docsData.total_rows > 0
1865
+ });
1866
+ }
1867
+ catch (err) {
1868
+ console.log('err: ', err);
1869
+ results.push({ databaseName: dbName, content: false });
1870
+ }
1871
+ }
1872
+ return results;
1873
+ }
1874
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: PouchdbService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1875
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: PouchdbService, providedIn: 'root' });
1876
+ }
1877
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: PouchdbService, decorators: [{
1878
+ type: Injectable,
1879
+ args: [{
1880
+ providedIn: 'root'
1881
+ }]
1882
+ }] });
1883
+
1884
+ /*
1885
+ * Public API Surface of view-toolkit
1886
+ */
1887
+
1888
+ /**
1889
+ * Generated bundle index. Do not edit.
1890
+ */
1891
+
1892
+ export { AppVersionResetService, CardComponent, ConfigService, Couchdb, FormComponent, GridComponent, MobileKeycloakService, NetworkLogService, NotificationService, PaginationComponent, PouchdbService, RequestService, UtilityService, ViewToolkitModule };
1893
+ //# sourceMappingURL=yomotech-view-toolkit.mjs.map