@yomotech/view-toolkit 0.0.3 → 0.0.5

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 +3539 -0
  2. package/fesm2022/yomotech-view-toolkit.mjs.map +1 -0
  3. package/package.json +51 -36
  4. package/types/yomotech-view-toolkit.d.ts +653 -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
@@ -1,125 +0,0 @@
1
- import { HttpClient, HttpHeaders } from '@angular/common/http';
2
- import { Injectable } from '@angular/core';
3
-
4
- @Injectable({
5
- providedIn: 'root'
6
- })
7
- export class RequestService {
8
- pageSize: number = 0;
9
- constructor(private http: HttpClient) { }
10
-
11
- getAllProject() {
12
- return this.http.get("../assets/main/layout_schema.json");
13
- }
14
-
15
- getEnvironmet(selectedProject: any) {
16
- return this.http.get(`../../assets/projects/${selectedProject}/environments/environment.json`);
17
- }
18
-
19
- getSectionInfo(url: string, envUrl?: any, passToken: boolean = false, selectedProject: string = '', userInfo: any = null) {
20
- if (envUrl) {
21
- if (passToken && selectedProject) {
22
- return this.http.get(envUrl + url, {
23
- headers: this.createAuthorizationHeader(userInfo),
24
- })
25
- } else {
26
- return this.http.get(envUrl + url);
27
- }
28
- } else {
29
- return this.http.get(url);
30
- };
31
- }
32
-
33
- getMainLayout(selectedProject: any) {
34
- return this.http.get(`../assets/projects/${selectedProject}/main/layout_schema.json`)
35
- }
36
-
37
- getInfo(url: string) {
38
- return this.http.get(url);
39
- }
40
-
41
- dynamicCall(method: string = "get", body: any = null, url: string, passToken: boolean = false, selectedProject: string = '', userInfo: any = null) {
42
- switch (method.toLowerCase()) {
43
- case 'get':
44
- if (passToken && selectedProject) {
45
- return this.http.get(url, {
46
- headers: this.createAuthorizationHeader(userInfo),
47
- })
48
- } else {
49
- return this.http.get(url);
50
- }
51
-
52
- case 'post':
53
- if (passToken && selectedProject) {
54
- return this.http.post(url, body, {
55
- headers: this.createAuthorizationHeader(userInfo),
56
- })
57
- } else {
58
- return this.http.post(url, body);
59
- }
60
- case 'put':
61
- if (passToken && selectedProject) {
62
- return this.http.put(url, body, {
63
- headers: this.createAuthorizationHeader(userInfo),
64
- })
65
- } else {
66
- return this.http.put(url, body);
67
- }
68
- case 'delete':
69
- if (passToken && selectedProject) {
70
- return this.http.delete(url, {
71
- headers: this.createAuthorizationHeader(userInfo),
72
- })
73
- } else {
74
- return this.http.delete(url);
75
- };
76
- case 'patch':
77
- return this.http.patch(url, body);
78
- default:
79
- throw new Error(`Unsupported HTTP method: ${method}`);
80
- }
81
- }
82
-
83
- createAuthorizationHeader(userInfo: any, tokenExist: boolean = false) {
84
- let authHeaders: HttpHeaders = new HttpHeaders();
85
- let token = tokenExist ? userInfo : userInfo && userInfo.jwt ? userInfo.jwt : userInfo?.authToken ? userInfo?.authToken : '';
86
- return authHeaders.set(
87
- 'Authorization',
88
- 'Bearer ' + token
89
- )
90
- }
91
-
92
- getLoginUser(token: any) {
93
- return this.http.get("https://dev-78992019.okta.com/oauth2/default/v1/userinfo", {
94
- headers: this.createAuthorizationHeader(token, true),
95
- })
96
- }
97
-
98
- saveDb(token: any, userInfo: any, order: any = {}) {
99
- if (token) {
100
- const headers = new HttpHeaders({
101
- 'Authorization': `Bearer ${token}`,
102
- 'Accept': 'application/json'
103
- });
104
- 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}`
105
- console.log('userInfo: ', userInfo);
106
- this.http.post(url2, order, { headers }).subscribe({
107
- next: res => {
108
- console.log('Save-res: ', res);
109
- }
110
- })
111
- }
112
- }
113
-
114
- getSaveOrder(token: any, userInfo: any, fromDate: any, toDate: any) {
115
- // if (token) {
116
- const headers = new HttpHeaders({
117
- 'Authorization': `Bearer ${token}`,
118
- 'Accept': 'application/json'
119
- });
120
- 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`
121
- return this.http.post(url, {}, { headers })
122
- // }
123
- }
124
- }
125
-
@@ -1,593 +0,0 @@
1
- import { Platform } from '@angular/cdk/platform';
2
- import { Injectable } from '@angular/core';
3
- import { Preferences } from '@capacitor/preferences';
4
- import { RequestService } from './request.service';
5
- import { loadStripe } from '@stripe/stripe-js';
6
- import { lastValueFrom } from 'rxjs';
7
- // import { Couchdb } from './couchdb';
8
-
9
- @Injectable({
10
- providedIn: 'root'
11
- })
12
- export class UtilityService {
13
- stripe: any = null;
14
-
15
- constructor(private platform: Platform,
16
- // private couchdbService: Couchdb,
17
- private requestService: RequestService) { }
18
-
19
- getScope(scope: any) {
20
- let propertyScope = "";
21
- let start = scope?.indexOf("#/") + 2;
22
- let end = scope?.indexOf("/", start);
23
- if (start && end) {
24
- propertyScope = scope.substring(start, end);
25
- }
26
- return propertyScope;
27
- }
28
-
29
- getProperty(scope: any, itemInfo?: any) {
30
- const property = scope?.reference ? scope?.reference.split('/').pop() : '';
31
- return { key: property, productSchema: itemInfo.propertySchema[property] };
32
- }
33
-
34
- async setStorage(key: string, value: any) {
35
- if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
36
- await Preferences.set({ key, value });
37
- } else {
38
- sessionStorage.setItem(key, value);
39
- }
40
- }
41
-
42
- async getStorage(key: string) {
43
- if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
44
- const { value } = await Preferences.get({ key });
45
- return value;
46
- } else {
47
- const storage = sessionStorage.getItem(key);
48
- return storage;
49
- }
50
- }
51
-
52
- async setLocalStorage(key: string, value: any) {
53
- const stringValue = JSON.stringify(value);
54
- if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
55
- await Preferences.set({ key, value: stringValue });
56
- } else {
57
- localStorage.setItem(key, stringValue);
58
- }
59
- }
60
-
61
- async removeLocalStorage(keyName: string) {
62
- if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
63
- await Preferences.remove({ key: keyName });
64
- } else {
65
- localStorage.removeItem(keyName);
66
- }
67
- }
68
-
69
- async removeStorage(key: string) {
70
- if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
71
- await Preferences.remove({ key });
72
- } else {
73
- sessionStorage.removeItem(key);
74
- }
75
- }
76
-
77
- async getLocalStorage(key: string) {
78
- if ((this.platform.ANDROID || this.platform.IOS) && !this.platform?.isBrowser) {
79
- const { value } = await Preferences.get({ key });
80
- return value ? JSON.parse(value) : null;
81
- } else {
82
- const value = localStorage.getItem(key);
83
- return value ? JSON.parse(value) : null;
84
- }
85
- }
86
-
87
- async showAllProjects() {
88
- await this.removeStorage('selectedProject');
89
- window.location.reload();
90
- }
91
-
92
- parseBodyObject(obj: any): any {
93
- const jsonString = JSON.stringify(obj);
94
- const replacedString = jsonString.replace(/{{(.*?)}}/g, (match, expression) => {
95
- try {
96
- return new Function(`return ${expression.trim()};`).call(this);
97
- } catch (error) {
98
- console.error(`Error evaluating expression: ${expression}`, error);
99
- return match;
100
- }
101
- });
102
- return JSON.parse(replacedString);
103
- }
104
-
105
- getTotalPrice(tableitemInfo: any): number {
106
- const total = tableitemInfo.data.reduce((total: any, item: any) => {
107
- if (item.quantity && !isNaN(item.quantity)) {
108
- return total + (item.unitPrice * item.quantity);
109
- }
110
- return total;
111
- }, 0);
112
- return total.toFixed(2);
113
- }
114
-
115
- getTotalQuantity(tableitemInfo: any) {
116
- let quantity = 0;
117
- tableitemInfo.data.forEach((cartItem: any) => {
118
- if (cartItem.quantity) {
119
- quantity = cartItem.quantity + quantity;
120
- }
121
- });
122
- return quantity;
123
- }
124
-
125
- replacePaginationParams(url: string, currentPage: number, pageSize: number): string {
126
- if (url.includes('{{pageNumber}}')) {
127
- url = url.replace(/{{pageNumber}}/g, currentPage.toString());
128
- }
129
-
130
- if (url.includes('{{pageSize}}') && pageSize !== undefined) {
131
- url = url.replace(/{{pageSize}}/g, pageSize.toString());
132
- }
133
- return url;
134
- }
135
-
136
- customButton(option: any, propertySchema: any, projectSeleted: any, environment: any) {
137
- if (option.url) {
138
- let body = {}
139
- if (option.propertyKey) {
140
- body = Object.keys(propertySchema[option.propertyKey]).reduce((acc, key) => {
141
- acc[key] = propertySchema[option.propertyKey][key]?.value;
142
- return acc;
143
- }, {} as Record<string, string>);
144
- }
145
- let url = environment?.apiUrl + option.url;
146
- this.requestService.dynamicCall(option.method, body, url, option.passToken, projectSeleted).subscribe((res) => {
147
- window.location.reload();
148
- })
149
- }
150
- }
151
-
152
- setDefaultUser(item: any, userInfo: any, environment: any) {
153
- let schema: any = item;
154
- let role = "default";
155
- if (environment?.login?.type === "keycloak") {
156
- if (userInfo?.name && item.options?.userRoleMapping) {
157
- schema = item.options[item.options?.userRoleMapping[role]];
158
- }
159
- } else if (environment?.login?.type === "jwtToken") {
160
- if (item.options?.loginResponse && item.options?.loginResponse.storageType == "sessionStorage") {
161
- if (userInfo) {
162
- role = userInfo[item.options?.loginResponse.role]?.toLowerCase();
163
- }
164
- schema = item.options[item.options?.userRoleMapping[role]];
165
- }
166
- }
167
- return schema;
168
- }
169
-
170
- setTableData(data: any, options: any = {}, tableitemInfo: any, projectSeleted: any) {
171
- if (options?.pagination?.pageSize && options?.pagination?.scrollable) {
172
- tableitemInfo.pageSize = options?.pagination?.pageSize;
173
- }
174
- let records: any;
175
- if (options.dataKey) {
176
- records = data[options.dataKey];
177
- } else if (options.key && data?._embedded) {
178
- records = data?._embedded[options.key];
179
- } else {
180
- if (!data?._embedded?.products && !Array.isArray(data)) {
181
- records = [data];
182
- } else {
183
- records = data?._embedded?.products;
184
- }
185
- }
186
- tableitemInfo.totalRecords = data?.totalPages ? data?.totalPages : data?.page?.totalElements;
187
- tableitemInfo.data = records.map((record: any) => ({
188
- ...record,
189
- ...(record.hasOwnProperty('imageUrl') && record.imageUrl
190
- ? { imageUrl: `${projectSeleted}/pages/images/` + record.imageUrl.split('/').pop() }
191
- : {})
192
- }));
193
- return tableitemInfo;
194
- }
195
-
196
- setOktaWebCredential(environment: any, projectName: any) {
197
- return {
198
- logo: `favicon.ico`,
199
- baseUrl: environment.login.web.issuer.split('/oauth2')[0],
200
- clientId: environment.login.web.clientId,
201
- redirectUri: environment.login.web.redirectUri,
202
- authParams: {
203
- pkce: true,
204
- issuer: environment.login.web.issuer,
205
- scopes: environment.login.web.scopes
206
- }
207
- }
208
- }
209
-
210
- setOktaMobileCredential(environment: any) {
211
- return {
212
- appId: environment.login.mobile.clientId,
213
- authorizationBaseUrl: environment.login.mobile.authorizationBaseUrl,
214
- accessTokenEndpoint: environment.login.mobile.accessTokenEndpoint,
215
- redirectUrl: environment.login.mobile.redirectUrl,
216
- scope: environment.login.mobile.scope,
217
- responseType: environment.login.mobile.responseType,
218
- pkceEnabled: environment.login.mobile.pkceEnabled
219
- }
220
- }
221
-
222
-
223
- async setupStripePaymentForm(
224
- environment: any,
225
- form: any,
226
- onCardChange: (message: string) => void
227
- ): Promise<void> {
228
- let hasCreditCard = false;
229
-
230
- if (form.layoutSchema?.formSections) {
231
- form.layoutSchema.formSections.forEach((formSection: any) => {
232
- if (formSection.formFields?.length > 0) {
233
- const foundCreditCard = formSection.formFields.some((formField: any) => {
234
- const scopeKey = this.getScope(formField.scope?.reference);
235
- return form.propertySchema[scopeKey] &&
236
- form.propertySchema[scopeKey][formField.scope?.reference.split('/').pop()]?.type === 'carditCard';
237
- });
238
- if (foundCreditCard) {
239
- hasCreditCard = true;
240
- return;
241
- }
242
- }
243
- });
244
- }
245
-
246
- if (hasCreditCard) {
247
- this.stripe = await loadStripe(environment.stripePublishableKey);
248
- const elements = this.stripe.elements();
249
- const cardElement = elements.create('card', { hidePostalCode: true });
250
- cardElement.mount('#card-element');
251
-
252
- cardElement.on('change', (event: { complete: boolean, error?: { message: string } }) => {
253
- if (event.complete) {
254
- onCardChange('');
255
- } else if (event.error) {
256
- onCardChange(event.error.message);
257
- }
258
- });
259
- }
260
- }
261
-
262
- async formData(form: any, environment: any, cartInfo: any): Promise<void> {
263
- if (form.layoutSchema?.formSections) {
264
- for (const formSection of form.layoutSchema.formSections) {
265
- if (formSection.formFields?.length > 0) {
266
- for (const formField of formSection.formFields) {
267
- const scope = this.getScope(formField.scope?.reference);
268
- const fieldKey = formField.scope?.reference.split('/').pop();
269
- const field = form.propertySchema?.[scope]?.[fieldKey];
270
-
271
- if (!field) continue;
272
-
273
- // Checkbox logic with copy action
274
- if (field.type === 'checkbox' && formField.option?.innerAction?.action === 'copy') {
275
- const fromSchema = form.propertySchema[formField.option.innerAction.from];
276
- const toSchema = form.propertySchema[formField.option.innerAction.to];
277
- const keys = Object.keys(fromSchema);
278
-
279
- keys.forEach((key: any) => {
280
- if (toSchema[key]) {
281
- const sourceValue = fromSchema?.[key]?.value;
282
- toSchema[key].value = sourceValue || '';
283
- }
284
- });
285
- }
286
-
287
- // Dropdown logic (async data fetching)
288
- if (field.type === 'dropdown' && formField.option?.data_url) {
289
- try {
290
- const res: any = await lastValueFrom(this.requestService.getInfo(environment.apiUrl + formField.option.data_url));
291
- const key = Object.keys(res._embedded || {})[0];
292
- if (key) {
293
- field.data = res._embedded[key];
294
- }
295
- } catch (err) {
296
- console.error('Failed to load dropdown data', err);
297
- }
298
- }
299
-
300
- // Cart info logic for string fields
301
- if (field.type === 'string' && formField?.option?.cartInfo) {
302
- if (field.value?.toString()?.includes('{{quantity}}')) {
303
- field.value = cartInfo.quantity;
304
- } else if (field.value?.toString()?.includes('{{totalPrice}}')) {
305
- field.value = cartInfo.totalPrice;
306
- }
307
- }
308
- }
309
- }
310
- }
311
- }
312
- }
313
-
314
- async processData(
315
- data: any,
316
- options: {
317
- dataKey?: string;
318
- setImageUrl?: boolean;
319
- showTable?: boolean;
320
- projectSelected: string;
321
- },
322
- tenantName: any
323
- ): Promise<any[]> {
324
- if (options.dataKey) {
325
- data = data[options.dataKey];
326
- } else {
327
- if (!data?._embedded?.products && !Array.isArray(data)) {
328
- data = [data];
329
- } else {
330
- data = data?._embedded?.products;
331
- }
332
- }
333
- const transformed = await Promise.all(
334
- data.map(async (record: any) => {
335
- let imageUrl = record.imageUrl;
336
- const imagePath = `pages/images/` +
337
- record?.imageUrl?.split('/').pop();
338
- if (
339
- tenantName &&
340
- record?.imageUrl &&
341
- options.setImageUrl
342
- ) {
343
- try {
344
- imageUrl = "";
345
- // imageUrl = await this.couchdbService.getFileContentFromCouchDb(
346
- // `${tenantName}_${options.projectSelected}`,
347
- // imagePath
348
- // );
349
- } catch (err) {
350
- console.warn(`Failed to fetch image from CouchDB for ${imagePath}`, err);
351
- imageUrl = '';
352
- }
353
- }
354
- return {
355
- ...record,
356
- ...(imageUrl ? { imageUrl } : {}),
357
- ...(imagePath ? { imagePath } : {}),
358
- };
359
- })
360
- );
361
-
362
- return transformed;
363
- }
364
-
365
- async setTableDataImages(records: any, tenantName: any, projectSelected: any): Promise<any[]> {
366
- const transformed = await Promise.all(
367
- records.map(async (record: any) => {
368
- let imageUrl = record.imageUrl;
369
- const imagePath = record?.imagePath ? record?.imagePath : `pages/images/` +
370
- record?.imageUrl?.split('/').pop();
371
- if (
372
- tenantName &&
373
- record?.imageUrl &&
374
- record.hasOwnProperty('imageUrl')
375
- ) {
376
- try {
377
- imageUrl = "";
378
- // imageUrl = await this.couchdbService.getFileContentFromCouchDb(
379
- // `${tenantName}_${projectSelected}`,
380
- // imagePath
381
- // );
382
- } catch (err) {
383
- console.warn(`Failed to fetch image from CouchDB for ${imagePath}`, err);
384
- imageUrl = '';
385
- }
386
- }
387
- return {
388
- ...record,
389
- ...(imageUrl ? { imageUrl } : {}),
390
- };
391
- })
392
- );
393
- return transformed;
394
- }
395
-
396
- // set date in localstorage
397
- normalizeDatesForStorage(obj: any): any {
398
- const normalized: any = {};
399
- Object.entries(obj).forEach(([key, value]: any) => {
400
- if (this.isDateLike(value)) {
401
- const date = value instanceof Date ? value : new Date(value);
402
- normalized[key] = this.toLocalISOString(date);
403
- } else {
404
- normalized[key] = value;
405
- }
406
- });
407
- return normalized;
408
- }
409
-
410
-
411
- isDateLike(value: any): boolean {
412
- if (!value) return false;
413
-
414
- // Actual Date object
415
- if (value instanceof Date && !isNaN(value.getTime())) {
416
- return true;
417
- }
418
-
419
- // ISO string (UTC or local)
420
- if (typeof value === 'string') {
421
- return false;
422
- }
423
-
424
- return false;
425
- }
426
-
427
- toLocalISOString(date: Date): string {
428
- const tzOffset = date.getTimezoneOffset() * 60000;
429
- return new Date(date.getTime() - tzOffset)
430
- .toISOString()
431
- .slice(0, 19);
432
- }
433
-
434
- // restore date Field from localstorage
435
- restoreDatesFromStorage(records: any[], propertySchema: any): any[] {
436
- if (!Array.isArray(records)) return records;
437
- if (!propertySchema) return records;
438
-
439
- return records.map(record => {
440
- const restored = { ...record };
441
-
442
- Object.keys(propertySchema).forEach(scopeKey => {
443
- const schemaGroup = propertySchema[scopeKey];
444
- if (!schemaGroup) return;
445
-
446
- Object.keys(schemaGroup).forEach(fieldKey => {
447
- const fieldSchema = schemaGroup[fieldKey];
448
- const value = restored[fieldKey];
449
- if (!value || typeof value !== 'string') return;
450
-
451
- // ✅ DATE or TIME fields only
452
- if (fieldSchema.type === 'date' || fieldSchema.type === 'time') {
453
- restored[fieldKey] = this.parseLocalISODate(value);
454
- }
455
- });
456
- });
457
-
458
- return restored;
459
- });
460
- }
461
-
462
- parseLocalISODate(value: string): Date {
463
- // Remove Z to avoid UTC shift
464
- const clean = value.replace('Z', '');
465
- const [datePart, timePart = '00:00:00.000'] = clean.split('T');
466
-
467
- const [y, m, d] = datePart.split('-').map(Number);
468
- const [hh = 0, mm = 0, ss = 0, ms = 0] =
469
- timePart.split(/[:.]/).map(Number);
470
-
471
- return new Date(y, m - 1, d, hh, mm, ss, ms);
472
- }
473
-
474
- // savecard conversion
475
- convertToDailyLogs(cardOrCards: any | any[]): any[] {
476
- // Normalize input to array
477
- const cards = Array.isArray(cardOrCards) ? cardOrCards : [cardOrCards];
478
-
479
- const results: any[] = [];
480
-
481
- for (const card of cards) {
482
-
483
- const fromDate = new Date(card.fromDate);
484
- const toDate = new Date(card.toDate);
485
-
486
- const fromTime = new Date(card.workDayTimeFrom);
487
- const toTime = new Date(card.workDayTimeTo);
488
-
489
- // Normalize dates to midnight
490
- const startDay = new Date(fromDate);
491
- startDay.setHours(0, 0, 0, 0);
492
-
493
- const endDay = new Date(toDate);
494
- endDay.setHours(0, 0, 0, 0);
495
-
496
- let currentDay = new Date(startDay);
497
-
498
- while (currentDay <= endDay) {
499
- const isFirstDay = this.isSameDay(currentDay, fromDate);
500
- const isLastDay = this.isSameDay(currentDay, toDate);
501
- const isSameDay = isFirstDay && isLastDay;
502
-
503
- let workFrom: Date;
504
- let workTo: Date;
505
-
506
- // SAME DAY
507
- if (isSameDay) {
508
- workFrom = this.applyTimeToDay(currentDay, fromTime);
509
- workTo = this.applyTimeToDay(currentDay, toTime);
510
- }
511
- // FIRST DAY
512
- else if (isFirstDay) {
513
- workFrom = this.applyTimeToDay(currentDay, fromTime);
514
- workTo = this.endOfDay(currentDay);
515
- }
516
- // LAST DAY
517
- else if (isLastDay) {
518
- workFrom = this.startOfDay(currentDay);
519
- workTo = this.applyTimeToDay(currentDay, toTime);
520
- }
521
- // MIDDLE DAY
522
- else {
523
- workFrom = this.startOfDay(currentDay);
524
- workTo = this.endOfDay(currentDay);
525
- }
526
-
527
- results.push({
528
- comment: card.comments || "",
529
- onCallDuty: false,
530
- timeCredit: false,
531
- workDay: this.toLocalISO(currentDay, 0, 0),
532
- workDayTimeFrom: this.toLocalISO(workFrom),
533
- workDayTimeTo: this.toLocalISO(workTo),
534
- workOrderNo: card.workOrderNo,
535
- workType: "A"
536
- });
537
-
538
- currentDay.setDate(currentDay.getDate() + 1);
539
- }
540
- }
541
-
542
- return results;
543
- }
544
- private applyTimeToDay(day: Date, time: Date): Date {
545
- const d = new Date(day);
546
- d.setHours(time.getHours(), time.getMinutes(), 0, 0);
547
- return d;
548
- }
549
-
550
- private startOfDay(d: Date): Date {
551
- const x = new Date(d);
552
- x.setHours(0, 0, 0, 0);
553
- return x;
554
- }
555
-
556
- private endOfDay(d: Date): Date {
557
- const x = new Date(d);
558
- x.setHours(23, 59, 0, 0);
559
- return x;
560
- }
561
-
562
- private isSameDay(a: Date, b: Date): boolean {
563
- return (
564
- a.getFullYear() === b.getFullYear() &&
565
- a.getMonth() === b.getMonth() &&
566
- a.getDate() === b.getDate()
567
- );
568
- }
569
-
570
- private toLocalISO(date: Date, hour?: number, minute?: number): string {
571
- const d = new Date(date);
572
-
573
- if (hour !== undefined && minute !== undefined) {
574
- d.setHours(hour, minute, 0, 0);
575
- }
576
-
577
- const pad = (n: number) => String(n).padStart(2, '0');
578
-
579
- const year = d.getFullYear();
580
- const month = pad(d.getMonth() + 1);
581
- const day = pad(d.getDate());
582
- const hrs = pad(d.getHours());
583
- const mins = pad(d.getMinutes());
584
-
585
- const offset = -d.getTimezoneOffset();
586
- const sign = offset >= 0 ? '+' : '-';
587
- const offH = pad(Math.floor(Math.abs(offset) / 60));
588
- const offM = pad(Math.abs(offset) % 60);
589
-
590
- return `${year}-${month}-${day}T${hrs}:${mins}:00${sign}${offH}:${offM}`;
591
- }
592
-
593
- }