@mis-wis/common 0.1.9 → 0.2.1

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 (53) hide show
  1. package/esm2020/lib/components/create-non-shift-modal/create-non-shift-modal.component.mjs +237 -0
  2. package/esm2020/lib/constants/assets.constants.mjs +8 -0
  3. package/esm2020/lib/models/env.model.mjs +1 -1
  4. package/esm2020/lib/models/session.model.mjs +2 -0
  5. package/esm2020/lib/services/http.service.mjs +29 -9
  6. package/esm2020/lib/services/session.errors.mjs +45 -0
  7. package/esm2020/lib/services/session.service.mjs +198 -0
  8. package/esm2020/lib/wis-common.module.mjs +13 -8
  9. package/esm2020/public-api.mjs +5 -1
  10. package/fesm2015/mis-wis-common.mjs +530 -25
  11. package/fesm2015/mis-wis-common.mjs.map +1 -1
  12. package/fesm2020/mis-wis-common.mjs +522 -25
  13. package/fesm2020/mis-wis-common.mjs.map +1 -1
  14. package/lib/components/create-non-shift-modal/create-non-shift-modal.component.d.ts +56 -0
  15. package/lib/constants/assets.constants.d.ts +7 -0
  16. package/lib/models/env.model.d.ts +1 -0
  17. package/lib/models/session.model.d.ts +22 -0
  18. package/lib/services/http.service.d.ts +16 -5
  19. package/lib/services/session.errors.d.ts +31 -0
  20. package/lib/services/session.service.d.ts +79 -0
  21. package/lib/wis-common.module.d.ts +9 -4
  22. package/package.json +9 -3
  23. package/public-api.d.ts +4 -0
  24. package/src/assets/calendar.svg +7 -0
  25. package/src/assets/images/icons/Wis-icon.svg +4 -0
  26. package/src/assets/images/icons/brand.png +0 -0
  27. package/src/assets/images/icons/broascast.svg +3 -0
  28. package/src/assets/images/icons/bulk-upload.svg +3 -0
  29. package/src/assets/images/icons/desk-mgmt.svg +6 -0
  30. package/src/assets/images/icons/employees-sidebar.svg +3 -0
  31. package/src/assets/images/icons/help-section.svg +4 -0
  32. package/src/assets/images/icons/home.svg +3 -0
  33. package/src/assets/images/icons/logout.svg +4 -0
  34. package/src/assets/images/icons/manage-premise.svg +3 -0
  35. package/src/assets/images/icons/meeting-room.svg +7 -0
  36. package/src/assets/images/icons/mis-icon.svg +3 -0
  37. package/src/assets/images/icons/my-bookings.svg +5 -0
  38. package/src/assets/images/icons/profile.svg +3 -0
  39. package/src/assets/images/icons/reception.svg +14 -0
  40. package/src/assets/images/icons/report.svg +3 -0
  41. package/src/assets/images/icons/resource-group.svg +3 -0
  42. package/src/assets/images/icons/roles.svg +3 -0
  43. package/src/assets/images/icons/sanitize.svg +10 -0
  44. package/src/assets/images/icons/seat-mgmt.svg +3 -0
  45. package/src/assets/images/icons/settings-sidebar.svg +3 -0
  46. package/src/assets/images/icons/signout.svg +4 -0
  47. package/src/assets/images/icons/user-group.svg +6 -0
  48. package/src/assets/images/icons/user-permission.svg +5 -0
  49. package/src/assets/images/icons/utilisation.svg +3 -0
  50. package/src/assets/images/icons/vaccine_approval.svg +8 -0
  51. package/src/assets/images/icons/vaccine_upload.png +0 -0
  52. package/src/assets/images/icons/work-planner-sidebar.svg +3 -0
  53. package/src/assets/images/icons/workInSyncText.svg +14 -0
@@ -1,18 +1,29 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, NgModule, Component, Inject } from '@angular/core';
3
- import * as i1$1 from '@angular/common';
3
+ import * as i5 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
- import * as i1$3 from '@angular/common/http';
6
- import { HttpErrorResponse } from '@angular/common/http';
7
- import { tap } from 'rxjs/operators';
5
+ import * as i1$2 from '@angular/common/http';
6
+ import { HttpErrorResponse, HttpClientModule } from '@angular/common/http';
7
+ import { tap, finalize } from 'rxjs/operators';
8
8
  import * as i1 from '@angular/router';
9
9
  import * as i2 from 'mis-crystal-design-system/toast';
10
- import * as i1$2 from '@angular/cdk/overlay';
10
+ import * as i1$1 from '@angular/cdk/overlay';
11
11
  import { OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
12
12
  import { ComponentPortal } from '@angular/cdk/portal';
13
13
  import * as i2$1 from 'mis-crystal-design-system/loader';
14
14
  import { LoaderModule } from 'mis-crystal-design-system/loader';
15
- import { ReplaySubject } from 'rxjs';
15
+ import { map, forkJoin, ReplaySubject } from 'rxjs';
16
+ import * as i2$2 from '@angular/forms';
17
+ import { Validators, ReactiveFormsModule } from '@angular/forms';
18
+ import dayjs from 'dayjs';
19
+ import customParseFormat from 'dayjs/plugin/customParseFormat';
20
+ import * as i1$3 from 'mis-crystal-design-system/modal';
21
+ import { MODAL_DATA_VAR } from 'mis-crystal-design-system/modal';
22
+ import * as i6 from 'mis-crystal-design-system/dropdown';
23
+ import { DropdownModule } from 'mis-crystal-design-system/dropdown';
24
+ import * as i7 from 'mis-crystal-design-system/datepicker_v2';
25
+ import { DatepickerModuleV2 } from 'mis-crystal-design-system/datepicker_v2';
26
+ import jwtDecode from 'jwt-decode';
16
27
 
17
28
  class AuthService {
18
29
  constructor() { }
@@ -151,7 +162,7 @@ class LoaderComponent {
151
162
  ngOnInit() { }
152
163
  }
153
164
  LoaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
154
- LoaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: LoaderComponent, selector: "mis-common-loader", ngImport: i0, template: "<div class=\"message-wrapper\" *ngIf=\"message; else noMessageLoader\">\n <span><mis-loader type=\"block\"></mis-loader></span>\n <p>{{ message }}</p>\n</div>\n<ng-template #noMessageLoader>\n <mis-loader></mis-loader>\n</ng-template>\n", styles: [".message-wrapper{max-width:343px;background-color:#fff;display:flex;flex-wrap:nowrap;align-items:center;padding:20px 16px;border-radius:6px}.message-wrapper span{position:relative;background-color:#fff;display:inline-block;width:40px;height:40px;margin-right:16px}.message-wrapper p{margin:0}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.LoaderComponent, selector: "mis-loader", inputs: ["mobileView"] }] });
165
+ LoaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: LoaderComponent, selector: "mis-common-loader", ngImport: i0, template: "<div class=\"message-wrapper\" *ngIf=\"message; else noMessageLoader\">\n <span><mis-loader type=\"block\"></mis-loader></span>\n <p>{{ message }}</p>\n</div>\n<ng-template #noMessageLoader>\n <mis-loader></mis-loader>\n</ng-template>\n", styles: [".message-wrapper{max-width:343px;background-color:#fff;display:flex;flex-wrap:nowrap;align-items:center;padding:20px 16px;border-radius:6px}.message-wrapper span{position:relative;background-color:#fff;display:inline-block;width:40px;height:40px;margin-right:16px}.message-wrapper p{margin:0}\n"], dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.LoaderComponent, selector: "mis-loader", inputs: ["mobileView"] }] });
155
166
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoaderComponent, decorators: [{
156
167
  type: Component,
157
168
  args: [{ selector: "mis-common-loader", template: "<div class=\"message-wrapper\" *ngIf=\"message; else noMessageLoader\">\n <span><mis-loader type=\"block\"></mis-loader></span>\n <p>{{ message }}</p>\n</div>\n<ng-template #noMessageLoader>\n <mis-loader></mis-loader>\n</ng-template>\n", styles: [".message-wrapper{max-width:343px;background-color:#fff;display:flex;flex-wrap:nowrap;align-items:center;padding:20px 16px;border-radius:6px}.message-wrapper span{position:relative;background-color:#fff;display:inline-block;width:40px;height:40px;margin-right:16px}.message-wrapper p{margin:0}\n"] }]
@@ -203,14 +214,14 @@ class LoaderService {
203
214
  return { positionStrategy, width, backdropClass, hasMessage };
204
215
  }
205
216
  }
206
- LoaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoaderService, deps: [{ token: i1$2.Overlay }], target: i0.ɵɵFactoryTarget.Injectable });
217
+ LoaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoaderService, deps: [{ token: i1$1.Overlay }], target: i0.ɵɵFactoryTarget.Injectable });
207
218
  LoaderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoaderService, providedIn: "root" });
208
219
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoaderService, decorators: [{
209
220
  type: Injectable,
210
221
  args: [{
211
222
  providedIn: "root"
212
223
  }]
213
- }], ctorParameters: function () { return [{ type: i1$2.Overlay }]; } });
224
+ }], ctorParameters: function () { return [{ type: i1$1.Overlay }]; } });
214
225
 
215
226
  /** @format */
216
227
  const CONSTANTS_LOGGER = {
@@ -268,14 +279,14 @@ class LoggerService {
268
279
  this.logRequest({ ...data, componentName, serviceUrl }, "error");
269
280
  }
270
281
  }
271
- LoggerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoggerService, deps: [{ token: i1$3.HttpClient }, { token: CONSTANTS_LOGGER.APP_NAME }, { token: CONSTANTS_LOGGER.ENV_VAR }], target: i0.ɵɵFactoryTarget.Injectable });
282
+ LoggerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoggerService, deps: [{ token: i1$2.HttpClient }, { token: CONSTANTS_LOGGER.APP_NAME }, { token: CONSTANTS_LOGGER.ENV_VAR }], target: i0.ɵɵFactoryTarget.Injectable });
272
283
  LoggerService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoggerService, providedIn: "root" });
273
284
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LoggerService, decorators: [{
274
285
  type: Injectable,
275
286
  args: [{
276
287
  providedIn: "root"
277
288
  }]
278
- }], ctorParameters: function () { return [{ type: i1$3.HttpClient }, { type: undefined, decorators: [{
289
+ }], ctorParameters: function () { return [{ type: i1$2.HttpClient }, { type: undefined, decorators: [{
279
290
  type: Inject,
280
291
  args: [CONSTANTS_LOGGER.APP_NAME]
281
292
  }] }, { type: undefined, decorators: [{
@@ -328,23 +339,43 @@ const API_URLS = {
328
339
  CONFIGURATIONS: "configurations"
329
340
  };
330
341
  class HttpService {
331
- constructor(env, auth, http) {
342
+ constructor(env, http) {
332
343
  this.env = env;
333
- this.auth = auth;
334
344
  this.http = http;
335
345
  }
336
- getConfigurations() {
337
- return this.http.get(`${this.env.empExp}/${this.auth.userDetails.buid}/${API_URLS.CONFIGURATIONS}`);
346
+ getProperties(Porperties) {
347
+ return this.http.get(`${this.env.ets}/ets/apis/properties/${Porperties.join(",")}`).pipe(map((res) => {
348
+ return res.reduce((acc, item) => {
349
+ acc[item.propertyName] = item.propertyValue === "true" ? true : item.propertyValue === "false" ? false : item.propertyValue;
350
+ return acc;
351
+ }, {});
352
+ }));
353
+ }
354
+ getOffices(nonce) {
355
+ const body = `CSRF_NONCE=${nonce}&method=getOfficeList`;
356
+ return this.http.post(`${this.env.ets}/Locality_Servlet`, body, { headers: { "Content-Type": "application/x-www-form-urlencoded" } });
357
+ }
358
+ listTransportLocalities(nonce) {
359
+ const body = `CSRF_NONCE=${nonce}&method=listTransportLocalities`;
360
+ return this.http.post(`${this.env.ets}/Locality_Servlet`, body, { headers: { "Content-Type": "application/x-www-form-urlencoded" } });
361
+ }
362
+ createEmptyIrregularTripSheet(nonce, direction) {
363
+ const body = `CSRF_NONCE=${nonce}&method=createEmptyIrregularTripSheet&direction=${direction}`;
364
+ return this.http.post(`${this.env.ets}/Tripsheet_Edit_Servlet`, body, { headers: { "Content-Type": "application/x-www-form-urlencoded" } });
365
+ }
366
+ addEmployeeToTripSheet(nonce, params) {
367
+ const body = `CSRF_NONCE=${nonce}&method=addEmployeeToTripSheet&tripsheet=${encodeURIComponent(JSON.stringify(params.tripsheet))}&employee=${encodeURIComponent(JSON.stringify(params.employee))}&pickupLoc=${encodeURIComponent(JSON.stringify(params.pickupLoc))}&dropLoc=${encodeURIComponent(JSON.stringify(params.dropLoc))}&pickUpTime="${params.pickUpTime}"&dropTime="${params.dropTime}"&position=${params.position}${params.routeSource ? "&routeSource=" + params.routeSource : ""}${params.assetList ? "&assetList=" + encodeURIComponent(JSON.stringify(params.assetList)) : ""}`;
368
+ return this.http.post(`${this.env.ets}/Tripsheet_Edit_Servlet`, body, { headers: { "Content-Type": "application/x-www-form-urlencoded" } });
338
369
  }
339
370
  }
340
- HttpService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: HttpService, deps: [{ token: CONSTANTS_WIS_COMMON }, { token: AuthService }, { token: i1$3.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
371
+ HttpService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: HttpService, deps: [{ token: CONSTANTS_WIS_COMMON }, { token: i1$2.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
341
372
  HttpService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: HttpService });
342
373
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: HttpService, decorators: [{
343
374
  type: Injectable
344
375
  }], ctorParameters: function () { return [{ type: undefined, decorators: [{
345
376
  type: Inject,
346
377
  args: [CONSTANTS_WIS_COMMON]
347
- }] }, { type: AuthService }, { type: i1$3.HttpClient }]; } });
378
+ }] }, { type: i1$2.HttpClient }]; } });
348
379
 
349
380
  class SidenavComponent {
350
381
  constructor() { }
@@ -357,24 +388,253 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
357
388
  args: [{ selector: "wis-common-sidenav", template: "<div class=\"wis-sidenav-wrapper\">\n <div class=\"wis-sidenav-header\">\n <div class=\"wis-sidenav-header-logo\">\n <img src=\"assets/sidenav/assets/Wis-icon.svg\" alt=\"\" />\n </div>\n <div class=\"wis-sidenav-header-title\">\n <h1>WIS</h1>\n </div>\n </div>\n <div class=\"wis-sidenav-body\">\n <div class=\"wis-sidenav-body-item\">\n <div class=\"wis-sidenav-body-item-icon\">\n <i class=\"fas fa-home\"></i>\n </div>\n <div class=\"wis-sidenav-body-item-text\">\n <h3>Home</h3>\n </div>\n </div>\n <div class=\"wis-sidenav-body-item\">\n <div class=\"wis-sidenav-body-item-icon\">\n <i class=\"fas fa-user\"></i>\n </div>\n <div class=\"wis-sidenav-body-item-text\">\n <h3>Profile</h3>\n </div>\n </div>\n <div class=\"wis-sidenav-body-item\">\n <div class=\"wis-sidenav-body-item-icon\">\n <i class=\"fas fa-users\"></i>\n </div>\n <div class=\"wis-sidenav-body-item-text\">\n <h3>Users</h3>\n </div>\n </div>\n <div class=\"wis-sidenav-body-item\">\n <div class=\"wis-sidenav-body-item-icon\">\n <i class=\"fas fa-cog\"></i>\n </div>\n <div class=\"wis-sidenav-body-item-text\">\n <h3>Settings</h3>\n </div>\n </div>\n </div>\n</div>\n", styles: [".wis-sidenav-wrapper{width:72px;border-right:1px solid #e0e0e0}\n"] }]
358
389
  }], ctorParameters: function () { return []; } });
359
390
 
391
+ /** @format */
392
+ const CONSTANTS_ASSETS_WIS_COMMON = {
393
+ IMAGES: {
394
+ CALENDAR_ICON: "assets/libraries/wis-common/calendar.svg"
395
+ },
396
+ ICONS: {}
397
+ };
398
+
399
+ dayjs.extend(customParseFormat);
400
+ const PROPERTIES = ["NON_SHIFT_TRIPS_CATEGORIES", "USE_VALID_OFFICE_FOR_IRREGULAR_TRIPS"];
401
+ const DATE_FORMAT = "DD/MM/YYYY";
402
+ const PICKUP_TIME_FORMAT = "DD/MM/YYYY HH/mm/ss";
403
+ class CreateNonShiftModalComponent {
404
+ constructor(modalData, modalRef, fb, http, toast) {
405
+ this.modalData = modalData;
406
+ this.modalRef = modalRef;
407
+ this.fb = fb;
408
+ this.http = http;
409
+ this.toast = toast;
410
+ this.CONSTANTS_ASSETS_WIS_COMMON = CONSTANTS_ASSETS_WIS_COMMON;
411
+ this.dateConfig = {
412
+ minDate: dayjs().format(DATE_FORMAT),
413
+ format: DATE_FORMAT
414
+ };
415
+ this.offices = [];
416
+ this.locationDropdownData = [];
417
+ this.categoryDropdownData = [];
418
+ this.hoursDropdownData = [];
419
+ this.minutesDropdownData = [];
420
+ this.showOtherAddress = false;
421
+ this.loading = false;
422
+ this.isSubmitting = false;
423
+ this.TYPE_OFFICE = 6;
424
+ this.TYPE_TRANSPORT = 3;
425
+ this.TYPE_OTHER = 4;
426
+ this.properties = {};
427
+ }
428
+ ngOnInit() {
429
+ this.loading = true;
430
+ const $office = this.http.getOffices(this.modalData.nonce);
431
+ const $properties = this.http.getProperties(PROPERTIES);
432
+ forkJoin([$office, $properties])
433
+ .pipe(finalize(() => (this.loading = false)))
434
+ .subscribe({
435
+ next: ([offices, properties]) => {
436
+ this.properties = properties;
437
+ this.initializeForm();
438
+ this.initializeDropdownData(offices);
439
+ this.setupFormListeners();
440
+ },
441
+ error: error => {
442
+ console.error("Error loading form data:", error);
443
+ this.modalRef.close();
444
+ }
445
+ });
446
+ }
447
+ initializeForm() {
448
+ const currentTime = this.modalData?.date ?? dayjs().format(DATE_FORMAT);
449
+ this.createTripsheetForm = this.fb.group({
450
+ direction: [this.modalData?.shiftType === "logout" ? "OUT" : "IN", Validators.required],
451
+ location: [{ label: "", value: "" }],
452
+ otherAddress: "",
453
+ tripCategory: [{ label: "", value: "" }],
454
+ date: [currentTime, Validators.required],
455
+ hours: [{ label: "", value: "" }],
456
+ mins: [{ label: "", value: "" }]
457
+ });
458
+ }
459
+ initializeDropdownData(offices) {
460
+ this.locationDropdownData = offices.map((office) => ({
461
+ label: office.address,
462
+ value: { type: this.TYPE_OFFICE, office: office || null }
463
+ }));
464
+ this.createTripsheetForm.get("location")?.setValue(this.locationDropdownData[0]);
465
+ if (!this.properties?.["USE_VALID_OFFICE_FOR_IRREGULAR_TRIPS"]) {
466
+ this.locationDropdownData.push({ label: "Airport", value: { type: this.TYPE_TRANSPORT, office: null } }, { label: "Other", value: { type: this.TYPE_OTHER, office: null } });
467
+ }
468
+ // Initialize category dropdown
469
+ const categoriesString = this.properties?.["NON_SHIFT_TRIPS_CATEGORIES"];
470
+ if (categoriesString && typeof categoriesString === "string") {
471
+ const categories = categoriesString.split(",").filter(cat => cat && cat.trim());
472
+ if (categories.length > 0) {
473
+ this.categoryDropdownData = categories.map(category => ({
474
+ label: category.trim(),
475
+ value: category.trim()
476
+ }));
477
+ }
478
+ }
479
+ const currentHour = new Date().getHours();
480
+ this.hoursDropdownData = Array.from({ length: 24 }, (_, i) => ({
481
+ label: this.padZero(i),
482
+ value: this.padZero(i)
483
+ }));
484
+ this.createTripsheetForm.patchValue({ hours: this.hoursDropdownData[currentHour] });
485
+ const currentMinute = new Date().getMinutes();
486
+ this.minutesDropdownData = Array.from({ length: 60 }, (_, i) => ({
487
+ label: this.padZero(i),
488
+ value: this.padZero(i)
489
+ }));
490
+ this.createTripsheetForm.patchValue({ mins: this.minutesDropdownData[currentMinute] });
491
+ }
492
+ setupFormListeners() {
493
+ this.createTripsheetForm?.valueChanges.subscribe(value => {
494
+ const { location } = this.createTripsheetForm?.value;
495
+ if (this.showOtherAddress !== (location?.value?.type === this.TYPE_OTHER)) {
496
+ this.showOtherAddress = location?.value?.type === this.TYPE_OTHER;
497
+ if (this.showOtherAddress) {
498
+ this.createTripsheetForm.get("otherAddress")?.setValidators([Validators.required]);
499
+ }
500
+ else {
501
+ this.createTripsheetForm.get("otherAddress")?.clearValidators();
502
+ }
503
+ this.createTripsheetForm.get("otherAddress")?.updateValueAndValidity();
504
+ }
505
+ });
506
+ }
507
+ padZero(num) {
508
+ return num.toString().padStart(2, "0");
509
+ }
510
+ onCancel() {
511
+ this.modalRef.close();
512
+ }
513
+ onSubmit() {
514
+ if (this.createTripsheetForm.invalid) {
515
+ return;
516
+ }
517
+ const formValue = this.createTripsheetForm.value;
518
+ const pickupTime = `${formValue.date} ${formValue.hours.value}/${formValue.mins.value}/00`;
519
+ const pickupTimeDate = dayjs(pickupTime, PICKUP_TIME_FORMAT).toDate();
520
+ if (this.isDateAndTimeFromPast(pickupTimeDate)) {
521
+ this.toast.displayMsg("Please select a future date and time.");
522
+ return;
523
+ }
524
+ if (this.categoryDropdownData.length > 0 && (!formValue.tripCategory || !formValue.tripCategory.value)) {
525
+ this.toast.displayMsg("Please provide a trip category.");
526
+ return;
527
+ }
528
+ if (formValue.location?.value?.type === this.TYPE_OTHER) {
529
+ if (!formValue.otherAddress || formValue.otherAddress.trim() === "") {
530
+ this.toast.displayMsg("Please provide the address.");
531
+ return;
532
+ }
533
+ if (formValue.otherAddress.includes(",")) {
534
+ this.toast.displayMsg("Special character (,) not allowed in address.");
535
+ return;
536
+ }
537
+ }
538
+ this.isSubmitting = true;
539
+ this.http.createEmptyIrregularTripSheet(this.modalData.nonce, formValue.direction).subscribe({
540
+ next: routeTripSheet => {
541
+ const pickupLoc = routeTripSheet.dir === "IN" ? this.modalData.employee.home : this.getLocation(formValue);
542
+ const dropLoc = routeTripSheet.dir === "OUT" ? this.modalData.employee.home : this.getLocation(formValue);
543
+ const pickupTimeFormatted = pickupTime;
544
+ const dropTimeFormatted = pickupTime;
545
+ const employee = { ...this.modalData.employee, employee_status: 1 };
546
+ const addEmployeeParams = {
547
+ tripsheet: routeTripSheet,
548
+ employee: employee,
549
+ pickupLoc: pickupLoc,
550
+ dropLoc: dropLoc,
551
+ pickUpTime: pickupTimeFormatted,
552
+ dropTime: dropTimeFormatted,
553
+ position: 0,
554
+ routeSource: this.modalData.routeSource,
555
+ assetList: this.modalData.assetList
556
+ };
557
+ this.http.addEmployeeToTripSheet(this.modalData.nonce, addEmployeeParams).subscribe({
558
+ next: updatedTripSheet => {
559
+ if (!updatedTripSheet.customMap) {
560
+ updatedTripSheet.customMap = {};
561
+ }
562
+ updatedTripSheet.customMap.tripCategory = formValue.tripCategory?.value || "";
563
+ this.modalRef.close({
564
+ success: true,
565
+ tripsheet: updatedTripSheet
566
+ });
567
+ },
568
+ error: error => {
569
+ console.error("Error adding employee to tripsheet:", error);
570
+ this.toast.displayMsg("Failed to add employee to tripsheet. Please try again.");
571
+ this.isSubmitting = false;
572
+ }
573
+ });
574
+ },
575
+ error: error => {
576
+ console.error("Error creating tripsheet:", error);
577
+ this.toast.displayMsg("Failed to create tripsheet. Please try again.");
578
+ this.isSubmitting = false;
579
+ }
580
+ });
581
+ }
582
+ isDateAndTimeFromPast(date) {
583
+ const now = new Date();
584
+ return date < now;
585
+ }
586
+ getLocation(formValue) {
587
+ const location = formValue.location?.value;
588
+ if (!location) {
589
+ return null;
590
+ }
591
+ const locType = location.type;
592
+ switch (locType) {
593
+ case this.TYPE_OFFICE:
594
+ return location.office;
595
+ case this.TYPE_TRANSPORT:
596
+ return {
597
+ id: null,
598
+ type: this.TYPE_TRANSPORT,
599
+ address: "Airport",
600
+ geoCord: null
601
+ };
602
+ case this.TYPE_OTHER:
603
+ return {
604
+ ...location.office,
605
+ address: formValue.otherAddress || ""
606
+ };
607
+ }
608
+ }
609
+ }
610
+ CreateNonShiftModalComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CreateNonShiftModalComponent, deps: [{ token: MODAL_DATA_VAR }, { token: i1$3.ModalRef }, { token: i2$2.FormBuilder }, { token: HttpService }, { token: i2.ToastService }], target: i0.ɵɵFactoryTarget.Component });
611
+ CreateNonShiftModalComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: CreateNonShiftModalComponent, selector: "app-create-non-shift-modal", ngImport: i0, template: "<div class=\"createTripsheet\">\n <h2 class=\"modal-header\">Create Non-Shift Tripsheet</h2>\n\n <div *ngIf=\"loading\" class=\"loading-container\">\n <div class=\"spinner\"></div>\n <p>Loading...</p>\n </div>\n\n <form\n *ngIf=\"!loading && createTripsheetForm\"\n [formGroup]=\"createTripsheetForm\"\n (ngSubmit)=\"onSubmit()\"\n class=\"createTripsheetForm\"\n id=\"createTripsheetForm\"\n >\n <div class=\"form-content\">\n <!-- Radio buttons row -->\n <div [ngClass]=\"{ 'radio-row': true, disabled: modalData?.shiftSelectionDisabled }\">\n <label class=\"radio-label\">\n <input class=\"modern-checkbox\" type=\"radio\" formControlName=\"direction\" value=\"OUT\" id=\"startLoc\" />\n <span>Start Location Fixed (Logout)</span>\n </label>\n <label class=\"radio-label\">\n <input class=\"modern-checkbox\" type=\"radio\" formControlName=\"direction\" value=\"IN\" id=\"endLoc\" />\n <span>End Location Fixed (Login)</span>\n </label>\n </div>\n\n <!-- Location field -->\n <div class=\"form-field\">\n <div class=\"label-cell\">\n <label class=\"locText\">Location</label>\n </div>\n <div class=\"input-cell\">\n <mis-dropdown\n [searchEnabled]=\"true\"\n [width]=\"'100%'\"\n [height]=\"'40px'\"\n [data]=\"locationDropdownData\"\n [selectedItem]=\"createTripsheetForm.get('location')?.value\"\n [label]=\"'Select location...'\"\n (onChange)=\"createTripsheetForm.get('location')?.setValue($event)\"\n ></mis-dropdown>\n </div>\n </div>\n\n <!-- Other address field -->\n <div class=\"form-field otherAddress\" *ngIf=\"showOtherAddress\">\n <div class=\"label-cell\">\n <label>Pick/Drop point <sup>*</sup></label>\n </div>\n <div class=\"input-cell\">\n <input type=\"text\" formControlName=\"otherAddress\" class=\"modern-input\" />\n </div>\n </div>\n\n <!-- Trip category field -->\n <div class=\"form-field\" *ngIf=\"categoryDropdownData.length > 0\">\n <div class=\"label-cell\">\n <label>Trip Category</label>\n </div>\n <div class=\"input-cell\">\n <mis-dropdown\n [searchEnabled]=\"false\"\n [width]=\"'250px'\"\n [height]=\"'40px'\"\n [data]=\"categoryDropdownData\"\n [selectedItem]=\"createTripsheetForm.get('tripCategory')?.value\"\n [label]=\"'Select category...'\"\n (onChange)=\"createTripsheetForm.get('tripCategory')?.setValue($event)\"\n ></mis-dropdown>\n </div>\n </div>\n\n <!-- Time field -->\n <div class=\"form-field\">\n <div class=\"label-cell\">\n <label class=\"fixedTimeText\">Time</label>\n </div>\n <div class=\"input-cell modern-date-container\">\n <div class=\"date-select\">\n <input\n misTzDp\n readonly\n [dpConfig]=\"dateConfig\"\n [formControl]=\"createTripsheetForm.get('date')\"\n style=\"height: 44px !important; font-size: 16px !important; cursor: pointer; vertical-align: middle !important\"\n />\n <img [src]=\"CONSTANTS_ASSETS_WIS_COMMON.IMAGES.CALENDAR_ICON\" alt=\"Calendar Icon\" class=\"date-icon data-picker-icon\" />\n </div>\n\n <mis-dropdown\n [searchEnabled]=\"false\"\n [width]=\"'5rem'\"\n [height]=\"'40px'\"\n [data]=\"hoursDropdownData\"\n [selectedItem]=\"createTripsheetForm.get('hours')?.value\"\n [label]=\"'HH'\"\n (onChange)=\"createTripsheetForm.get('hours')?.setValue($event)\"\n ></mis-dropdown>\n\n <mis-dropdown\n [searchEnabled]=\"false\"\n [width]=\"'5rem'\"\n [height]=\"'40px'\"\n [data]=\"minutesDropdownData\"\n [selectedItem]=\"createTripsheetForm.get('mins')?.value\"\n [label]=\"'MM'\"\n (onChange)=\"createTripsheetForm.get('mins')?.setValue($event)\"\n ></mis-dropdown>\n </div>\n </div>\n </div>\n\n <div class=\"form-actions\">\n <button mis-button type=\"outline\" (click)=\"onCancel()\" [disabled]=\"isSubmitting\">Cancel</button>\n <button mis-button type=\"primary\" [disabled]=\"isSubmitting || createTripsheetForm?.invalid\">\n {{ isSubmitting ? \"Creating...\" : \"Create\" }}\n </button>\n </div>\n </form>\n</div>\n", styles: [".createTripsheet{width:40rem;margin:auto;background:#fff;border-radius:.5rem;padding:1.25rem}.createTripsheet .modal-header{font-size:1.25rem;font-weight:600;color:#333;margin:0 0 1.25rem;padding-bottom:.9375rem;border-bottom:.0625rem solid #e0e0e0}.createTripsheet .loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3.75rem 1.25rem;min-height:12.5rem}.createTripsheet .loading-container .spinner{border:.1875rem solid #f3f3f3;border-top:.1875rem solid #007bff;border-radius:50%;width:2.5rem;height:2.5rem;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.createTripsheet .createTripsheetForm .form-content{display:flex;flex-direction:column}.createTripsheet .createTripsheetForm .form-field{display:flex;align-items:flex-start;gap:1.25rem;padding:.9375rem 0}.createTripsheet .createTripsheetForm .form-field .label-cell{flex:0 0 30%;padding-top:.5rem}.createTripsheet .createTripsheetForm .form-field .label-cell label{font-size:.875rem;font-weight:500;color:#333}.createTripsheet .createTripsheetForm .form-field .input-cell{flex:1;display:flex}.createTripsheet .createTripsheetForm .radio-row{display:flex;gap:1.25rem;padding:.9375rem 0}.createTripsheet .createTripsheetForm .radio-label{font-size:.875rem;display:flex;align-items:center;cursor:pointer;margin:0}.createTripsheet .createTripsheetForm .radio-label .modern-checkbox{margin-right:.625rem;vertical-align:sub;cursor:pointer;width:1rem;height:1rem;accent-color:#007bff}.createTripsheet .createTripsheetForm .radio-label span{-webkit-user-select:none;user-select:none;white-space:nowrap}.createTripsheet .createTripsheetForm .modern-input{width:100%;padding:.5rem .75rem;border:.0625rem solid #ddd;border-radius:.25rem;font-size:.875rem;transition:border-color .3s}.createTripsheet .createTripsheetForm .modern-input:focus{outline:none;border-color:#007bff;box-shadow:0 0 0 .2rem #007bff40}.createTripsheet .createTripsheetForm .modern-input:disabled{background-color:#f5f5f5;cursor:not-allowed}.createTripsheet .createTripsheetForm sup{color:#dc3545}.createTripsheet .createTripsheetForm ::ng-deep mis-dropdown{display:block;width:100%}.createTripsheet .createTripsheetForm .modern-date-container{position:inherit;float:inherit;display:flex;align-items:center;gap:.625rem}.createTripsheet .createTripsheetForm .ng-invalid{border:.0625rem solid #dc3545}.createTripsheet .createTripsheetForm .form-actions{text-align:right;margin:.625rem;border-top:.0625rem solid #e0e0e0;padding:.625rem;display:flex;justify-content:flex-end;gap:.625rem;margin-bottom:0}.createTripsheet .createTripsheetForm .form-actions button{padding:.625rem 1.5rem;font-size:.875rem;font-weight:500;border-radius:.375rem;border:none;cursor:pointer;transition:all .3s ease;min-width:6.25rem}.createTripsheet .createTripsheetForm .form-actions button[type=primary]{background-color:#0937b2;color:#fff;border:.0625rem solid #0937b2}.createTripsheet .createTripsheetForm .form-actions button[type=outline]{background-color:transparent;color:#6c757d;border:.0625rem solid #ddd}.createTripsheet .createTripsheetForm .form-actions button:disabled{opacity:.6;cursor:not-allowed;box-shadow:none}.date-select{height:2.5rem;border:.0625rem solid #e0e0e0;padding:0;border-radius:.375rem;display:flex;flex-wrap:nowrap;justify-content:space-between;align-items:center;position:relative;overflow:hidden;left:-.5%;flex-shrink:0}.date-select input{background-color:transparent;display:inline-block;padding:.25rem 0 .25rem .75rem;width:100%;border:none;outline:none;cursor:pointer;font-size:.875rem}.date-select img{position:relative;right:1rem}.radio-row.disabled{pointer-events:none;opacity:.5}\n"], dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i6.DropdownComponent, selector: "mis-dropdown", inputs: ["data", "height", "ariaLabel", "width", "label", "itemSizeForCdk", "showOnlyIcon", "higlightSelectedValue", "dropdownListHeight", "dropdownListWidth", "dropdownListPosition", "config", "searchEnabled", "selectedItem", "noDataMessage", "multiLine", "additionalInfoMessage", "scrollIntoView", "searchLabel", "customStyles", "activeItem"], outputs: ["onChange"] }, { kind: "directive", type: i2$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i7.TzDatepickerDirective, selector: "input[misTzDp]", inputs: ["dpConfig", "selectedDate", "datesDisabled", "dateMessages", "positionX", "positionY", "offsetX", "offsetY", "allowBookingOnDisabledDay", "disableBoxShadow", "disableOverLay", "openElement"], outputs: ["dateChange"] }] });
612
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CreateNonShiftModalComponent, decorators: [{
613
+ type: Component,
614
+ args: [{ selector: "app-create-non-shift-modal", template: "<div class=\"createTripsheet\">\n <h2 class=\"modal-header\">Create Non-Shift Tripsheet</h2>\n\n <div *ngIf=\"loading\" class=\"loading-container\">\n <div class=\"spinner\"></div>\n <p>Loading...</p>\n </div>\n\n <form\n *ngIf=\"!loading && createTripsheetForm\"\n [formGroup]=\"createTripsheetForm\"\n (ngSubmit)=\"onSubmit()\"\n class=\"createTripsheetForm\"\n id=\"createTripsheetForm\"\n >\n <div class=\"form-content\">\n <!-- Radio buttons row -->\n <div [ngClass]=\"{ 'radio-row': true, disabled: modalData?.shiftSelectionDisabled }\">\n <label class=\"radio-label\">\n <input class=\"modern-checkbox\" type=\"radio\" formControlName=\"direction\" value=\"OUT\" id=\"startLoc\" />\n <span>Start Location Fixed (Logout)</span>\n </label>\n <label class=\"radio-label\">\n <input class=\"modern-checkbox\" type=\"radio\" formControlName=\"direction\" value=\"IN\" id=\"endLoc\" />\n <span>End Location Fixed (Login)</span>\n </label>\n </div>\n\n <!-- Location field -->\n <div class=\"form-field\">\n <div class=\"label-cell\">\n <label class=\"locText\">Location</label>\n </div>\n <div class=\"input-cell\">\n <mis-dropdown\n [searchEnabled]=\"true\"\n [width]=\"'100%'\"\n [height]=\"'40px'\"\n [data]=\"locationDropdownData\"\n [selectedItem]=\"createTripsheetForm.get('location')?.value\"\n [label]=\"'Select location...'\"\n (onChange)=\"createTripsheetForm.get('location')?.setValue($event)\"\n ></mis-dropdown>\n </div>\n </div>\n\n <!-- Other address field -->\n <div class=\"form-field otherAddress\" *ngIf=\"showOtherAddress\">\n <div class=\"label-cell\">\n <label>Pick/Drop point <sup>*</sup></label>\n </div>\n <div class=\"input-cell\">\n <input type=\"text\" formControlName=\"otherAddress\" class=\"modern-input\" />\n </div>\n </div>\n\n <!-- Trip category field -->\n <div class=\"form-field\" *ngIf=\"categoryDropdownData.length > 0\">\n <div class=\"label-cell\">\n <label>Trip Category</label>\n </div>\n <div class=\"input-cell\">\n <mis-dropdown\n [searchEnabled]=\"false\"\n [width]=\"'250px'\"\n [height]=\"'40px'\"\n [data]=\"categoryDropdownData\"\n [selectedItem]=\"createTripsheetForm.get('tripCategory')?.value\"\n [label]=\"'Select category...'\"\n (onChange)=\"createTripsheetForm.get('tripCategory')?.setValue($event)\"\n ></mis-dropdown>\n </div>\n </div>\n\n <!-- Time field -->\n <div class=\"form-field\">\n <div class=\"label-cell\">\n <label class=\"fixedTimeText\">Time</label>\n </div>\n <div class=\"input-cell modern-date-container\">\n <div class=\"date-select\">\n <input\n misTzDp\n readonly\n [dpConfig]=\"dateConfig\"\n [formControl]=\"createTripsheetForm.get('date')\"\n style=\"height: 44px !important; font-size: 16px !important; cursor: pointer; vertical-align: middle !important\"\n />\n <img [src]=\"CONSTANTS_ASSETS_WIS_COMMON.IMAGES.CALENDAR_ICON\" alt=\"Calendar Icon\" class=\"date-icon data-picker-icon\" />\n </div>\n\n <mis-dropdown\n [searchEnabled]=\"false\"\n [width]=\"'5rem'\"\n [height]=\"'40px'\"\n [data]=\"hoursDropdownData\"\n [selectedItem]=\"createTripsheetForm.get('hours')?.value\"\n [label]=\"'HH'\"\n (onChange)=\"createTripsheetForm.get('hours')?.setValue($event)\"\n ></mis-dropdown>\n\n <mis-dropdown\n [searchEnabled]=\"false\"\n [width]=\"'5rem'\"\n [height]=\"'40px'\"\n [data]=\"minutesDropdownData\"\n [selectedItem]=\"createTripsheetForm.get('mins')?.value\"\n [label]=\"'MM'\"\n (onChange)=\"createTripsheetForm.get('mins')?.setValue($event)\"\n ></mis-dropdown>\n </div>\n </div>\n </div>\n\n <div class=\"form-actions\">\n <button mis-button type=\"outline\" (click)=\"onCancel()\" [disabled]=\"isSubmitting\">Cancel</button>\n <button mis-button type=\"primary\" [disabled]=\"isSubmitting || createTripsheetForm?.invalid\">\n {{ isSubmitting ? \"Creating...\" : \"Create\" }}\n </button>\n </div>\n </form>\n</div>\n", styles: [".createTripsheet{width:40rem;margin:auto;background:#fff;border-radius:.5rem;padding:1.25rem}.createTripsheet .modal-header{font-size:1.25rem;font-weight:600;color:#333;margin:0 0 1.25rem;padding-bottom:.9375rem;border-bottom:.0625rem solid #e0e0e0}.createTripsheet .loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3.75rem 1.25rem;min-height:12.5rem}.createTripsheet .loading-container .spinner{border:.1875rem solid #f3f3f3;border-top:.1875rem solid #007bff;border-radius:50%;width:2.5rem;height:2.5rem;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.createTripsheet .createTripsheetForm .form-content{display:flex;flex-direction:column}.createTripsheet .createTripsheetForm .form-field{display:flex;align-items:flex-start;gap:1.25rem;padding:.9375rem 0}.createTripsheet .createTripsheetForm .form-field .label-cell{flex:0 0 30%;padding-top:.5rem}.createTripsheet .createTripsheetForm .form-field .label-cell label{font-size:.875rem;font-weight:500;color:#333}.createTripsheet .createTripsheetForm .form-field .input-cell{flex:1;display:flex}.createTripsheet .createTripsheetForm .radio-row{display:flex;gap:1.25rem;padding:.9375rem 0}.createTripsheet .createTripsheetForm .radio-label{font-size:.875rem;display:flex;align-items:center;cursor:pointer;margin:0}.createTripsheet .createTripsheetForm .radio-label .modern-checkbox{margin-right:.625rem;vertical-align:sub;cursor:pointer;width:1rem;height:1rem;accent-color:#007bff}.createTripsheet .createTripsheetForm .radio-label span{-webkit-user-select:none;user-select:none;white-space:nowrap}.createTripsheet .createTripsheetForm .modern-input{width:100%;padding:.5rem .75rem;border:.0625rem solid #ddd;border-radius:.25rem;font-size:.875rem;transition:border-color .3s}.createTripsheet .createTripsheetForm .modern-input:focus{outline:none;border-color:#007bff;box-shadow:0 0 0 .2rem #007bff40}.createTripsheet .createTripsheetForm .modern-input:disabled{background-color:#f5f5f5;cursor:not-allowed}.createTripsheet .createTripsheetForm sup{color:#dc3545}.createTripsheet .createTripsheetForm ::ng-deep mis-dropdown{display:block;width:100%}.createTripsheet .createTripsheetForm .modern-date-container{position:inherit;float:inherit;display:flex;align-items:center;gap:.625rem}.createTripsheet .createTripsheetForm .ng-invalid{border:.0625rem solid #dc3545}.createTripsheet .createTripsheetForm .form-actions{text-align:right;margin:.625rem;border-top:.0625rem solid #e0e0e0;padding:.625rem;display:flex;justify-content:flex-end;gap:.625rem;margin-bottom:0}.createTripsheet .createTripsheetForm .form-actions button{padding:.625rem 1.5rem;font-size:.875rem;font-weight:500;border-radius:.375rem;border:none;cursor:pointer;transition:all .3s ease;min-width:6.25rem}.createTripsheet .createTripsheetForm .form-actions button[type=primary]{background-color:#0937b2;color:#fff;border:.0625rem solid #0937b2}.createTripsheet .createTripsheetForm .form-actions button[type=outline]{background-color:transparent;color:#6c757d;border:.0625rem solid #ddd}.createTripsheet .createTripsheetForm .form-actions button:disabled{opacity:.6;cursor:not-allowed;box-shadow:none}.date-select{height:2.5rem;border:.0625rem solid #e0e0e0;padding:0;border-radius:.375rem;display:flex;flex-wrap:nowrap;justify-content:space-between;align-items:center;position:relative;overflow:hidden;left:-.5%;flex-shrink:0}.date-select input{background-color:transparent;display:inline-block;padding:.25rem 0 .25rem .75rem;width:100%;border:none;outline:none;cursor:pointer;font-size:.875rem}.date-select img{position:relative;right:1rem}.radio-row.disabled{pointer-events:none;opacity:.5}\n"] }]
615
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
616
+ type: Inject,
617
+ args: [MODAL_DATA_VAR]
618
+ }] }, { type: i1$3.ModalRef }, { type: i2$2.FormBuilder }, { type: HttpService }, { type: i2.ToastService }]; } });
619
+
360
620
  class WisCommonModule {
361
621
  static forRoot(env) {
362
622
  return {
363
623
  ngModule: WisCommonModule,
364
- providers: [{ provide: CONSTANTS_WIS_COMMON, useValue: env }, ConfigurationService, LoaderService]
624
+ providers: [HttpService, { provide: CONSTANTS_WIS_COMMON, useValue: env }, ConfigurationService, LoaderService]
365
625
  };
366
626
  }
367
627
  }
368
628
  WisCommonModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: WisCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
369
- WisCommonModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: WisCommonModule, declarations: [LoaderComponent, SidenavComponent], imports: [CommonModule, OverlayModule, LoaderModule], exports: [SidenavComponent] });
370
- WisCommonModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: WisCommonModule, providers: [HttpService], imports: [CommonModule, OverlayModule, LoaderModule] });
629
+ WisCommonModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: WisCommonModule, declarations: [LoaderComponent, SidenavComponent, CreateNonShiftModalComponent], imports: [CommonModule, HttpClientModule, OverlayModule, LoaderModule, DropdownModule, ReactiveFormsModule, DatepickerModuleV2], exports: [SidenavComponent, CreateNonShiftModalComponent] });
630
+ WisCommonModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: WisCommonModule, imports: [CommonModule, HttpClientModule, OverlayModule, LoaderModule, DropdownModule, ReactiveFormsModule, DatepickerModuleV2] });
371
631
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: WisCommonModule, decorators: [{
372
632
  type: NgModule,
373
633
  args: [{
374
- declarations: [LoaderComponent, SidenavComponent],
375
- imports: [CommonModule, OverlayModule, LoaderModule],
376
- providers: [HttpService],
377
- exports: [SidenavComponent]
634
+ declarations: [LoaderComponent, SidenavComponent, CreateNonShiftModalComponent],
635
+ imports: [CommonModule, HttpClientModule, OverlayModule, LoaderModule, DropdownModule, ReactiveFormsModule, DatepickerModuleV2,],
636
+ providers: [],
637
+ exports: [SidenavComponent, CreateNonShiftModalComponent]
378
638
  }]
379
639
  }] });
380
640
 
@@ -404,6 +664,243 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
404
664
  }]
405
665
  }], ctorParameters: function () { return []; } });
406
666
 
667
+ class SessionError extends Error {
668
+ }
669
+ class SessionTokenNotFoundError extends SessionError {
670
+ constructor() {
671
+ super('Session token was not found.');
672
+ this.name = 'SessionTokenNotFoundError';
673
+ }
674
+ }
675
+ class SessionTokenExpiredError extends SessionError {
676
+ constructor() {
677
+ super('Session token has expired.');
678
+ this.name = 'SessionTokenExpiredError';
679
+ }
680
+ }
681
+ class SessionTokenInvalidError extends SessionError {
682
+ constructor() {
683
+ super('Session token could not be decoded.');
684
+ this.name = 'SessionTokenInvalidError';
685
+ }
686
+ }
687
+ class SessionClaimNotFoundError extends SessionError {
688
+ constructor(claim) {
689
+ super(`Session claim "${claim}" was not found in the token.`);
690
+ this.claim = claim;
691
+ this.name = 'SessionClaimNotFoundError';
692
+ }
693
+ }
694
+ /** Renders failures as `claim (reason), claim (reason)` for error messages. */
695
+ function describeClaimFailures(failures) {
696
+ return failures.map(f => `${f.claim} (${f.reason})`).join(', ');
697
+ }
698
+ /**
699
+ * Every claim `run`'s `next` failed to read, reported once after the block has finished.
700
+ * Extends `SessionClaimNotFoundError` — and reports the first failure as `claim` — so handlers
701
+ * written against the single-claim error keep working.
702
+ */
703
+ class SessionClaimsMissingError extends SessionClaimNotFoundError {
704
+ constructor(failures) {
705
+ super(failures[0].claim);
706
+ this.failures = failures;
707
+ this.name = 'SessionClaimsMissingError';
708
+ this.message = `Session claims not found: ${describeClaimFailures(failures)}.`;
709
+ }
710
+ }
711
+
712
+ const DEFAULT_SESSION_TOKEN_PREFIX = 'sso-wis-token';
713
+ const DEFAULT_SESSION_TOKEN_FALLBACK_KEY = 'x-wis-token';
714
+ const DEFAULT_VET_TOKEN_PREFIX = 'x-vet-token';
715
+ const LAUNCH_SOURCE_VET = 'VET';
716
+ class SessionService {
717
+ constructor() {
718
+ this.config = {};
719
+ this.cachedToken = null;
720
+ this.cachedState = null;
721
+ this.collecting = null;
722
+ }
723
+ init(config) {
724
+ this.config = { ...config };
725
+ this.cachedToken = null;
726
+ this.cachedState = null;
727
+ }
728
+ /**
729
+ * Runs `handlers.next` and returns its result, or `handlers.error(error)` if it throws a `SessionError`.
730
+ * Centralizes the try/catch mechanics; the caller still supplies the actual handling logic.
731
+ */
732
+ read(handlers) {
733
+ try {
734
+ return handlers.next(this);
735
+ }
736
+ catch (e) {
737
+ if (e instanceof SessionError) {
738
+ return handlers.error(e);
739
+ }
740
+ throw e;
741
+ }
742
+ }
743
+ /**
744
+ * Statement-style variant of `read` for blocks of assignments/side effects with no return value.
745
+ *
746
+ * `next` always runs to completion: a claim that is absent or blank yields `undefined` instead of
747
+ * throwing, and every such failure is reported once afterwards via `handlers.error`, as a
748
+ * `SessionClaimsMissingError` listing all of them. An unusable token (missing, expired,
749
+ * undecodable) still aborts `next` immediately with the matching `SessionError`.
750
+ *
751
+ * Collecting covers the synchronous body of `next` only — claim reads deferred into a subscription,
752
+ * timeout or promise run after it has returned and throw as usual.
753
+ *
754
+ * An error `next` throws for any other reason propagates untouched, except that any claims missing
755
+ * at the time are appended to its message and attached as `sessionClaimFailures` — a collected
756
+ * `undefined` reaching the block is the usual cause, and that is the part worth knowing.
757
+ */
758
+ run(handlers) {
759
+ const failures = [];
760
+ const previous = this.collecting;
761
+ this.collecting = failures;
762
+ try {
763
+ handlers.next(this);
764
+ }
765
+ catch (e) {
766
+ if (e instanceof SessionError) {
767
+ handlers.error(e);
768
+ return;
769
+ }
770
+ if (failures.length && e instanceof Error) {
771
+ e.sessionClaimFailures = failures;
772
+ e.message = `${e.message} — session claims missing during run(): ${describeClaimFailures(failures)}`;
773
+ }
774
+ throw e;
775
+ }
776
+ finally {
777
+ this.collecting = previous;
778
+ }
779
+ if (failures.length) {
780
+ handlers.error(new SessionClaimsMissingError(failures));
781
+ }
782
+ }
783
+ get isVET() {
784
+ return this.state.isVET;
785
+ }
786
+ get sub() { return this.getClaim('sub'); }
787
+ get empGuid() { return this.getClaim('employeeGUID'); }
788
+ get employeeId() { return this.getClaim('employeeId'); }
789
+ get internalSsoRole() { return this.getClaim('internal_sso_role'); }
790
+ get roles() { return this.getClaim('roles'); }
791
+ get sessionId() { return this.getClaim('sessionId'); }
792
+ get loggedInUser() { return this.getClaim('loggedInUser'); }
793
+ get exp() { return this.getClaim('exp'); }
794
+ get iat() { return this.getClaim('iat'); }
795
+ get businessUnitId() { return this.getClaim('businessUnitId'); }
796
+ get allowedBuids() { return this.getClaim('ALLOWED_BUIDS'); }
797
+ get vetUserEmailId() { return this.getClaim('vetUserEmailId'); }
798
+ get vetUserId() { return this.getClaim('vetUserId'); }
799
+ get source() { return this.getClaim('source'); }
800
+ get roleId() {
801
+ const raw = this.resolveRole(this.getClaims());
802
+ if (!raw) {
803
+ return this.missingClaim('roleId', 'absent');
804
+ }
805
+ return Number(raw);
806
+ }
807
+ /** First numeric role in `internal_sso_role` then `roles`, or `''` when the token carries none. */
808
+ resolveRole(claims) {
809
+ const candidates = [claims.internal_sso_role, ...(claims.roles ?? [])];
810
+ return candidates
811
+ .map(value => value?.trim())
812
+ .find(value => this.isDigitsOnly(value)) ?? '';
813
+ }
814
+ isDigitsOnly(value) {
815
+ return !!value && /^\d+$/.test(value);
816
+ }
817
+ getClaims() {
818
+ const state = this.state;
819
+ if (state.status === 'ok') {
820
+ return state.claims;
821
+ }
822
+ if (state.status === 'not-found') {
823
+ throw new SessionTokenNotFoundError();
824
+ }
825
+ if (state.status === 'expired') {
826
+ throw new SessionTokenExpiredError();
827
+ }
828
+ throw new SessionTokenInvalidError();
829
+ }
830
+ getClaim(key) {
831
+ const claims = this.getClaims();
832
+ const value = claims[key];
833
+ const isEmptyString = typeof value === 'string' && value.trim() === '';
834
+ if (value === undefined || value === null || isEmptyString) {
835
+ return this.missingClaim(key, isEmptyString ? 'blank' : 'absent');
836
+ }
837
+ return (typeof value === 'string' ? value.trim() : value);
838
+ }
839
+ /** Records the failure and yields `undefined` while `run` is collecting; throws otherwise. */
840
+ missingClaim(claim, reason) {
841
+ if (this.collecting) {
842
+ this.collecting.push({ claim, reason });
843
+ return undefined;
844
+ }
845
+ throw new SessionClaimNotFoundError(claim);
846
+ }
847
+ get state() {
848
+ const { token, isVET } = this.findToken();
849
+ if (!this.cachedState || token !== this.cachedToken) {
850
+ this.cachedToken = token;
851
+ this.cachedState = this.build(token, isVET);
852
+ }
853
+ return this.cachedState;
854
+ }
855
+ build(token, isVET) {
856
+ if (!token) {
857
+ return { status: 'not-found', isVET };
858
+ }
859
+ let claims;
860
+ try {
861
+ claims = jwtDecode(token);
862
+ }
863
+ catch {
864
+ return { status: 'invalid', isVET };
865
+ }
866
+ if (this.isExpired(claims)) {
867
+ return { status: 'expired', isVET };
868
+ }
869
+ return { status: 'ok', claims, isVET };
870
+ }
871
+ isExpired(claims) {
872
+ return typeof claims.exp === 'number' && claims.exp * 1000 <= Date.now();
873
+ }
874
+ isVETSource() {
875
+ return getQueryParam('source') === LAUNCH_SOURCE_VET;
876
+ }
877
+ resolveBuid() {
878
+ return getQueryParam('buid') || getCookie('buid') || null;
879
+ }
880
+ findToken() {
881
+ const buid = this.resolveBuid();
882
+ if (this.isVETSource()) {
883
+ const vetKey = this.config.vetTokenCookieKey ?? (buid ? `${DEFAULT_VET_TOKEN_PREFIX}-${buid}` : null);
884
+ const vetToken = (vetKey ? getCookie(vetKey) : '') || '';
885
+ if (vetToken) {
886
+ return { token: vetToken, isVET: true };
887
+ }
888
+ }
889
+ const sessionToken = this.config.sessionTokenCookieKey
890
+ ? getCookie(this.config.sessionTokenCookieKey)
891
+ : (buid ? getCookie(`${DEFAULT_SESSION_TOKEN_PREFIX}-${buid}`) : '') || getCookie(DEFAULT_SESSION_TOKEN_FALLBACK_KEY);
892
+ return { token: sessionToken || '', isVET: false };
893
+ }
894
+ }
895
+ SessionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SessionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
896
+ SessionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SessionService, providedIn: 'root' });
897
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SessionService, decorators: [{
898
+ type: Injectable,
899
+ args: [{
900
+ providedIn: 'root'
901
+ }]
902
+ }] });
903
+
407
904
  /*
408
905
  * Public API Surface of wis-common
409
906
  */
@@ -412,5 +909,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
412
909
  * Generated bundle index. Do not edit.
413
910
  */
414
911
 
415
- export { AuthInterceptor, AuthModule, AuthService, ConfigurationService, LoaderService, LoggerModule, LoggerService, MfeCommunicationService, SidenavComponent, WisCommonModule, filterNavList, getCookie, getQueryParam, removeCookie, setCookie };
912
+ export { AuthInterceptor, AuthModule, AuthService, ConfigurationService, CreateNonShiftModalComponent, LoaderService, LoggerModule, LoggerService, MfeCommunicationService, SessionClaimNotFoundError, SessionClaimsMissingError, SessionError, SessionService, SessionTokenExpiredError, SessionTokenInvalidError, SessionTokenNotFoundError, SidenavComponent, WisCommonModule, describeClaimFailures, filterNavList, getCookie, getQueryParam, removeCookie, setCookie };
416
913
  //# sourceMappingURL=mis-wis-common.mjs.map