@yomotech/view-toolkit 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ng-package.json +7 -0
- package/package.json +36 -22
- package/src/lib/app-version.ts +2 -0
- package/src/lib/containers/card/card.component.css +0 -0
- package/src/lib/containers/card/card.component.html +449 -0
- package/src/lib/containers/card/card.component.ts +471 -0
- package/src/lib/containers/form/form.component.css +0 -0
- package/src/lib/containers/form/form.component.html +1 -0
- package/src/lib/containers/form/form.component.ts +12 -0
- package/src/lib/containers/grid/grid.component.css +0 -0
- package/src/lib/containers/grid/grid.component.html +1 -0
- package/src/lib/containers/grid/grid.component.ts +12 -0
- package/src/lib/containers/pagination/pagination.component.css +0 -0
- package/src/lib/containers/pagination/pagination.component.html +1 -0
- package/src/lib/containers/pagination/pagination.component.ts +12 -0
- package/src/lib/services/app-version-reset.service.ts +59 -0
- package/src/lib/services/config.service.ts +128 -0
- package/src/lib/services/couchdb.ts +224 -0
- package/src/lib/services/mobile-keycloak.service.ts +116 -0
- package/src/lib/services/network-log.service.ts +27 -0
- package/src/lib/services/notification.service.ts +26 -0
- package/src/lib/services/pouchdb.service.ts +183 -0
- package/src/lib/services/request.service.ts +125 -0
- package/src/lib/services/utility.service.ts +593 -0
- package/src/lib/view-toolkit.module.ts +25 -0
- package/src/lib/view-toolkit.spec.ts +23 -0
- package/src/lib/view-toolkit.ts +15 -0
- package/src/public-api.ts +22 -0
- package/tsconfig.lib.json +17 -0
- package/tsconfig.lib.prod.json +11 -0
- package/tsconfig.spec.json +15 -0
- package/fesm2022/abdulahad-view-toolkit.mjs +0 -94
- package/fesm2022/abdulahad-view-toolkit.mjs.map +0 -1
- package/fesm2022/abdulahad061-view-toolkit.mjs +0 -94
- package/fesm2022/abdulahad061-view-toolkit.mjs.map +0 -1
- package/fesm2022/yomotech-view-toolkit.mjs +0 -95
- package/fesm2022/yomotech-view-toolkit.mjs.map +0 -1
- package/types/abdulahad-view-toolkit.d.ts +0 -33
- package/types/abdulahad061-view-toolkit.d.ts +0 -33
- package/types/yomotech-view-toolkit.d.ts +0 -30
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { ChangeDetectorRef, Component, EventEmitter, Input, NgZone, Output } from '@angular/core';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { UtilityService } from '../../services/utility.service';
|
|
5
|
+
import { RequestService } from '../../services/request.service';
|
|
6
|
+
|
|
7
|
+
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
8
|
+
import { SimpleChanges } from '@angular/core';
|
|
9
|
+
import { OAuthService } from 'angular-oauth2-oidc';
|
|
10
|
+
import { CapacitorHttp } from '@capacitor/core';
|
|
11
|
+
|
|
12
|
+
import { NzIconModule } from 'ng-zorro-antd/icon';
|
|
13
|
+
import { NzButtonModule } from 'ng-zorro-antd/button';
|
|
14
|
+
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
|
|
15
|
+
import { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';
|
|
16
|
+
|
|
17
|
+
import { DatePickerModule } from 'primeng/datepicker';
|
|
18
|
+
import { Platform } from '@angular/cdk/platform';
|
|
19
|
+
|
|
20
|
+
@Component({
|
|
21
|
+
selector: 'vt-card',
|
|
22
|
+
imports: [
|
|
23
|
+
CommonModule,
|
|
24
|
+
FormsModule,
|
|
25
|
+
NzIconModule,
|
|
26
|
+
DatePickerModule,
|
|
27
|
+
NzButtonModule,
|
|
28
|
+
NzDatePickerModule,
|
|
29
|
+
NzModalModule,
|
|
30
|
+
// StringComponent,
|
|
31
|
+
// PaginationComponent
|
|
32
|
+
],
|
|
33
|
+
standalone: true,
|
|
34
|
+
templateUrl: './card.component.html',
|
|
35
|
+
styleUrl: './card.component.css',
|
|
36
|
+
})
|
|
37
|
+
export class CardComponent {
|
|
38
|
+
@Input() itemInfo: any = {};
|
|
39
|
+
@Input() currentPage: number = 0;
|
|
40
|
+
@Input() pageSize: number = 5;
|
|
41
|
+
@Input() selectedLanguageInfo: any = {};
|
|
42
|
+
@Input() pages: number[] = [];
|
|
43
|
+
@Output() cardButtonClick: EventEmitter<any> = new EventEmitter();
|
|
44
|
+
@Output() cardHeaderButtonClick: EventEmitter<any> = new EventEmitter();
|
|
45
|
+
@Output() linkDetails: EventEmitter<any> = new EventEmitter();
|
|
46
|
+
@Output() imageDetails: EventEmitter<any> = new EventEmitter();
|
|
47
|
+
@Output() onPageSizeChange: EventEmitter<any> = new EventEmitter();
|
|
48
|
+
@Output() onPageChange: EventEmitter<any> = new EventEmitter();
|
|
49
|
+
cardPerRow: string = "col-12 md:col-6 lg:col-";
|
|
50
|
+
isLoading: boolean = false;
|
|
51
|
+
layoutSchemaCopy: any = {};
|
|
52
|
+
headerSchemaCopy: any = {};
|
|
53
|
+
footerSchemaCopy: any = {};
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
constructor(
|
|
57
|
+
private utilityService: UtilityService,
|
|
58
|
+
private platform: Platform,
|
|
59
|
+
private http: HttpClient,
|
|
60
|
+
private cdr: ChangeDetectorRef,
|
|
61
|
+
private zone: NgZone,
|
|
62
|
+
private modalService: NzModalService,
|
|
63
|
+
private oauthService: OAuthService,
|
|
64
|
+
private requestService: RequestService) {
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
ngOnInit() {
|
|
68
|
+
if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
|
|
69
|
+
this.cardPerRow = "col-";
|
|
70
|
+
} else {
|
|
71
|
+
this.cardPerRow = "col-12 md:col-6 lg:col-";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
76
|
+
if (changes['itemInfo']) {
|
|
77
|
+
if (this.itemInfo.layoutSchema) {
|
|
78
|
+
this.layoutSchemaCopy = JSON.parse(JSON.stringify(this.itemInfo.layoutSchema));
|
|
79
|
+
}
|
|
80
|
+
if (this.itemInfo.header) {
|
|
81
|
+
this.headerSchemaCopy = JSON.parse(JSON.stringify(this.itemInfo.header));
|
|
82
|
+
}
|
|
83
|
+
if (this.itemInfo.footer) {
|
|
84
|
+
this.footerSchemaCopy = JSON.parse(JSON.stringify(this.itemInfo.footer));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if ((changes['selectedLanguageInfo'] || this.selectedLanguageInfo) && this.selectedLanguageInfo.selectedLanguage) {
|
|
88
|
+
this.itemInfo.footer = this.updatebuttonLanguage(this.footerSchemaCopy, this.selectedLanguageInfo.selectedLanguage)
|
|
89
|
+
this.itemInfo.header = this.updatebuttonLanguage(this.headerSchemaCopy, this.selectedLanguageInfo.selectedLanguage)
|
|
90
|
+
this.itemInfo.layoutSchema = this.updateLayoutLanguage(this.layoutSchemaCopy, this.selectedLanguageInfo.selectedLanguage)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private safeUpdate(fn: () => void) {
|
|
95
|
+
if (NgZone.isInAngularZone()) {
|
|
96
|
+
fn();
|
|
97
|
+
this.cdr.markForCheck();
|
|
98
|
+
} else {
|
|
99
|
+
this.zone.run(() => {
|
|
100
|
+
fn();
|
|
101
|
+
this.cdr.markForCheck();
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
forceNumericKeyboard(event: any) {
|
|
107
|
+
const input = event?.target as HTMLInputElement;
|
|
108
|
+
if (input && input.tagName === 'INPUT') {
|
|
109
|
+
input.setAttribute('inputmode', 'numeric'); // Android
|
|
110
|
+
input.setAttribute('pattern', '[0-9:]*'); // iOS
|
|
111
|
+
input.setAttribute('type', 'tel'); // strongest signal
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
onDateTyping(event: any) {
|
|
116
|
+
const input = event.target as HTMLInputElement;
|
|
117
|
+
if (!input) return;
|
|
118
|
+
let digits = input.value.replace(/\D/g, '');
|
|
119
|
+
digits = digits.substring(0, 8);
|
|
120
|
+
let formatted = '';
|
|
121
|
+
if (digits.length <= 4) {
|
|
122
|
+
formatted = digits;
|
|
123
|
+
} else if (digits.length <= 6) {
|
|
124
|
+
formatted = `${digits.slice(0, 4)}-${digits.slice(4)}`;
|
|
125
|
+
} else {
|
|
126
|
+
formatted = `${digits.slice(0, 4)}-${digits.slice(4, 6)}-${digits.slice(6)}`;
|
|
127
|
+
}
|
|
128
|
+
input.value = formatted;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
updatebuttonLanguage<T>(
|
|
132
|
+
schema: T,
|
|
133
|
+
translations: Record<string, string>
|
|
134
|
+
): T {
|
|
135
|
+
const cloned = JSON.parse(JSON.stringify(schema));
|
|
136
|
+
|
|
137
|
+
const walk = (obj: any) => {
|
|
138
|
+
if (!obj || typeof obj !== 'object') return;
|
|
139
|
+
|
|
140
|
+
// ✅ Replace direct caption (e.g. button.caption)
|
|
141
|
+
if (typeof obj.caption === 'string') {
|
|
142
|
+
const original = obj.caption;
|
|
143
|
+
obj.caption = translations[original] ?? original;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ✅ Replace modalTitle if present
|
|
147
|
+
if (typeof obj.modalTitle === 'string') {
|
|
148
|
+
const original = obj.modalTitle;
|
|
149
|
+
obj.modalTitle = translations[original] ?? original;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 🔁 Recurse
|
|
153
|
+
Object.keys(obj).forEach((key) => {
|
|
154
|
+
const value = obj[key];
|
|
155
|
+
if (typeof value === 'object') {
|
|
156
|
+
walk(value);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
walk(cloned);
|
|
162
|
+
return cloned;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
updateLayoutLanguage<T>(
|
|
167
|
+
schema: T,
|
|
168
|
+
translations: Record<string, string>
|
|
169
|
+
): T {
|
|
170
|
+
// Deep clone to avoid mutating original schema
|
|
171
|
+
const cloned = JSON.parse(JSON.stringify(schema));
|
|
172
|
+
|
|
173
|
+
const walk = (obj: any) => {
|
|
174
|
+
if (!obj || typeof obj !== 'object') return;
|
|
175
|
+
|
|
176
|
+
// ✅ If label.caption exists → translate it
|
|
177
|
+
if (obj.label && typeof obj.label.caption === 'string') {
|
|
178
|
+
const originalCaption = obj.label.caption;
|
|
179
|
+
obj.label.caption =
|
|
180
|
+
translations[originalCaption] ?? originalCaption;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 🔁 Recurse into object properties
|
|
184
|
+
Object.keys(obj).forEach((key) => {
|
|
185
|
+
const value = obj[key];
|
|
186
|
+
if (typeof value === 'object') {
|
|
187
|
+
walk(value);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
walk(cloned);
|
|
193
|
+
return cloned;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
dateChangeEvent(filter: any, value: any) {
|
|
197
|
+
const scope = this.getScope(filter.scope.reference);
|
|
198
|
+
const field = filter.scope?.reference.split('/').pop();
|
|
199
|
+
this.itemInfo.propertySchema[scope][field].value = value
|
|
200
|
+
this.applyDateFilter(this.extractFilterValues(this.itemInfo.propertySchema[scope]))
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async applyDateFilter(filters: any) {
|
|
204
|
+
const from = filters.fromDateFilter ? new Date(filters.fromDateFilter) : null;
|
|
205
|
+
const to = filters.toDateFilter ? new Date(filters.toDateFilter) : null;
|
|
206
|
+
if (to && from) {
|
|
207
|
+
const formattedFrom = this.formatToOffsetISO(from);
|
|
208
|
+
const formattedTo = this.formatToOffsetISO(to);
|
|
209
|
+
const keycloakInfo: any = await this.utilityService.getLocalStorage('KeycloakInfo');
|
|
210
|
+
const logined: any = await this.utilityService.getLocalStorage('loginedUser');
|
|
211
|
+
this.safeUpdate(() => this.isLoading = true);
|
|
212
|
+
if (this.platform.ANDROID || this.platform.IOS) {
|
|
213
|
+
let saveOrder = await this.getSaveOrder(keycloakInfo?.token, keycloakInfo, formattedFrom, formattedTo)
|
|
214
|
+
this.itemInfo.data = saveOrder?.length > 0 ? saveOrder : []
|
|
215
|
+
this.safeUpdate(() => this.isLoading = false);
|
|
216
|
+
} else {
|
|
217
|
+
this.requestService.getSaveOrder(logined?.token, logined, formattedFrom, formattedTo).subscribe((saveOrders: any) => {
|
|
218
|
+
const updatedData = this.utilityService.restoreDatesFromStorage(saveOrders, this.itemInfo.propertySchema);
|
|
219
|
+
this.itemInfo.data = updatedData?.length > 0 ? updatedData : []
|
|
220
|
+
this.safeUpdate(() => this.isLoading = false);
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async getSaveOrder(
|
|
227
|
+
token: string,
|
|
228
|
+
userInfo: any,
|
|
229
|
+
fromDate: any,
|
|
230
|
+
toDate: any
|
|
231
|
+
) {
|
|
232
|
+
if (!token) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const company = userInfo.p5_plant
|
|
237
|
+
? `${userInfo.p5_group}/${userInfo.p5_client}/${userInfo.p5_plant}`
|
|
238
|
+
: `${userInfo.p5_group}/${userInfo.p5_client}/`;
|
|
239
|
+
|
|
240
|
+
const url = `${userInfo.p5_backend_url}/assetsmobileservice/Zeiterfassung/requestBookedTimeRecording`;
|
|
241
|
+
|
|
242
|
+
try {
|
|
243
|
+
const response = await CapacitorHttp.post({
|
|
244
|
+
url,
|
|
245
|
+
params: {
|
|
246
|
+
resourceNo: userInfo.p5_resource_no,
|
|
247
|
+
workDayFrom: fromDate,
|
|
248
|
+
workDayTo: toDate,
|
|
249
|
+
company,
|
|
250
|
+
appVersion: '1',
|
|
251
|
+
},
|
|
252
|
+
headers: {
|
|
253
|
+
Authorization: `Bearer ${token}`, // ✅ REQUIRED
|
|
254
|
+
Accept: 'application/json',
|
|
255
|
+
},
|
|
256
|
+
// ❗ NO BODY needed for this endpoint
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
console.log('getSaveOrder response:', response.data);
|
|
260
|
+
return response.data;
|
|
261
|
+
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error('Failed to fetch saved orders', error);
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
formatToOffsetISO(date: Date): string {
|
|
269
|
+
if (!date) return "";
|
|
270
|
+
|
|
271
|
+
const pad = (n: number, len = 2) => String(n).padStart(len, "0");
|
|
272
|
+
const year = date.getFullYear();
|
|
273
|
+
const month = pad(date.getMonth() + 1);
|
|
274
|
+
const day = pad(date.getDate());
|
|
275
|
+
const hours = pad(date.getHours());
|
|
276
|
+
const minutes = pad(date.getMinutes());
|
|
277
|
+
const seconds = pad(date.getSeconds());
|
|
278
|
+
const ms = pad(date.getMilliseconds(), 4); // 4-digit milliseconds
|
|
279
|
+
|
|
280
|
+
// timezone offset
|
|
281
|
+
const offset = -date.getTimezoneOffset(); // in minutes
|
|
282
|
+
const offSign = offset >= 0 ? "+" : "-";
|
|
283
|
+
const offHours = pad(Math.floor(Math.abs(offset) / 60));
|
|
284
|
+
const offMinutes = pad(Math.abs(offset) % 60);
|
|
285
|
+
|
|
286
|
+
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}:${ms}${offSign}${offHours}:${offMinutes}`;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
extractFilterValues(schema: Record<string, any>): Record<string, any> {
|
|
290
|
+
return Object.keys(schema).reduce((acc, key) => {
|
|
291
|
+
if (key.includes('Filter') && schema[key]?.value !== undefined) {
|
|
292
|
+
acc[key] = schema[key].value;
|
|
293
|
+
}
|
|
294
|
+
return acc;
|
|
295
|
+
}, {} as Record<string, any>);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
invokeOnPageSizeChange(pageSize: any) {
|
|
299
|
+
this.onPageSizeChange.emit(pageSize);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
invokeGoToPage(page: any) {
|
|
303
|
+
this.onPageChange.emit(page);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
invokeOnCardHeader(element: any) {
|
|
307
|
+
this.cardHeaderButtonClick.emit(element);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
invokeOnCardFooter(element: any) {
|
|
311
|
+
// this.cardHeaderButtonClick.emit(element);
|
|
312
|
+
this.d4_SaveAll();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async invokeButtonClick(layout: any, record: any, recordIndex: any) {
|
|
316
|
+
if (layout?.option?.action === "delete" && layout?.option?.storageType == "localstorage") {
|
|
317
|
+
if (layout?.option?.deleteMessage) {
|
|
318
|
+
this.showConfirm(layout?.option, recordIndex);
|
|
319
|
+
}
|
|
320
|
+
} else if (layout?.option?.action === "save" && layout?.option?.storageType === "database") {
|
|
321
|
+
const final_array = this.utilityService.convertToDailyLogs(record);
|
|
322
|
+
await this.saveToDb(final_array, recordIndex, layout.option.data_url)
|
|
323
|
+
} else {
|
|
324
|
+
this.cardButtonClick.emit({ layout: layout, record: record, recordIndex: recordIndex });
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
showConfirm(option: any, recordIndex: any) {
|
|
329
|
+
this.modalService.confirm({
|
|
330
|
+
nzTitle: this.selectedLanguageInfo && this.selectedLanguageInfo?.selectedLanguage['Confirm'] ? this.selectedLanguageInfo.selectedLanguage['Confirm'] : 'Confirm',
|
|
331
|
+
nzContent: this.selectedLanguageInfo && this.selectedLanguageInfo?.selectedLanguage[option.deleteMessage] ? this.selectedLanguageInfo.selectedLanguage[option.deleteMessage] : option.deleteMessage,
|
|
332
|
+
nzOkText: this.selectedLanguageInfo && this.selectedLanguageInfo?.selectedLanguage['Delete'] ? this.selectedLanguageInfo.selectedLanguage['Delete'] : 'Delete',
|
|
333
|
+
nzCancelText: this.selectedLanguageInfo && this.selectedLanguageInfo?.selectedLanguage['Cancel'] ? this.selectedLanguageInfo.selectedLanguage['Cancel'] : 'Cancel',
|
|
334
|
+
nzOnOk: () => this.deleteRecord(recordIndex, option.data_url)
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async d4_SaveAll() {
|
|
339
|
+
let allOrders: any[] = [];
|
|
340
|
+
for (let i = 0; i < this.itemInfo.data.length; i++) {
|
|
341
|
+
const element = this.itemInfo.data[i];
|
|
342
|
+
const dailyLogs = this.utilityService.convertToDailyLogs(element);
|
|
343
|
+
if (Array.isArray(dailyLogs)) {
|
|
344
|
+
allOrders.push(...dailyLogs);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
await this.saveToDb(allOrders, null, true);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
deleteRecord(recordIndex: any, data_url: any) {
|
|
352
|
+
this.itemInfo.data.splice(recordIndex, 1);
|
|
353
|
+
this.utilityService.setLocalStorage('timeRecords', JSON.stringify(this.itemInfo.data));
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
deleteAllRecord() {
|
|
357
|
+
this.itemInfo.data = []
|
|
358
|
+
this.utilityService.setLocalStorage('timeRecords', JSON.stringify(this.itemInfo.data));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async saveToDb(orders: any, orderIndex?: any, data_url?: any, deleteAll: boolean = false) {
|
|
362
|
+
this.safeUpdate(() => this.isLoading = true);
|
|
363
|
+
const token = this.oauthService.getAccessToken(); // whatever you have
|
|
364
|
+
const logined: any = await this.utilityService.getLocalStorage('loginedUser');
|
|
365
|
+
const keycloakInfo: any = await this.utilityService.getLocalStorage('KeycloakInfo');
|
|
366
|
+
let saveobject = {
|
|
367
|
+
ressourceNo: logined?.p5_resource_no ? logined.p5_resource_no : keycloakInfo?.p5_resource_no,
|
|
368
|
+
returnTimeRecordingLine: orders
|
|
369
|
+
}
|
|
370
|
+
if (this.platform.ANDROID || this.platform.IOS) {
|
|
371
|
+
const res = await this.mobileSaveDb(keycloakInfo.token, keycloakInfo, saveobject, orderIndex, data_url, deleteAll);
|
|
372
|
+
} else {
|
|
373
|
+
this.webSaveDb(token, logined, saveobject, orderIndex, data_url, deleteAll);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
webSaveDb(token: any, userInfo: any, order: any = {}, orderIndex?: any, dataUrl?: any, deleteAll: boolean = false) {
|
|
378
|
+
if (token) {
|
|
379
|
+
const headers = new HttpHeaders({
|
|
380
|
+
'Authorization': `Bearer ${token}`,
|
|
381
|
+
'Accept': 'application/json'
|
|
382
|
+
});
|
|
383
|
+
let url2: any = `${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}`
|
|
384
|
+
this.http.post(url2, order, { headers }).subscribe({
|
|
385
|
+
next: res => {
|
|
386
|
+
this.safeUpdate(() => this.isLoading = false);
|
|
387
|
+
if (orderIndex && orderIndex > -1) {
|
|
388
|
+
this.deleteRecord(orderIndex, dataUrl)
|
|
389
|
+
} else {
|
|
390
|
+
this.deleteAllRecord();
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
})
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
async mobileSaveDb(token: string, userInfo: any, order: any = {}, orderIndex: number, dataUrl: any, deleteAll: boolean = false) {
|
|
398
|
+
if (!token) {
|
|
399
|
+
console.log("NO-token", token);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const company = userInfo.p5_plant
|
|
404
|
+
? `${userInfo.p5_group}/${userInfo.p5_client}/${userInfo.p5_plant}`
|
|
405
|
+
: `${userInfo.p5_group}/${userInfo.p5_client}/`;
|
|
406
|
+
|
|
407
|
+
const url = `${userInfo.p5_backend_url}/assetsmobileservice/Zeiterfassung/registerTimeRecording`;
|
|
408
|
+
|
|
409
|
+
try {
|
|
410
|
+
const response = await CapacitorHttp.post({
|
|
411
|
+
url,
|
|
412
|
+
params: {
|
|
413
|
+
company,
|
|
414
|
+
appVersion: '1',
|
|
415
|
+
resourceNo: userInfo.p5_resource_no,
|
|
416
|
+
},
|
|
417
|
+
headers: {
|
|
418
|
+
Authorization: `Bearer ${token}`,
|
|
419
|
+
Accept: 'application/json',
|
|
420
|
+
'Content-Type': 'application/json',
|
|
421
|
+
},
|
|
422
|
+
data: order,
|
|
423
|
+
});
|
|
424
|
+
if (orderIndex != null && orderIndex > -1) {
|
|
425
|
+
this.deleteRecord(orderIndex, dataUrl);
|
|
426
|
+
} else {
|
|
427
|
+
this.deleteAllRecord();
|
|
428
|
+
}
|
|
429
|
+
this.safeUpdate(() => this.isLoading = false);
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
return response.data;
|
|
433
|
+
|
|
434
|
+
} catch (error) {
|
|
435
|
+
this.safeUpdate(() => this.isLoading = false);
|
|
436
|
+
console.error('Failed to save time recording', error);
|
|
437
|
+
throw error;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
showLinkDetails(option: any, record: any) {
|
|
442
|
+
this.linkDetails.emit({ option: option, record: record })
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
showImageDetails(option: any, record: any) {
|
|
446
|
+
this.imageDetails.emit({ option: option, record: record })
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
getProperty(scope: any) {
|
|
450
|
+
const property = scope ? scope.split('/').pop() : '';
|
|
451
|
+
return { key: property, productSchema: this.itemInfo.propertySchema[this.getScope(scope)][property] };
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
getStyleWithoutClasses(styleObject: any) {
|
|
455
|
+
if (!styleObject) {
|
|
456
|
+
return { classes: '', style: {} };
|
|
457
|
+
}
|
|
458
|
+
const { classes, ...styleWithoutClasses } = styleObject;
|
|
459
|
+
return { classes: classes && classes.length > 0 ? classes[0] : '', style: styleWithoutClasses };
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
getScope(scope: any) {
|
|
463
|
+
let propertyScope = "";
|
|
464
|
+
let start = scope?.indexOf("#/") + 2;
|
|
465
|
+
let end = scope?.indexOf("/", start);
|
|
466
|
+
if (start && end) {
|
|
467
|
+
propertyScope = scope.substring(start, end);
|
|
468
|
+
}
|
|
469
|
+
return propertyScope;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<p>form works!</p>
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<p>grid works!</p>
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<p>pagination works!</p>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'vt-pagination',
|
|
5
|
+
imports: [],
|
|
6
|
+
standalone: true,
|
|
7
|
+
templateUrl: './pagination.component.html',
|
|
8
|
+
styleUrl: './pagination.component.css',
|
|
9
|
+
})
|
|
10
|
+
export class PaginationComponent {
|
|
11
|
+
|
|
12
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { Preferences } from '@capacitor/preferences';
|
|
3
|
+
import { APP_VERSION } from '../app-version';
|
|
4
|
+
import { Platform } from '@angular/cdk/platform';
|
|
5
|
+
|
|
6
|
+
const VERSION_KEY = 'APP_VERSION';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@Injectable({
|
|
10
|
+
providedIn: 'root'
|
|
11
|
+
})
|
|
12
|
+
export class AppVersionResetService {
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
private platform: Platform) {
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async run(): Promise<void> {
|
|
20
|
+
if (this.platform.ANDROID || this.platform.IOS) {
|
|
21
|
+
await this.clearNativeIfChanged();
|
|
22
|
+
// this.clearWebIfChanged();
|
|
23
|
+
// return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private async clearNativeIfChanged(): Promise<void> {
|
|
28
|
+
const { value: savedVersion } = await Preferences.get({ key: VERSION_KEY });
|
|
29
|
+
if (savedVersion === APP_VERSION) return;
|
|
30
|
+
console.log(`🧹 Clearing Capacitor Preferences (new build ${APP_VERSION})`);
|
|
31
|
+
await Preferences.clear();
|
|
32
|
+
this.clearWebStores();
|
|
33
|
+
await Preferences.set({ key: VERSION_KEY, value: APP_VERSION });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// private clearWebIfChanged(): void {
|
|
37
|
+
// const savedVersion = sessionStorage.getItem(VERSION_KEY) || localStorage.getItem(VERSION_KEY);
|
|
38
|
+
// if (savedVersion === APP_VERSION) return;
|
|
39
|
+
// this.clearWebStores();
|
|
40
|
+
// localStorage.setItem(VERSION_KEY, APP_VERSION);
|
|
41
|
+
// sessionStorage.setItem(VERSION_KEY, APP_VERSION);
|
|
42
|
+
// }
|
|
43
|
+
|
|
44
|
+
private clearWebStores(): void {
|
|
45
|
+
try { localStorage.clear(); } catch { }
|
|
46
|
+
try { sessionStorage.clear(); } catch { }
|
|
47
|
+
try {
|
|
48
|
+
if (typeof document !== 'undefined' && document.cookie) {
|
|
49
|
+
document.cookie.split(';').forEach((c) => {
|
|
50
|
+
const eqPos = c.indexOf('=');
|
|
51
|
+
const name = eqPos > -1 ? c.substring(0, eqPos).trim() : c.trim();
|
|
52
|
+
if (name) {
|
|
53
|
+
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
} catch { }
|
|
58
|
+
}
|
|
59
|
+
}
|