tango-app-ui-manage-tickets 3.7.0-beta.15 → 3.7.0-beta.16

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 (91) hide show
  1. package/.eslintrc.json +37 -0
  2. package/ng-package.json +7 -0
  3. package/package.json +12 -25
  4. package/src/lib/components/add-csm-modal/add-csm-modal.component.html +32 -0
  5. package/src/lib/components/add-csm-modal/add-csm-modal.component.scss +14 -0
  6. package/src/lib/components/add-csm-modal/add-csm-modal.component.spec.ts +23 -0
  7. package/src/lib/components/add-csm-modal/add-csm-modal.component.ts +94 -0
  8. package/src/lib/components/audit-log/audit-log.component.html +1 -0
  9. package/src/lib/components/audit-log/audit-log.component.scss +0 -0
  10. package/src/lib/components/audit-log/audit-log.component.spec.ts +23 -0
  11. package/src/lib/components/audit-log/audit-log.component.ts +10 -0
  12. package/src/lib/components/audit-metrics/audit-metrics.component.html +345 -0
  13. package/src/lib/components/audit-metrics/audit-metrics.component.scss +34 -0
  14. package/src/lib/components/audit-metrics/audit-metrics.component.spec.ts +23 -0
  15. package/src/lib/components/audit-metrics/audit-metrics.component.ts +292 -0
  16. package/src/lib/components/comment-model/comment-model.component.html +24 -0
  17. package/src/lib/components/comment-model/comment-model.component.scss +20 -0
  18. package/src/lib/components/comment-model/comment-model.component.spec.ts +23 -0
  19. package/src/lib/components/comment-model/comment-model.component.ts +53 -0
  20. package/src/lib/components/count/count.component.html +54 -0
  21. package/src/lib/components/count/count.component.scss +14 -0
  22. package/src/lib/components/count/count.component.spec.ts +23 -0
  23. package/src/lib/components/count/count.component.ts +82 -0
  24. package/src/lib/components/footfall-dic/footfall-dic.component.html +1242 -0
  25. package/src/lib/components/footfall-dic/footfall-dic.component.scss +273 -0
  26. package/src/lib/components/footfall-dic/footfall-dic.component.spec.ts +23 -0
  27. package/src/lib/components/footfall-dic/footfall-dic.component.ts +1106 -0
  28. package/src/lib/components/group-select/group-select.component.html +44 -0
  29. package/src/lib/components/group-select/group-select.component.scss +144 -0
  30. package/src/lib/components/group-select/group-select.component.spec.ts +23 -0
  31. package/src/lib/components/group-select/group-select.component.ts +145 -0
  32. package/src/lib/components/re-trigger/re-trigger.component.html +53 -0
  33. package/src/lib/components/re-trigger/re-trigger.component.scss +16 -0
  34. package/src/lib/components/re-trigger/re-trigger.component.spec.ts +23 -0
  35. package/src/lib/components/re-trigger/re-trigger.component.ts +96 -0
  36. package/src/lib/components/reactive-select/reactive-select.component.html +18 -0
  37. package/src/lib/components/reactive-select/reactive-select.component.scss +52 -0
  38. package/src/lib/components/reactive-select/reactive-select.component.spec.ts +23 -0
  39. package/src/lib/components/reactive-select/reactive-select.component.ts +104 -0
  40. package/src/lib/components/tango-manage-tickets/tango-manage-tickets.component.html +38 -0
  41. package/src/lib/components/tango-manage-tickets/tango-manage-tickets.component.scss +35 -0
  42. package/src/lib/components/tango-manage-tickets/tango-manage-tickets.component.spec.ts +23 -0
  43. package/src/lib/components/tango-manage-tickets/tango-manage-tickets.component.ts +116 -0
  44. package/src/lib/components/tickets/tickets.component.html +439 -0
  45. package/src/lib/components/tickets/tickets.component.scss +131 -0
  46. package/src/lib/components/tickets/tickets.component.spec.ts +23 -0
  47. package/src/lib/components/tickets/tickets.component.ts +748 -0
  48. package/src/lib/services/excel.service.ts +48 -0
  49. package/src/lib/services/ticket.service.spec.ts +16 -0
  50. package/src/lib/services/ticket.service.ts +175 -0
  51. package/src/lib/tango-manage-tickets-routing.module.ts +16 -0
  52. package/src/lib/tango-manage-tickets.module.ts +34 -0
  53. package/{public-api.d.ts → src/public-api.ts} +8 -2
  54. package/tsconfig.lib.json +14 -0
  55. package/tsconfig.lib.prod.json +10 -0
  56. package/tsconfig.spec.json +14 -0
  57. package/esm2022/lib/components/add-csm-modal/add-csm-modal.component.mjs +0 -98
  58. package/esm2022/lib/components/audit-log/audit-log.component.mjs +0 -11
  59. package/esm2022/lib/components/audit-metrics/audit-metrics.component.mjs +0 -298
  60. package/esm2022/lib/components/comment-model/comment-model.component.mjs +0 -58
  61. package/esm2022/lib/components/count/count.component.mjs +0 -89
  62. package/esm2022/lib/components/footfall-dic/footfall-dic.component.mjs +0 -983
  63. package/esm2022/lib/components/group-select/group-select.component.mjs +0 -155
  64. package/esm2022/lib/components/re-trigger/re-trigger.component.mjs +0 -96
  65. package/esm2022/lib/components/reactive-select/reactive-select.component.mjs +0 -108
  66. package/esm2022/lib/components/tango-manage-tickets/tango-manage-tickets.component.mjs +0 -127
  67. package/esm2022/lib/components/tickets/tickets.component.mjs +0 -793
  68. package/esm2022/lib/services/excel.service.mjs +0 -45
  69. package/esm2022/lib/services/ticket.service.mjs +0 -161
  70. package/esm2022/lib/tango-manage-tickets-routing.module.mjs +0 -24
  71. package/esm2022/lib/tango-manage-tickets.module.mjs +0 -54
  72. package/esm2022/public-api.mjs +0 -6
  73. package/esm2022/tango-app-ui-manage-tickets.mjs +0 -5
  74. package/fesm2022/tango-app-ui-manage-tickets.mjs +0 -3006
  75. package/fesm2022/tango-app-ui-manage-tickets.mjs.map +0 -1
  76. package/index.d.ts +0 -5
  77. package/lib/components/add-csm-modal/add-csm-modal.component.d.ts +0 -30
  78. package/lib/components/audit-log/audit-log.component.d.ts +0 -5
  79. package/lib/components/audit-metrics/audit-metrics.component.d.ts +0 -59
  80. package/lib/components/comment-model/comment-model.component.d.ts +0 -17
  81. package/lib/components/count/count.component.d.ts +0 -23
  82. package/lib/components/footfall-dic/footfall-dic.component.d.ts +0 -139
  83. package/lib/components/group-select/group-select.component.d.ts +0 -33
  84. package/lib/components/re-trigger/re-trigger.component.d.ts +0 -32
  85. package/lib/components/reactive-select/reactive-select.component.d.ts +0 -32
  86. package/lib/components/tango-manage-tickets/tango-manage-tickets.component.d.ts +0 -27
  87. package/lib/components/tickets/tickets.component.d.ts +0 -84
  88. package/lib/services/excel.service.d.ts +0 -10
  89. package/lib/services/ticket.service.d.ts +0 -49
  90. package/lib/tango-manage-tickets-routing.module.d.ts +0 -7
  91. package/lib/tango-manage-tickets.module.d.ts +0 -21
@@ -0,0 +1,1106 @@
1
+ import { ChangeDetectorRef, Component, OnDestroy, OnInit,ElementRef,ViewChild } from '@angular/core';
2
+ import { Subject, takeUntil } from 'rxjs';
3
+ import { GlobalStateService } from 'tango-app-ui-global';
4
+ import { TicketService } from '../../services/ticket.service';
5
+ import { ToastService } from 'tango-app-ui-shared';
6
+ import { ExcelService } from '../../services/excel.service';
7
+ import { FormBuilder, FormControl } from '@angular/forms';
8
+ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
9
+
10
+ @Component({
11
+ selector: "lib-footfall-dic",
12
+ templateUrl: "./footfall-dic.component.html",
13
+ styleUrl: "./footfall-dic.component.scss",
14
+ })
15
+ export class FootfallDicComponent implements OnInit,OnDestroy {
16
+ searchValue: any;
17
+ loading: boolean = false;
18
+ noData: boolean = false;
19
+ sortedColumn: any='';
20
+ sortDirection: any=1;
21
+ sortedColumn1: any='';
22
+ sortDirection1: any=1;
23
+ footfallView:boolean = true;
24
+ headerFilters: any;
25
+ footfallList_req: any;
26
+ form: any;
27
+ selectedRevopsType: FormControl;
28
+ revopsTypeArray: any = [
29
+ { value: "", label: "All" },
30
+ { value: "duplicateImages", label: "Duplicates" },
31
+ { value: "employee", label: "Employee/Staff" },
32
+ { value: "houseKeeping", label: "House Keeping" },
33
+ ];
34
+ type: any = [
35
+ { value: "open", label: "Open" },
36
+ { value: "closed", label: "Closed" },
37
+ ];
38
+ // selectedStatus: FormControl;
39
+
40
+ pendingArray: any = [
41
+ // { value: "", label: "All" },
42
+ { value: "pending", label: "Pending" },
43
+ { value: "approved", label: "Approved" },
44
+ { value: "rejected", label: "Rejected" },
45
+ ];
46
+ actionStatus: FormControl;
47
+ filterForm:any;
48
+
49
+ ticketData: any = {
50
+ ticketName: "Footfall Directory",
51
+ ticketId: "TE_INF_F5645G4534A24",
52
+ storeName: "LKST98 | RK Salai, Mylapore, Chennai, Tamil Nadu, India",
53
+ status: "Open",
54
+ date: "04 Sep 2023",
55
+ footfall: {
56
+ total: 100,
57
+ duplicates: 10,
58
+ employee: 2,
59
+ houseKeeping: 1,
60
+ },
61
+ duplicates: [
62
+ { url: "assets/img1.jpg" },
63
+ { url: "assets/img2.jpg" },
64
+ { url: "assets/img3.jpg" },
65
+ ],
66
+ };
67
+ selectedStores: any[] = [];
68
+ allSelected: boolean = false;
69
+ stores: any[] = [];
70
+ private readonly destroy$ = new Subject();
71
+
72
+ constructor(
73
+ private gs: GlobalStateService,
74
+ private ticketService: TicketService,
75
+ private cd: ChangeDetectorRef,
76
+ private toast: ToastService,private modalService: NgbModal,
77
+ private excelservice: ExcelService,private fb: FormBuilder,
78
+ ) {}
79
+
80
+ ngOnDestroy(): void {
81
+ this.destroy$.next(true);
82
+ this.destroy$.complete();
83
+ }
84
+ ngOnInit(): void {
85
+ this.footfallView = true;
86
+
87
+ this.selectedRevopsType = new FormControl('');
88
+ this.filterForm = this.fb.group({
89
+ selectedStatus: new FormControl('open'),
90
+ actionStatus: new FormControl('pending'),
91
+ ClusterList: new FormControl([]),
92
+ });
93
+
94
+ this.form = this.fb.group({
95
+ selectedRevopsType: this.selectedRevopsType,
96
+ });
97
+ this.gs.dataRangeValue?.pipe(takeUntil(this.destroy$))?.subscribe({
98
+ next: (data: any) => {
99
+ if (data) {
100
+ this.headerFilters = data;
101
+ this.footfallList_req = {
102
+ client: this.headerFilters.clients.toString(),
103
+ fromDate: this.headerFilters?.date?.startDate,
104
+ toDate: this.headerFilters?.date?.endDate,
105
+ };
106
+ this.getTicketSummary();
107
+ this.getTicketList();
108
+ }
109
+ },
110
+ });
111
+ }
112
+ getFootfallSummaryData: any;
113
+ getTicketSummary() {
114
+ this.ticketService
115
+ .getTicketSummaryApi(
116
+ this.footfallList_req.client,
117
+ this.footfallList_req.fromDate,
118
+ this.footfallList_req.toDate
119
+ )
120
+ .pipe(takeUntil(this.destroy$))
121
+ .subscribe({
122
+ next: (res: any) => {
123
+ if (res && res?.data && res?.data?.result) {
124
+ this.getFootfallSummaryData = res?.data?.result;
125
+ } else {
126
+ this.getFootfallSummaryData = [];
127
+ }
128
+ },
129
+ error: (err: any) => {
130
+ this.getFootfallSummaryData = [];
131
+ },
132
+ complete: () => {
133
+ this.getFootfallSummaryData.length === 0;
134
+ },
135
+ });
136
+ this.cd.detectChanges();
137
+ }
138
+ offset = 0;
139
+ limit = 10;
140
+ isExport:any = false;
141
+ footfallListData:any;
142
+ totalItems:any;
143
+ paginationSizes = [10, 20, 30];
144
+ getTicketList(){
145
+ this.loading = true;
146
+ this.searchValue = this.searchValue?.trim() || '';
147
+ this.offset = this.offset || 1;
148
+ this.limit = this.limit || 10;
149
+ this.isExport = false;
150
+ this.ticketService
151
+ .getTicketListApi(
152
+ this.footfallList_req.client,
153
+ this.footfallList_req.fromDate,
154
+ this.footfallList_req.toDate,
155
+ this.searchValue,this.limit,
156
+ this.offset,this.isExport,this.sortedColumn,this.sortDirection
157
+ )
158
+ .pipe(takeUntil(this.destroy$))
159
+ .subscribe({
160
+ next: (res: any) => {
161
+ if (res && res.code === 200) {
162
+ this.noData = false;
163
+ this.loading = false;
164
+ this.footfallListData = res?.data?.result;
165
+
166
+ this.totalItems = res?.data?.count;
167
+ if (this.totalItems < 10) { this.paginationSizes = [this.totalItems] } else { this.paginationSizes = [10, 20, 30] }
168
+ } else {
169
+ this.noData = true;
170
+ this.loading = false;
171
+ this.footfallListData =[];
172
+
173
+ }
174
+ this.cd.detectChanges();
175
+ },
176
+ error: (err: any) => {
177
+ this.noData = true;
178
+ this.loading = false;
179
+ },
180
+ complete: () => {
181
+ this.loading = false;
182
+ },
183
+ });
184
+ }
185
+
186
+ currentPage:any = 1;
187
+ pageSize:any = 10;
188
+ onPageChange(pageOffset: number) {
189
+ this.currentPage = Number(pageOffset);
190
+ this.offset = Number(pageOffset);
191
+ this.limit =10;
192
+ this.getTicketList();
193
+ }
194
+
195
+ onPageSizeChange(pageSize: number) {
196
+ this.pageSize = Number(pageSize);
197
+ this.limit = Number(pageSize);
198
+ this.currentPage = 1;
199
+ this.offset = 1;
200
+ this.getTicketList();
201
+ }
202
+
203
+ setpageSize() {
204
+ if (this.totalItems < 10) {
205
+ return this.totalItems;
206
+ } else {
207
+ return this.pageSize;
208
+ }
209
+ }
210
+ searchData() {
211
+ this.currentPage = 1;
212
+ this.offset = 1;
213
+ this.limit=10;
214
+ this.getTicketList();
215
+ }
216
+
217
+ exportXLSX() {
218
+ this.searchValue = this.searchValue?.trim() || '';
219
+ this.offset = 1;
220
+ this.limit = 10000;
221
+ this.isExport = true;
222
+ this.ticketService
223
+ .getTicketListExportApi(
224
+ this.footfallList_req.client,
225
+ this.footfallList_req.fromDate,
226
+ this.footfallList_req.toDate,
227
+ this.searchValue,this.limit,
228
+ this.offset,this.isExport,this.sortedColumn,this.sortDirection
229
+ )
230
+ .pipe(takeUntil(this.destroy$))
231
+ .subscribe({
232
+ next: (res: any) => {
233
+ this.excelservice.saveAsExcelFile(res, 'footfall directory ticket ')
234
+ },
235
+ error: (err: any) => {
236
+ this.toast.getErrorToast('Error exporting data:' + err.error ? err.error : err.message);
237
+ }
238
+ })
239
+ }
240
+
241
+ onSort(column: string) {
242
+ if (this.sortedColumn === column) {
243
+ this.sortDirection = this.sortDirection === 1 ? -1 : 1;
244
+ } else {
245
+ this.sortedColumn = column;
246
+ this.sortDirection = 1;
247
+ }
248
+ this.getTicketList();
249
+ }
250
+ storeCount:any;
251
+
252
+ searchStoresData(){
253
+ this.getStores();
254
+ }
255
+
256
+ StoresSearchValue:any='';
257
+ sortOrderStores:any;
258
+
259
+ sortValue(column: string) {
260
+ if (this.sortedColumn1 === column) {
261
+ this.sortedColumn1 = this.sortDirection1 === 1 ? -1 : 1;
262
+ } else {
263
+ this.sortedColumn1 = column;
264
+ this.sortDirection1 = 1;
265
+ }
266
+ this.getStores();
267
+ }
268
+ getStores(){
269
+ this.ticketService.getTaggedStoresApi(
270
+ this.footfallList_req.client,
271
+ this.footfallList_req.fromDate,
272
+ this.footfallList_req.toDate,
273
+ this.StoresSearchValue,
274
+ this.groups,
275
+ this.sortDirection1,
276
+ ).pipe(takeUntil(this.destroy$))
277
+ .subscribe({
278
+ next: (res: any) => {
279
+ if (res && res.code === 200) {
280
+ if(res?.data?.result?.length){
281
+ this.stores = res?.data?.result;
282
+ this.storeCount = res.data?.count || 0;
283
+ } else {
284
+ this.stores = [];
285
+ this.storeCount =0;
286
+ }
287
+ } else{
288
+ this.stores = [];
289
+ this.storeCount =0;
290
+ }
291
+ this.cd.detectChanges();
292
+ },
293
+ error: (err: any) => {
294
+ this.stores =[];
295
+ this.storeCount =0;
296
+ },
297
+ complete: () => {},
298
+ });
299
+ }
300
+ getTaggedStoresData: any;
301
+
302
+
303
+ typeChange(event: any) {
304
+ this.filterForm.get('selectedStatus')?.setValue(event || null);
305
+ }
306
+
307
+ pendingChange(event: any) {
308
+ this.filterForm.get('actionStatus')?.setValue(event || null);
309
+ }
310
+
311
+ RevopsTypeChange(event: any) {
312
+ const selectedType = event ?? '';
313
+ this.footfalloffset =1;
314
+ if(selectedType === '') {
315
+ this.footfalllimit = 1;
316
+ this.footfallcurrentPage =1;
317
+ } else {
318
+ this.footfalllimit = 10;
319
+ }
320
+ this.form.get('selectedRevopsType')?.setValue(selectedType);
321
+ this.allSelectValue =false;
322
+ // Clear selected lists
323
+ this.selectedEmployeeImagesList = [];
324
+ this.selectedHousekeepingImagesList = [];
325
+ this.selectedDuplicateImagesList = [];
326
+ this.cd.detectChanges();
327
+ // Reset counts
328
+ this.employeeACCount = '';
329
+ this.houseKeepingACCount = '';
330
+ this.duplicateACCount = '';
331
+ // console.log(this.footfalllimit)
332
+ this.dataStoreView();
333
+ }
334
+
335
+
336
+
337
+ footfalloffset=1;
338
+ footfalllimit=1;
339
+ footfallTicketsData:any=[];
340
+ storeIdValue:any;
341
+
342
+
343
+ dataReset(){
344
+ this.selectedStores = [];
345
+ this.allSelected = false;
346
+ this.StoresSearchValue ='';
347
+ this.getStores();
348
+ this.form.get('selectedRevopsType')?.setValue('');
349
+ this.filterForm.get('selectedStatus')?.setValue('open');
350
+ this.filterForm.get('actionStatus')?.setValue('pending');
351
+ this.dataStoreView();
352
+ }
353
+ dataApply() {
354
+ this.footfalloffset =1;
355
+ if(this.selectedRevopsType.value === '') {
356
+ this.footfallcurrentPage =1;
357
+ this.footfalllimit = 1;
358
+ } else{
359
+ this.footfalllimit = 10;
360
+ }
361
+ this.allSelectValue =false
362
+ this.dataStoreView();
363
+ }
364
+ imageUrl:any;
365
+ dataIndexId:any;
366
+ dateString:any;
367
+ footfallNoData = false;
368
+ footfallLoading = true;
369
+ private lastSelectedTicket: any = null;
370
+
371
+ hasInitialStoreSynced = false;
372
+
373
+ addStoreIfNotExists(store: any) {
374
+ if (this.hasInitialStoreSynced) return;
375
+
376
+ const storeId = store?.storeId;
377
+ if (storeId && !this.selectedStores.includes(storeId)) {
378
+ this.selectedStores.push(storeId);
379
+ }
380
+
381
+ this.hasInitialStoreSynced = true;
382
+ this.allSelected = this.selectedStores.length === this.stores.length;
383
+ }
384
+ selecteValues:any;
385
+ selectedStatus:any;
386
+ dataStoreView(data?: any) {
387
+ // console.log(data)
388
+ this.getAllGroups();
389
+ this.footfallTicketsData = [];
390
+ this.footfallNoData = false;
391
+ this.footfallLoading = true;
392
+ const ticket = data?._source ? data : this.lastSelectedTicket;
393
+
394
+ if (!ticket || !ticket._source) {
395
+ this.footfallLoading = false;
396
+ this.footfallNoData = true;
397
+ this.toast.getErrorToast('No ticket data available');
398
+ return;
399
+ }
400
+
401
+ this.lastSelectedTicket = ticket;
402
+ this.addStoreIfNotExists(ticket._source);
403
+ this.dataIndexId = ticket._id || '';
404
+ this.dateString = ticket._source.dateString || '';
405
+ this.imageUrl = this.ticketService?.footfallCDN;
406
+ this.storeIdValue = this.selectedStores;
407
+ const revopsType = this.form.get('selectedRevopsType')?.value;
408
+ const selectedStatus = this.selectedStatus = this.filterForm.get('selectedStatus')?.value;
409
+ const actionStatus = this.selecteValues = this.filterForm.get('actionStatus')?.value;
410
+
411
+ const storeId = this.storeIdValue;
412
+ const fromDate = this.footfallList_req.fromDate;
413
+ const toDate = this.footfallList_req.toDate;
414
+ const offset = this.footfalloffset;
415
+ const limit = revopsType ==='' ? this.footfalllimit :this.footfalllimit = 10;
416
+
417
+ this.ticketService
418
+ .getTicketsApi(storeId, fromDate, toDate, revopsType, selectedStatus, actionStatus, offset, limit)
419
+ .pipe(takeUntil(this.destroy$))
420
+ .subscribe({
421
+ next: (res: any) => {
422
+ if(res && res.code ===200){
423
+ if (res?.data?.result?.length === 0) {
424
+ this.footfallTicketsData = [];
425
+ this.footfallView = true;
426
+ this.footfallNoData = true;
427
+ this.footfallLoading = false;
428
+ this.toast.getErrorToast('No data found for the selected filters');
429
+ } else {
430
+ this.footfallTicketsData = res?.data?.result ?? [];
431
+ this.totalItemsFootfall = res?.data?.count;
432
+ if (this.footfalllimit === 1) {
433
+ this.paginationSizes = [1];
434
+ this.pageSizeFootfall = 1;
435
+ } else {
436
+ const limit = this.totalItemsFootfall < 10 ? this.totalItemsFootfall : 10;
437
+ this.paginationSizes = [limit];
438
+ this.pageSizeFootfall = limit;
439
+ }
440
+ // console.log(this.footfalllimit)
441
+ // this.footfalllimit ===1 ? this.paginationSizes : [this.totalItemsFootfall];
442
+ // this.paginationSizes = this.totalItemsFootfall < 1
443
+ // ? [this.totalItemsFootfall]
444
+ // : [1];
445
+
446
+ this.footfallView = false;
447
+ this.footfallNoData = false;
448
+ this.footfallLoading = false;
449
+ }
450
+ } else {
451
+ this.footfallTicketsData = [];
452
+ this.footfallView = false;
453
+ this.footfallNoData = true;
454
+ this.footfallLoading = false;
455
+ }
456
+ },
457
+ error: () => {
458
+ this.footfallTicketsData = [];
459
+ this.footfallView = false;
460
+ this.footfallNoData = true;
461
+ this.footfallLoading = false;
462
+ },
463
+ complete: () => {
464
+ this.cd.detectChanges();
465
+ },
466
+ });
467
+ }
468
+
469
+ isCollapsed = false;
470
+
471
+ toggleSidebar() {
472
+ this.isCollapsed = !this.isCollapsed;
473
+ }
474
+ matchedType: any;
475
+
476
+ matchedArray: any = [{ value: "all", label: "matched: All" }];
477
+ onFilterApply() {
478
+ this.getStores();
479
+ if(this.selectedRevopsType.value === '')
480
+ this.footfalllimit = 1;
481
+ else
482
+ this.footfalllimit = 10;
483
+ this.dataStoreView();
484
+
485
+ }
486
+ pageSizeFootfall:any = 1;
487
+ footfallcurrentPage:any = 1;
488
+ onFootfallPageChange(pageOffset: number) {
489
+ this.footfallcurrentPage = Number(pageOffset);
490
+ this.footfalloffset = Number(pageOffset);
491
+ this.footfalllimit =1;
492
+ this.cancel();
493
+ this.dataStoreView();
494
+ }
495
+
496
+ onFootfallPageSizeChange(pageSize: number) {
497
+ this.footfalllimit = Number(pageSize);
498
+ this.pageSizeFootfall = Number(pageSize);
499
+ this.footfallcurrentPage = 1;
500
+ this.footfalloffset = 1;
501
+ this.dataStoreView();
502
+ }
503
+ totalItemsFootfall:any;
504
+ setFootfallpageSize() {
505
+ if(this.footfalllimit === 1){
506
+ if (this.totalItemsFootfall < 1) {
507
+ return this.totalItemsFootfall;
508
+ } else {
509
+ return this.pageSizeFootfall;
510
+ }
511
+ } else {
512
+ if (this.totalItemsFootfall < 10) {
513
+ return this.totalItemsFootfall;
514
+ } else {
515
+ return this.pageSizeFootfall;
516
+ }
517
+ }
518
+ }
519
+
520
+
521
+
522
+ footfallMulticurrentPage:any = 1;
523
+ onFootfallMultiPageChange(pageOffset: number) {
524
+ this.footfallMulticurrentPage = Number(pageOffset);
525
+ this.footfalloffset = Number(pageOffset);
526
+ this.footfalllimit =10;
527
+ this.allSelectValue =false;
528
+ this.cancel();
529
+ this.dataStoreView();
530
+ }
531
+
532
+ onFootfallMultiPageSizeChange(pageSize: number) {
533
+ this.footfalllimit = Number(pageSize);
534
+ this.pageSizeFootfall = Number(pageSize);
535
+ this.footfallMulticurrentPage = 1;
536
+ this.footfalloffset = 1;
537
+
538
+ this.dataStoreView();
539
+ }
540
+ toggleStoreSelection(store: any) {
541
+ const storeId = store?.storeId;
542
+ if (!storeId) return;
543
+
544
+ const index = this.selectedStores.indexOf(storeId);
545
+
546
+ if (index > -1) {
547
+ this.selectedStores.splice(index, 1);
548
+ } else {
549
+ this.selectedStores.push(storeId);
550
+ }
551
+
552
+ this.allSelected = this.selectedStores.length === this.stores.length;
553
+ }
554
+
555
+
556
+ toggleSelectAll() {
557
+ const visibleStoreIds = this.filteredStores.map((s) => s.storeId);
558
+
559
+ if (this.allSelected) {
560
+ // Remove only the visible ones
561
+ this.selectedStores = this.selectedStores.filter(
562
+ id => !visibleStoreIds.includes(id)
563
+ );
564
+ } else {
565
+ // Add only those that are not already selected
566
+ const newIds = visibleStoreIds.filter(id => !this.selectedStores.includes(id)
567
+ );
568
+ this.selectedStores = [...this.selectedStores, ...newIds];
569
+ }
570
+
571
+ this.allSelected = this.selectedStores.length === this.stores.length;
572
+ }
573
+
574
+
575
+ isSelected(store: any): boolean {
576
+ return this.selectedStores.includes(store.storeId);
577
+ }
578
+
579
+
580
+ imgtoggleSelectAll() {
581
+ this.allSelected = !this.allSelected;
582
+ this.ticketData.duplicates.forEach((img: any) => {
583
+ img.selected = this.allSelected;
584
+ });
585
+ }
586
+
587
+ selectedImagesList: any[] = [];
588
+
589
+ selectedDuplicateImagesList: any[] = [];
590
+ selectedHousekeepingImagesList: any[] = [];
591
+ selectedEmployeeImagesList: any[] = [];
592
+ houseKeepingACCount:any;
593
+ employeeACCount:any;
594
+ duplicateACCount:any;
595
+
596
+ cloneWithoutSelected(obj: any) {
597
+ const { ...rest } = obj;
598
+ return rest;
599
+ }
600
+
601
+
602
+ allSelectValue = false;
603
+
604
+ cloneWithoutSelected1(data: any): any {
605
+ const { __parent, ...rest } = data;
606
+ return { ...rest };
607
+ }
608
+
609
+ onImageCheckboxChange1(data: any, category: string, parentOriginal?: any) {
610
+ let selectedList: any;
611
+
612
+ if (category === 'duplicate') {
613
+ parentOriginal = parentOriginal || data.__parent;
614
+
615
+ const existingOriginal = this.selectedDuplicateImagesList.find(
616
+ (item: any) => item.tempId === parentOriginal?.tempId
617
+ );
618
+
619
+ if (data.selected) {
620
+ if (existingOriginal) {
621
+ const alreadyExists = existingOriginal.data?.some(
622
+ (dup: any) => dup.tempId === data.tempId
623
+ );
624
+ if (!alreadyExists) {
625
+ existingOriginal.data.push(this.cloneWithoutSelected1(data));
626
+ }
627
+ } else {
628
+ this.selectedDuplicateImagesList.push({
629
+ tempId: parentOriginal?.tempId,
630
+ filePath: parentOriginal?.filePath,
631
+ entryTime: parentOriginal?.entryTime,
632
+ exitTime: parentOriginal?.exitTime,
633
+ timeRange: parentOriginal?.timeRange,
634
+ data: [this.cloneWithoutSelected1(data)],
635
+ });
636
+ }
637
+ } else {
638
+ if (existingOriginal) {
639
+ existingOriginal.data = existingOriginal.data.filter(
640
+ (d: any) => d.tempId !== data.tempId
641
+ );
642
+
643
+ if (existingOriginal.data.length === 0) {
644
+ this.selectedDuplicateImagesList = this.selectedDuplicateImagesList.filter(
645
+ (o: any) => o.tempId !== parentOriginal?.tempId
646
+ );
647
+ }
648
+ }
649
+ }
650
+
651
+ this.duplicateACCount = this.selectedDuplicateImagesList.reduce(
652
+ (sum: number, orig: any) => sum + orig.data.length,
653
+ 0
654
+ );
655
+ }
656
+
657
+ if (category === 'employee') {
658
+ selectedList = this.selectedEmployeeImagesList;
659
+ } else if (category === 'houseKeeping') {
660
+ selectedList = this.selectedHousekeepingImagesList;
661
+ }
662
+
663
+ if (category !== 'duplicate') {
664
+ if (data.selected) {
665
+ const alreadyExists = selectedList.some((item: any) => item.tempId === data.tempId);
666
+ if (!alreadyExists) {
667
+ selectedList.push(data);
668
+ }
669
+ } else {
670
+ const index = selectedList.findIndex((item: any) => item.tempId === data.tempId);
671
+ if (index !== -1) {
672
+ selectedList.splice(index, 1);
673
+ }
674
+ }
675
+
676
+ this.employeeACCount = this.selectedEmployeeImagesList.length;
677
+ this.houseKeepingACCount = this.selectedHousekeepingImagesList.length;
678
+ }
679
+
680
+ // 🔒 Disable other checkboxes if one type is selected
681
+ const totalSelected =
682
+ this.duplicateACCount + this.employeeACCount + this.houseKeepingACCount;
683
+
684
+ if (totalSelected > 0) {
685
+ this.checkedValue = false;
686
+ } else {
687
+ this.checkedValue = true;
688
+ }
689
+
690
+ this.cd.detectChanges(); // To update the template
691
+ this.allSelectValue = this.areAllCheckboxesSelected();
692
+
693
+ // console.log('✅ Counts:', {
694
+ // duplicateACCount: this.duplicateACCount,
695
+ // employeeACCount: this.employeeACCount,
696
+ // houseKeepingACCount: this.houseKeepingACCount,
697
+ // checkedValue: this.checkedValue,
698
+ // });
699
+ }
700
+
701
+
702
+
703
+ selectAllValue() {
704
+ this.allSelectValue = !this.allSelectValue;
705
+ this.checkedValue = !this.allSelectValue;
706
+
707
+ this.selectedEmployeeImagesList = [];
708
+ this.selectedHousekeepingImagesList = [];
709
+ this.selectedDuplicateImagesList = [];
710
+
711
+ for (const ticket of this.footfallTicketsData) {
712
+ const source = ticket._source;
713
+
714
+ // ✅ Employee
715
+ if (Array.isArray(source.employee)) {
716
+ source.employee.forEach((img: any) => {
717
+ img.selected = this.allSelectValue;
718
+ if (this.allSelectValue && !this.selectedEmployeeImagesList.some(e => e.tempId === img.tempId)) {
719
+ this.selectedEmployeeImagesList.push(img);
720
+ }
721
+ });
722
+ }
723
+
724
+ // ✅ Housekeeping
725
+ if (Array.isArray(source.houseKeeping)) {
726
+ source.houseKeeping.forEach((emp: any) => {
727
+ emp.selected = this.allSelectValue;
728
+ if (this.allSelectValue && !this.selectedHousekeepingImagesList.some(e => e.tempId === emp.tempId)) {
729
+ this.selectedHousekeepingImagesList.push(emp);
730
+ }
731
+ });
732
+ }
733
+
734
+ // ✅ Duplicate
735
+ if (Array.isArray(source.duplicateImages)) {
736
+ source.duplicateImages.forEach((original: any) => {
737
+ if (Array.isArray(original.data)) {
738
+ original.data.forEach((dup: any) => {
739
+ dup.selected = this.allSelectValue;
740
+ dup.__parent = original; // ✅ Needed for uncheck
741
+ });
742
+
743
+ if (this.allSelectValue && original.data.length > 0) {
744
+ const existing = this.selectedDuplicateImagesList.find(
745
+ (o: any) => o.tempId === original.tempId
746
+ );
747
+
748
+ if (!existing) {
749
+ this.selectedDuplicateImagesList.push({
750
+ tempId: original.tempId,
751
+ filePath: original.filePath,
752
+ entryTime: original.entryTime,
753
+ exitTime: original.exitTime,
754
+ timeRange: original.timeRange,
755
+ data: original.data.map((d: any) => this.cloneWithoutSelected1(d)),
756
+ });
757
+ }
758
+ }
759
+ }
760
+ });
761
+ }
762
+ }
763
+ // console.log('✅ All selected:', this.selectedDuplicateImagesList);
764
+ this.houseKeepingACCount = this.selectedHousekeepingImagesList.length;
765
+ this.employeeACCount = this.selectedEmployeeImagesList.length;
766
+ this.duplicateACCount = this.selectedDuplicateImagesList.reduce(
767
+ (sum: number, orig: any) => sum + orig.data.length,
768
+ 0
769
+ );
770
+ }
771
+
772
+
773
+ areAllCheckboxesSelected(): boolean {
774
+ for (const ticket of this.footfallTicketsData) {
775
+ const source = ticket._source;
776
+
777
+ if (source.employee?.some((img: any) => !img.selected)) return false;
778
+ if (source.houseKeeping?.some((img: any) => !img.selected)) return false;
779
+ if (source.duplicateImages?.some((original: any) =>
780
+ original.data?.some((dup: any) => !dup.selected))) return false;
781
+ }
782
+ return true;
783
+ }
784
+ checkedValue =true;
785
+
786
+
787
+
788
+
789
+
790
+
791
+
792
+
793
+ onImageCheckboxChange(data: any, category: string, parentOriginal?: any) {
794
+ let selectedList;
795
+
796
+ switch (category) {
797
+ case 'duplicate':
798
+ // Ensure selectedDuplicateImagesList is an array of ORIGINALS with selected children
799
+ const existingOriginal = this.selectedDuplicateImagesList.find(
800
+ (item: any) => item.tempId === parentOriginal?.tempId
801
+ );
802
+
803
+ if (data.selected) {
804
+ if (existingOriginal) {
805
+ const alreadyExists = existingOriginal.data?.some(
806
+ (dup: any) => dup.tempId === data.tempId
807
+ );
808
+ if (!alreadyExists) {
809
+ existingOriginal.data.push(this.cloneWithoutSelected(data)); // ✅ no 'selected' key
810
+ }
811
+ } else {
812
+ this.selectedDuplicateImagesList.push({
813
+ tempId: parentOriginal?.tempId,
814
+ filePath: parentOriginal?.filePath,
815
+ entryTime: parentOriginal?.entryTime,
816
+ exitTime: parentOriginal?.exitTime,
817
+ timeRange: parentOriginal?.timeRange,
818
+ data: [this.cloneWithoutSelected(data)], // ✅
819
+ });
820
+ }
821
+ } else {
822
+ // Remove from selected duplicates
823
+ if (existingOriginal) {
824
+ existingOriginal.data = existingOriginal.data.filter(
825
+ (d: any) => d.tempId !== data.tempId
826
+ );
827
+
828
+ // Remove the whole original if no duplicates are left
829
+ if (existingOriginal.data.length === 0) {
830
+ this.selectedDuplicateImagesList = this.selectedDuplicateImagesList.filter(
831
+ (o: any) => o.tempId !== parentOriginal?.tempId
832
+ );
833
+ }
834
+ }
835
+ }
836
+
837
+ // Count only from selected duplicates
838
+ this.duplicateACCount = this.selectedDuplicateImagesList.reduce(
839
+ (sum: number, orig: any) => sum + orig.data.length,
840
+ 0
841
+ );
842
+ return;
843
+
844
+ case 'houseKeeping':
845
+ selectedList = this.selectedHousekeepingImagesList;
846
+ break;
847
+
848
+ case 'employee':
849
+ selectedList = this.selectedEmployeeImagesList;
850
+ break;
851
+
852
+ default:
853
+ return;
854
+ }
855
+
856
+ // Unchanged logic for employee and housekeeping
857
+ selectedList = selectedList || [];
858
+ if (data.selected) {
859
+ const alreadyExists = Array.isArray(selectedList) && selectedList.some((item: any) => item.tempId === data.tempId);
860
+ if (!alreadyExists) {
861
+ selectedList.push(data);
862
+ }
863
+ } else {
864
+ const updated = Array.isArray(selectedList) ? selectedList.filter((item: any) => item.tempId !== data.tempId) : [];
865
+
866
+ if (category === 'houseKeeping') {
867
+ this.selectedHousekeepingImagesList = updated;
868
+ } else if (category === 'employee') {
869
+ this.selectedEmployeeImagesList = updated;
870
+ }
871
+ }
872
+ this.houseKeepingACCount = this.selectedHousekeepingImagesList?.length|| 0
873
+ this.employeeACCount = this.selectedEmployeeImagesList.length || 0
874
+ }
875
+
876
+
877
+ commentText:any;
878
+ submitValue(status: string = 'approved', category: string = 'duplicate') {
879
+ // Step 1: Validate based on current category
880
+ let selectedList;
881
+ switch (category) {
882
+ case 'duplicate':
883
+ selectedList = this.selectedDuplicateImagesList;
884
+ break;
885
+ case 'houseKeeping':
886
+ selectedList = this.selectedHousekeepingImagesList;
887
+ break;
888
+ case 'employee':
889
+ selectedList = this.selectedEmployeeImagesList;
890
+ break;
891
+ default:
892
+ return;
893
+ }
894
+
895
+ if (selectedList.length === 0) {
896
+ this.toast.getErrorToast('Please select at least one image');
897
+ return;
898
+ }
899
+
900
+ // Replace selected → isChecked before sending
901
+ const transformedList = selectedList.map(item => {
902
+ const { selected, ...rest } = item;
903
+ return { ...rest, isChecked: true };
904
+ });
905
+
906
+ // Step 2: Build full payload
907
+ const payload: any[] = [];
908
+
909
+ for (const ticket of this.footfallTicketsData) {
910
+ const source = ticket._source;
911
+
912
+ const singlePayload: any = {
913
+ _id: ticket._id,
914
+ comments: this.commentText || '',
915
+ dateString: source.dateString || this.dateString,
916
+
917
+ employeeStatus: category === 'employee' ? status : source.employeeStatus,
918
+ houseKeepingStatus: category === 'houseKeeping' ? status : source.houseKeepingStatus,
919
+ duplicateStatus: category === 'duplicate' ? status : source.duplicateStatus,
920
+ };
921
+
922
+ if (category === 'employee') {
923
+ singlePayload.employee = transformedList;
924
+ singlePayload.employeeACCount = this.employeeACCount ? this.employeeACCount : 0;
925
+ }
926
+
927
+ if (category === 'houseKeeping') {
928
+ singlePayload.houseKeeping = transformedList;
929
+ singlePayload.houseKeepingACCount = this.houseKeepingACCount ? this.houseKeepingACCount : 0;
930
+ }
931
+
932
+ if (category === 'duplicate') {
933
+ singlePayload.duplicateImages = transformedList;
934
+ singlePayload.duplicateACCount = this.duplicateACCount ? this.duplicateACCount : 0;
935
+ }
936
+
937
+ payload.push(singlePayload);
938
+ }
939
+
940
+ // console.log('Payload to submit:', payload);
941
+ // return
942
+ // Step 3: Set status based on current category
943
+ switch (category) {
944
+ case 'duplicate':
945
+ payload.forEach(item => item.duplicateStatus = status);
946
+ break;
947
+ case 'houseKeeping':
948
+ payload.forEach(item => item.houseKeepingStatus = status);
949
+ break;
950
+ case 'employee':
951
+ payload.forEach(item => item.employeeStatus = status);
952
+ break;
953
+ }
954
+
955
+ // Step 4: Submit the payload
956
+ this.ticketService.getUpdateStatusApi({data:payload})
957
+ .pipe(takeUntil(this.destroy$))
958
+ .subscribe({
959
+ next: (res: any) => {
960
+ if (res && res.code === 200) {
961
+ this.toast.getSuccessToast(res?.message || 'Ticket updated successfully');
962
+ // this.selectedStores =[];
963
+ // this.allSelected = false;
964
+ // this.allSelectValue =false;
965
+ this.footfalloffset =1;
966
+ this.dataStoreView();
967
+ this.cancel();
968
+ } else {
969
+ this.toast.getErrorToast('Failed to update ticket');
970
+ }
971
+ },
972
+ error: (err: any) => {
973
+ const msg = err.error.error || err.error || err?.error?.message || err.message || 'Unknown error';
974
+ this.toast.getErrorToast('Error updating ticket: ' + msg);
975
+
976
+ this.allSelected = false;
977
+ this.allSelectValue =false;
978
+ }
979
+ });
980
+ }
981
+ searchTerm:any = '';
982
+ get filteredStores() {
983
+ if (!this.searchTerm?.trim()) return this.stores;
984
+
985
+ const term = this.searchTerm.toLowerCase();
986
+ return this.stores.filter(store =>
987
+ store?.storeName?.toLowerCase().includes(term)
988
+ );
989
+ }
990
+ onImageError(event: any): void {
991
+ event.target.src = 'assets/images/fallback-image.png'; // or any default image path
992
+ }
993
+ backToNavigation(){
994
+ this.selectedStores = [];
995
+ this.allSelected = false;
996
+ this.allSelectValue =false;
997
+ this.hasInitialStoreSynced = false;
998
+ this.footfallView =true;
999
+ this.cancel();
1000
+ this.ClusterList =[];
1001
+ // this.groups =[];
1002
+ // this.filterForm.get('ClusterList')?.setValue('')
1003
+ this.form.get('selectedRevopsType')?.setValue('');
1004
+ this.filterForm.get('selectedStatus')?.setValue('open');
1005
+ this.filterForm.get('actionStatus')?.setValue('pending');
1006
+ this.getTicketSummary();
1007
+ this.getTicketList();
1008
+ }
1009
+ @ViewChild('zoomPopup') zoomPopup: ElementRef;
1010
+ popupvalue:any;
1011
+ popupType:any;
1012
+ popupOpen(type:any,value:any){
1013
+ const modalRef = this.modalService.open(this.zoomPopup, { centered: true, size: 'md',
1014
+ backdrop: 'static', // Prevent closing on outside click
1015
+ keyboard: false // Prevent closing on ESC key
1016
+ });
1017
+ this.popupType = type;
1018
+ if(value ==='duplicateImages'){
1019
+ this.popupvalue = 'duplicate';
1020
+ } else{
1021
+ this.popupvalue = value;
1022
+ }
1023
+ }
1024
+ cancel() {
1025
+ // this.allSelected = false;
1026
+ // this.allSelectValue = false;
1027
+ if(this.selectedRevopsType?.value !=='')
1028
+ this.allSelectValue = false;
1029
+ // Clear all selected flags from the data
1030
+ for (const ticket of this.footfallTicketsData) {
1031
+ const source = ticket._source;
1032
+
1033
+ source.employee?.forEach((img: any) => (img.selected = false));
1034
+ source.houseKeeping?.forEach((img: any) => (img.selected = false));
1035
+ source.duplicateImages?.forEach((original: any) => {
1036
+ original.data?.forEach((dup: any) => (dup.selected = false));
1037
+ });
1038
+ }
1039
+ this.clear();
1040
+
1041
+ // this.checkedValue = true;
1042
+ }
1043
+ clear(){
1044
+ this.modalService.dismissAll();
1045
+ this.selectedEmployeeImagesList = [];
1046
+ this.selectedHousekeepingImagesList = [];
1047
+ this.selectedDuplicateImagesList = [];
1048
+
1049
+ // Reset counts
1050
+ this.employeeACCount = '';
1051
+ this.houseKeepingACCount = '';
1052
+ this.duplicateACCount = '';
1053
+ }
1054
+ ClusterList:any=[];
1055
+ getAllGroups() {
1056
+ this.ClusterList =[];
1057
+ // this.groups =[];
1058
+
1059
+ this.ticketService.getclusters({ clientId: this.headerFilters.client, group: [], city: [] }).subscribe({
1060
+ next: (res: any) => {
1061
+ if (res && res.code == 200) {
1062
+ this.ClusterList = res?.data?.groupData;
1063
+ this.getStores();
1064
+ } else {
1065
+ this.ClusterList = [];
1066
+ }
1067
+ }
1068
+ })
1069
+ }
1070
+ groups: any = [];
1071
+ ongroupSelect(event: any) {
1072
+ this.selectedStores =[];
1073
+ this.allSelected = false;
1074
+ this.allSelectValue =false;
1075
+ this.filterForm.get('ClusterList')?.setValue(event)
1076
+ this.groups = event.map((el: any) => el.groupName)
1077
+
1078
+ }
1079
+ // isSubmitDisabled(): boolean {
1080
+ // switch (this.selectedRevopsType?.value) {
1081
+ // case 'employee':
1082
+ // return this.employeeACCount === 0;
1083
+ // case 'houseKeeping':
1084
+ // return this.houseKeepingACCount === 0;
1085
+ // case 'duplicate':
1086
+ // return this.duplicateACCount === 0;
1087
+ // default:
1088
+ // return true;
1089
+ // }
1090
+ // }
1091
+ getFormattedEntryTime(entryTime: string): string {
1092
+ if (!entryTime) return '-';
1093
+ const [hours, minutes, seconds] = entryTime.split(':').map(Number);
1094
+ const date = new Date();
1095
+ date.setHours(hours, minutes, seconds);
1096
+ return date.toLocaleTimeString('en-US', {
1097
+ hour: '2-digit',
1098
+ minute: '2-digit',
1099
+ // second: '2-digit',
1100
+ hour12: true
1101
+ });
1102
+ }
1103
+ showSelectAllBox() {
1104
+ this.filterForm.get('actionStatus')?.setValue('pending');
1105
+ }
1106
+ }