@senior-gestao-relacionamento/angular-components 2.0.0-master-d6f488bf → 2.0.0-master-eb758aaf

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 (39) hide show
  1. package/esm2022/lib/components/schedule/entities/participant-lookup.interface.mjs +2 -0
  2. package/esm2022/lib/components/schedule/entities/schedule-type.interface.mjs +2 -0
  3. package/esm2022/lib/components/schedule/entities/schedule.interface.mjs +2 -0
  4. package/esm2022/lib/components/schedule/enums/schedule.enums.mjs +65 -0
  5. package/esm2022/lib/components/schedule/helpers/schedule-date.helpers.mjs +109 -0
  6. package/esm2022/lib/components/schedule/helpers/schedule-display.helpers.mjs +108 -0
  7. package/esm2022/lib/components/schedule/schedule-detail/schedule-detail.component.mjs +79 -0
  8. package/esm2022/lib/components/schedule/schedule-form/schedule-form.component.mjs +731 -0
  9. package/esm2022/lib/components/schedule/services/schedule-type.service.mjs +23 -10
  10. package/esm2022/lib/components/schedule/services/schedule.service.mjs +30 -33
  11. package/esm2022/public-api.mjs +7 -5
  12. package/fesm2022/senior-gestao-relacionamento-angular-components.mjs +797 -739
  13. package/fesm2022/senior-gestao-relacionamento-angular-components.mjs.map +1 -1
  14. package/lib/components/schedule/entities/participant-lookup.interface.d.ts +38 -0
  15. package/lib/components/schedule/entities/schedule-type.interface.d.ts +10 -0
  16. package/lib/components/schedule/{models → entities}/schedule.interface.d.ts +19 -15
  17. package/lib/components/schedule/{models → enums}/schedule.enums.d.ts +5 -0
  18. package/lib/components/schedule/helpers/schedule-date.helpers.d.ts +9 -0
  19. package/lib/components/schedule/helpers/schedule-display.helpers.d.ts +17 -0
  20. package/lib/components/schedule/schedule-detail/schedule-detail.component.d.ts +43 -0
  21. package/lib/components/schedule/schedule-form/schedule-form.component.d.ts +139 -0
  22. package/lib/components/schedule/services/schedule-type.service.d.ts +14 -6
  23. package/lib/components/schedule/services/schedule.service.d.ts +21 -51
  24. package/package.json +3 -3
  25. package/public-api.d.ts +8 -5
  26. package/esm2022/lib/components/schedule/components/index.mjs +0 -3
  27. package/esm2022/lib/components/schedule/components/schedule-detail.component.mjs +0 -204
  28. package/esm2022/lib/components/schedule/components/schedule-form.component.mjs +0 -780
  29. package/esm2022/lib/components/schedule/index.mjs +0 -6
  30. package/esm2022/lib/components/schedule/models/index.mjs +0 -2
  31. package/esm2022/lib/components/schedule/models/schedule.enums.mjs +0 -59
  32. package/esm2022/lib/components/schedule/models/schedule.interface.mjs +0 -2
  33. package/esm2022/lib/components/schedule/services/index.mjs +0 -3
  34. package/lib/components/schedule/components/index.d.ts +0 -2
  35. package/lib/components/schedule/components/schedule-detail.component.d.ts +0 -53
  36. package/lib/components/schedule/components/schedule-form.component.d.ts +0 -98
  37. package/lib/components/schedule/index.d.ts +0 -5
  38. package/lib/components/schedule/models/index.d.ts +0 -2
  39. package/lib/components/schedule/services/index.d.ts +0 -2
@@ -1,39 +1,37 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { NgModule, Injectable, EventEmitter, Component, Input, Output, ViewChild } from '@angular/core';
3
- import * as i3 from '@angular/common';
3
+ import * as i6 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
- import { BehaviorSubject, of, tap, Subject, debounceTime } from 'rxjs';
5
+ import { BehaviorSubject, of, tap, Subject, debounceTime, switchMap } from 'rxjs';
6
6
  import * as i1 from '@angular/common/http';
7
+ import { HttpParams } from '@angular/common/http';
7
8
  import * as i1$1 from '@angular/forms';
8
9
  import { Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
9
- import * as i6 from 'primeng/drawer';
10
- import { DrawerModule } from 'primeng/drawer';
11
- import * as i8 from 'primeng/button';
10
+ import * as i7 from 'primeng/button';
12
11
  import { ButtonModule } from 'primeng/button';
13
- import * as i9 from 'primeng/dropdown';
12
+ import * as i4 from 'primeng/dialog';
13
+ import { DialogModule } from 'primeng/dialog';
14
+ import * as i9 from 'primeng/drawer';
15
+ import { DrawerModule } from 'primeng/drawer';
16
+ import * as i10 from 'primeng/dropdown';
14
17
  import { DropdownModule } from 'primeng/dropdown';
15
- import * as i10 from 'primeng/inputnumber';
18
+ import * as i11 from 'primeng/inputnumber';
16
19
  import { InputNumberModule } from 'primeng/inputnumber';
17
- import * as i11 from 'primeng/multiselect';
20
+ import * as i12 from 'primeng/multiselect';
18
21
  import { MultiSelectModule } from 'primeng/multiselect';
19
- import * as i12 from 'primeng/divider';
22
+ import * as i7$1 from 'primeng/tag';
23
+ import { TagModule } from 'primeng/tag';
24
+ import * as i13 from 'primeng/tooltip';
25
+ import { TooltipModule } from 'primeng/tooltip';
26
+ import * as i14 from 'primeng/divider';
20
27
  import { DividerModule } from 'primeng/divider';
21
- import * as i13 from 'primeng/table';
28
+ import * as i15 from 'primeng/table';
22
29
  import { TableModule } from 'primeng/table';
23
- import * as i14 from 'primeng/autocomplete';
30
+ import * as i16 from 'primeng/autocomplete';
24
31
  import { AutoCompleteModule } from 'primeng/autocomplete';
25
- import * as i15 from 'primeng/tooltip';
26
- import { TooltipModule } from 'primeng/tooltip';
27
- import * as i2 from '@seniorsistemas/components-ai';
28
- import { EntityService, TranslatePipe, LoadingComponent, DynamicFormComponent } from '@seniorsistemas/components-ai';
29
- import * as i2$1 from 'primeng/api';
30
- import { ConfirmationService } from 'primeng/api';
31
- import * as i4 from 'primeng/dialog';
32
- import { DialogModule } from 'primeng/dialog';
33
- import * as i6$1 from 'primeng/tag';
34
- import { TagModule } from 'primeng/tag';
35
- import * as i8$1 from 'primeng/confirmdialog';
36
- import { ConfirmDialogModule } from 'primeng/confirmdialog';
32
+ import * as i5 from '@seniorsistemas/components-ai';
33
+ import { TranslatePipe, DynamicFormComponent } from '@seniorsistemas/components-ai';
34
+ import * as i8 from 'primeng/api';
37
35
 
38
36
  /**
39
37
  * Módulo principal da biblioteca @senior-gestao-relacionamento/angular-components
@@ -305,279 +303,445 @@ var ParticipantConfirmation;
305
303
  ParticipantConfirmation["Pending"] = "PENDING";
306
304
  ParticipantConfirmation["No"] = "NO";
307
305
  })(ParticipantConfirmation || (ParticipantConfirmation = {}));
306
+ var Status;
307
+ (function (Status) {
308
+ Status["Active"] = "ACTIVE";
309
+ Status["Inactive"] = "INACTIVE";
310
+ Status["Deleted"] = "DELETED";
311
+ })(Status || (Status = {}));
308
312
 
309
- class ScheduleService extends EntityService {
313
+ const MINUTES_HALF_HOUR = 30;
314
+ const DAYS_IN_WEEK = 7;
315
+ const ORDINAL_THIRD_WEEK = 3;
316
+ const HOURS_IN_DAY = 24;
317
+ const MINUTES_IN_HOUR = 60;
318
+ const DATE_STRING_LENGTH = 10;
319
+ const TIME_SHORT_LENGTH = 5;
320
+ function formatDateToString(d) {
321
+ return d.toISOString().split('T')[0];
322
+ }
323
+ function toDateString(v) {
324
+ if (!v) {
325
+ return '';
326
+ }
327
+ if (v instanceof Date) {
328
+ return formatDateToString(v);
329
+ }
330
+ const s = String(v);
331
+ return s.length > DATE_STRING_LENGTH ? s.substring(0, DATE_STRING_LENGTH) : s;
332
+ }
333
+ function toTimeString(v) {
334
+ if (!v) {
335
+ return '';
336
+ }
337
+ if (v instanceof Date) {
338
+ return formatTime(v.getHours(), v.getMinutes());
339
+ }
340
+ const s = String(v);
341
+ if (s.includes('T')) {
342
+ const d = new Date(s);
343
+ return formatTime(d.getHours(), d.getMinutes());
344
+ }
345
+ return s.length === TIME_SHORT_LENGTH ? s + ':00' : s;
346
+ }
347
+ function getDefaultStartTime(d) {
348
+ let h = d.getHours();
349
+ let m = d.getMinutes();
350
+ if (m < MINUTES_HALF_HOUR) {
351
+ m = MINUTES_HALF_HOUR;
352
+ }
353
+ else {
354
+ h++;
355
+ m = 0;
356
+ }
357
+ if (h >= HOURS_IN_DAY) {
358
+ h = 0;
359
+ }
360
+ return formatTime(h, m);
361
+ }
362
+ function getDefaultEndTime(startTime) {
363
+ const [hS, mS] = startTime.split(':');
364
+ let h = +hS;
365
+ let m = +mS + MINUTES_HALF_HOUR;
366
+ if (m >= MINUTES_IN_HOUR) {
367
+ h++;
368
+ m -= MINUTES_IN_HOUR;
369
+ }
370
+ if (h >= HOURS_IN_DAY) {
371
+ h = 0;
372
+ }
373
+ return formatTime(h, m);
374
+ }
375
+ function getCurrentWeekDay(d) {
376
+ const days = [
377
+ WeekDay.Sunday, WeekDay.Monday, WeekDay.Tuesday,
378
+ WeekDay.Wednesday, WeekDay.Thursday, WeekDay.Friday,
379
+ WeekDay.Saturday
380
+ ];
381
+ return days[d.getDay()];
382
+ }
383
+ function getCurrentMonth(d) {
384
+ const months = [
385
+ Month.January, Month.February, Month.March,
386
+ Month.April, Month.May, Month.June,
387
+ Month.July, Month.August, Month.September,
388
+ Month.October, Month.November, Month.December
389
+ ];
390
+ return months[d.getMonth()];
391
+ }
392
+ function getOrdinalForDate(d) {
393
+ const dom = d.getDate();
394
+ const wn = Math.ceil(dom / DAYS_IN_WEEK);
395
+ const ld = new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
396
+ if (dom + DAYS_IN_WEEK > ld && wn >= 4) {
397
+ return OrdinalWeekDay.Last;
398
+ }
399
+ switch (wn) {
400
+ case 1: {
401
+ return OrdinalWeekDay.First;
402
+ }
403
+ case 2: {
404
+ return OrdinalWeekDay.Second;
405
+ }
406
+ case ORDINAL_THIRD_WEEK: {
407
+ return OrdinalWeekDay.Third;
408
+ }
409
+ case 4: {
410
+ return OrdinalWeekDay.Fourth;
411
+ }
412
+ default: {
413
+ return OrdinalWeekDay.Last;
414
+ }
415
+ }
416
+ }
417
+ function formatTime(h, m) {
418
+ return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:00`;
419
+ }
420
+
421
+ const ICON_PI_USER = 'pi pi-user';
422
+ const ORIGIN_LABELS = {
423
+ ACCOUNT: 'crmx.components.schedule_participant_account',
424
+ ACCOUNT_CONTACT: 'crmx.components.schedule_participant_account_contact',
425
+ COLLABORATOR: 'crmx.components.schedule_participant_collaborator',
426
+ EXTERNAL_PARTICIPANT: 'crmx.components.schedule_participant_external'
427
+ };
428
+ const ORIGIN_ICONS = {
429
+ ACCOUNT: 'pi pi-building',
430
+ ACCOUNT_CONTACT: 'pi pi-id-card',
431
+ COLLABORATOR: ICON_PI_USER,
432
+ EXTERNAL_PARTICIPANT: 'pi pi-user-plus'
433
+ };
434
+ function getOriginLabel(t, o) {
435
+ return t.translate(ORIGIN_LABELS[o] ?? o);
436
+ }
437
+ function getOriginIcon(o) {
438
+ return ORIGIN_ICONS[o] ?? ICON_PI_USER;
439
+ }
440
+ function getParticipantName(p) {
441
+ const candidates = [
442
+ p.collaborator?.name,
443
+ p.account?.name,
444
+ p.accountContact?.name,
445
+ p.externalParticipant?.name
446
+ ];
447
+ return candidates.find(name => name != null) ?? '-';
448
+ }
449
+ function getParticipantType(t, p) {
450
+ if (p.collaborator) {
451
+ return t.translate('crmx.components.schedule_participant_collaborator');
452
+ }
453
+ if (p.account) {
454
+ return t.translate('crmx.components.schedule_participant_account');
455
+ }
456
+ if (p.accountContact) {
457
+ return t.translate('crmx.components.schedule_participant_account_contact');
458
+ }
459
+ if (p.externalParticipant) {
460
+ return t.translate('crmx.components.schedule_participant_external');
461
+ }
462
+ return '-';
463
+ }
464
+ function getParticipantTypeIcon(p) {
465
+ if (p.collaborator) {
466
+ return ICON_PI_USER;
467
+ }
468
+ if (p.account) {
469
+ return 'pi pi-building';
470
+ }
471
+ if (p.accountContact) {
472
+ return 'pi pi-id-card';
473
+ }
474
+ if (p.externalParticipant) {
475
+ return 'pi pi-user-plus';
476
+ }
477
+ return ICON_PI_USER;
478
+ }
479
+ function getPrioritySeverity(p) {
480
+ switch (p) {
481
+ case SchedulePriority.Low: {
482
+ return 'success';
483
+ }
484
+ case SchedulePriority.Medium: {
485
+ return 'info';
486
+ }
487
+ case SchedulePriority.High: {
488
+ return 'warn';
489
+ }
490
+ case SchedulePriority.Critical: {
491
+ return 'danger';
492
+ }
493
+ default: {
494
+ return 'info';
495
+ }
496
+ }
497
+ }
498
+ function getPriorityLabel(t, p) {
499
+ return t.translate(`crmx.components.schedule_priority_${p.toLowerCase()}`);
500
+ }
501
+ function getConfirmationSeverity(c) {
502
+ switch (c) {
503
+ case 'YES': {
504
+ return 'success';
505
+ }
506
+ case 'NO': {
507
+ return 'danger';
508
+ }
509
+ default: {
510
+ return 'warn';
511
+ }
512
+ }
513
+ }
514
+ function getConfirmationLabel(t, c) {
515
+ switch (c) {
516
+ case 'YES': {
517
+ return t.translate('crmx.components.schedule_confirmation_yes');
518
+ }
519
+ case 'NO': {
520
+ return t.translate('crmx.components.schedule_confirmation_no');
521
+ }
522
+ default: {
523
+ return t.translate('crmx.components.schedule_confirmation_pending');
524
+ }
525
+ }
526
+ }
527
+
528
+ class ScheduleService {
529
+ http;
310
530
  entityUrl = 'crmx/schedule/entities/schedule';
311
531
  actionsUrl = 'crmx/schedule/actions';
312
532
  queriesUrl = 'crmx/schedule/queries';
313
- constructor(http, translationService) {
314
- super(http, translationService);
315
- this.initializeService();
533
+ constructor(http) {
534
+ this.http = http;
535
+ }
536
+ get(id) {
537
+ return this.http.get(`/${this.entityUrl}/${id}`);
538
+ }
539
+ insert(entity) {
540
+ return this.http.post(`/${this.entityUrl}`, entity);
541
+ }
542
+ update(id, entity) {
543
+ return this.http.put(`/${this.entityUrl}/${id}`, entity);
544
+ }
545
+ delete(id) {
546
+ return this.http.delete(`/${this.entityUrl}/${id}`);
316
547
  }
317
- /**
318
- * Busca recorrências de agendas por período
319
- */
320
548
  getRecurrencesByDate(startDate, endDate) {
321
549
  return this.http.post(`/${this.queriesUrl}/getRecurrencesByDate`, { startDate, endDate });
322
550
  }
323
- /**
324
- * Gera descrição textual da recorrência configurada
325
- */
326
551
  generateRecurrenceDescription(payload) {
327
552
  return this.http.post(`/${this.queriesUrl}/generateRecurrenceDescription`, payload);
328
553
  }
329
- /**
330
- * Aceita uma agenda (participante)
331
- */
332
554
  acceptSchedule(scheduleId, participantId, date) {
333
555
  return this.http.post(`/${this.actionsUrl}/acceptSchedule`, { scheduleId, participantId, date });
334
556
  }
335
- /**
336
- * Rejeita uma agenda (participante)
337
- */
338
557
  rejectSchedule(scheduleId, participantId, date) {
339
558
  return this.http.post(`/${this.actionsUrl}/rejectSchedule`, { scheduleId, participantId, date });
340
559
  }
341
- /**
342
- * Cancela uma agenda ou recorrência específica
343
- */
344
560
  cancelSchedule(scheduleId, date) {
345
561
  return this.http.post(`/${this.actionsUrl}/cancelSchedule`, { scheduleId, date });
346
562
  }
347
- /**
348
- * Gerencia participantes de uma agenda
349
- */
350
563
  manageParticipants(scheduleId, participants) {
351
564
  return this.http.post(`/crmx/schedule/signals/manageScheduleParticipants`, { scheduleId, ...participants });
352
565
  }
353
- /**
354
- * Lista participantes de uma agenda
355
- */
356
566
  listParticipants(scheduleId) {
357
567
  return this.http.get(`/${this.entityUrl}/${scheduleId}/participants`);
358
568
  }
359
- /**
360
- * Busca participantes disponíveis (lookup)
361
- */
362
569
  searchParticipantLookup(filter, size = 10, offset = 0) {
363
570
  return this.http.post(`/${this.queriesUrl}/listParticipants`, { filter, size, offset, orderBy: 'name ASC' });
364
571
  }
365
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleService, deps: [{ token: i1.HttpClient }, { token: i2.TranslationService }], target: i0.ɵɵFactoryTarget.Injectable });
572
+ list(params = {}) {
573
+ let httpParams = new HttpParams();
574
+ if (params.size) {
575
+ httpParams = httpParams.set('size', String(params.size));
576
+ }
577
+ if (params.filterQuery) {
578
+ httpParams = httpParams.set('filter', params.filterQuery);
579
+ }
580
+ return this.http.get(`/${this.entityUrl}`, { params: httpParams });
581
+ }
582
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
366
583
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleService, providedIn: 'root' });
367
584
  }
368
585
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleService, decorators: [{
369
586
  type: Injectable,
370
587
  args: [{ providedIn: 'root' }]
371
- }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.TranslationService }] });
588
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
372
589
 
373
- class ScheduleTypeService extends EntityService {
590
+ class ScheduleTypeService {
591
+ http;
374
592
  entityUrl = 'crmx/schedule/entities/scheduleType';
375
- actionsUrl = 'crmx/schedule/actions';
376
- constructor(http, translationService) {
377
- super(http, translationService);
378
- this.initializeService();
593
+ constructor(http) {
594
+ this.http = http;
595
+ }
596
+ list(params = {}) {
597
+ let httpParams = new HttpParams();
598
+ if (params.size) {
599
+ httpParams = httpParams.set('size', String(params.size));
600
+ }
601
+ const statusFilter = "status != 'DELETED'";
602
+ const filter = params.filterQuery
603
+ ? `(${params.filterQuery}) and ${statusFilter}`
604
+ : statusFilter;
605
+ httpParams = httpParams.set('filter', filter);
606
+ return this.http.get(`/${this.entityUrl}`, { params: httpParams });
607
+ }
608
+ get(id) {
609
+ return this.http.get(`/${this.entityUrl}/${id}`);
379
610
  }
380
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleTypeService, deps: [{ token: i1.HttpClient }, { token: i2.TranslationService }], target: i0.ɵɵFactoryTarget.Injectable });
611
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleTypeService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
381
612
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleTypeService, providedIn: 'root' });
382
613
  }
383
614
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleTypeService, decorators: [{
384
615
  type: Injectable,
385
616
  args: [{ providedIn: 'root' }]
386
- }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.TranslationService }] });
617
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
387
618
 
619
+ /** S109: Extract magic numbers to named constants */
620
+ const MAX_NAME_LENGTH = 255;
621
+ const DEBOUNCE_MS = 500;
622
+ const PARTICIPANT_SEARCH_LIMIT = 5;
388
623
  class ScheduleFormComponent {
389
624
  fb;
390
- t;
391
625
  scheduleService;
392
626
  scheduleTypeService;
627
+ currentCollaboratorService;
628
+ t;
393
629
  visible = false;
394
- scheduleData = null;
630
+ selectedDate = new Date();
395
631
  visibleChange = new EventEmitter();
396
- onSave = new EventEmitter();
397
- onCancel = new EventEmitter();
632
+ saved = new EventEmitter();
398
633
  detailFormComponent;
399
- MAX_NAME_LENGTH = 255;
400
- MIN_SEARCH_RESULTS = 5;
401
- MINUTES_HALF_HOUR = 30;
402
- MINUTES_IN_HOUR = 60;
403
- HOURS_IN_DAY = 24;
404
- DAYS_IN_WEEK = 7;
405
- DEBOUNCE_TIME_MS = 500;
406
- ORDINAL_WEEK_THRESHOLD = 4;
407
- WEEK_DAYS_IN_MONTH = 3;
408
- TIME_SECONDS_SUFFIX = ':00';
409
- scheduleForm;
410
634
  scheduleDetailFields = [];
411
635
  entityDataForForm = null;
412
- // Participants
636
+ scheduleForm;
637
+ isEditing = false;
638
+ currentCollaboratorId = null;
639
+ scheduleTypes = [];
640
+ participants = [];
413
641
  participantsLoading = false;
414
- addedParticipants = [];
415
- participantSuggestions = [];
416
- selectedParticipantLookup = null;
417
- // Recurrence
418
642
  recurrenceDescription = '';
643
+ /** S2933: Mark as readonly */
419
644
  recurrenceChange$ = new Subject();
420
- // Options
645
+ participantSuggestions = [];
646
+ selectedParticipantLookup = null;
647
+ addedParticipants = [];
421
648
  priorityOptions = [];
422
649
  recurrenceOptions = [];
423
650
  weekDayOptions = [];
424
651
  repeatWhenOptions = [];
425
652
  ordinalOptions = [];
426
653
  monthOptions = [];
427
- get isEditing() {
428
- return !!this.scheduleData?.id;
429
- }
430
- constructor(fb, t, scheduleService, scheduleTypeService) {
654
+ /** S2933: Mark constructor-injected services as readonly */
655
+ constructor(fb, scheduleService, scheduleTypeService, currentCollaboratorService, t) {
431
656
  this.fb = fb;
432
- this.t = t;
433
657
  this.scheduleService = scheduleService;
434
658
  this.scheduleTypeService = scheduleTypeService;
659
+ this.currentCollaboratorService = currentCollaboratorService;
660
+ this.t = t;
435
661
  }
436
662
  ngOnInit() {
437
663
  this.initOptions();
438
664
  this.initDetailFields();
439
665
  this.initForm();
666
+ this.loadScheduleTypes();
667
+ this.loadCollaborator();
440
668
  this.setupRecurrenceDescriptionWatcher();
441
669
  }
442
- ngOnChanges() {
443
- if (this.visible && this.scheduleData) {
444
- this.loadScheduleData();
445
- }
446
- else if (this.visible) {
447
- this.resetForm();
448
- }
670
+ loadCollaborator() {
671
+ this.currentCollaboratorService.load().subscribe({
672
+ next: (collab) => {
673
+ this.currentCollaboratorId = collab?.id ?? null;
674
+ },
675
+ error: () => {
676
+ this.currentCollaboratorId = null;
677
+ }
678
+ });
449
679
  }
450
680
  initOptions() {
451
681
  this.priorityOptions = [
452
- { label: this.t.translate('crmx.schedule.priority_low'), value: SchedulePriority.Low },
453
- { label: this.t.translate('crmx.schedule.priority_medium'), value: SchedulePriority.Medium },
454
- { label: this.t.translate('crmx.schedule.priority_high'), value: SchedulePriority.High },
455
- { label: this.t.translate('crmx.schedule.priority_critical'), value: SchedulePriority.Critical }
682
+ { label: this.t.translate('crmx.components.schedule_priority_low'), value: SchedulePriority.Low },
683
+ { label: this.t.translate('crmx.components.schedule_priority_medium'), value: SchedulePriority.Medium },
684
+ { label: this.t.translate('crmx.components.schedule_priority_high'), value: SchedulePriority.High },
685
+ { label: this.t.translate('crmx.components.schedule_priority_critical'), value: SchedulePriority.Critical }
456
686
  ];
457
687
  this.recurrenceOptions = [
458
- { label: this.t.translate('crmx.schedule.recurrence_daily'), value: ScheduleRecurrence.Daily },
459
- { label: this.t.translate('crmx.schedule.recurrence_weekly'), value: ScheduleRecurrence.Weekly },
460
- { label: this.t.translate('crmx.schedule.recurrence_monthly'), value: ScheduleRecurrence.Monthly },
461
- { label: this.t.translate('crmx.schedule.recurrence_yearly'), value: ScheduleRecurrence.Yearly }
688
+ { label: this.t.translate('crmx.components.schedule_recurrence_daily'), value: ScheduleRecurrence.Daily },
689
+ { label: this.t.translate('crmx.components.schedule_recurrence_weekly'), value: ScheduleRecurrence.Weekly },
690
+ { label: this.t.translate('crmx.components.schedule_recurrence_monthly'), value: ScheduleRecurrence.Monthly },
691
+ { label: this.t.translate('crmx.components.schedule_recurrence_yearly'), value: ScheduleRecurrence.Yearly }
462
692
  ];
463
693
  this.weekDayOptions = [
464
- { label: this.t.translate('crmx.schedule.sunday'), value: WeekDay.Sunday },
465
- { label: this.t.translate('crmx.schedule.monday'), value: WeekDay.Monday },
466
- { label: this.t.translate('crmx.schedule.tuesday'), value: WeekDay.Tuesday },
467
- { label: this.t.translate('crmx.schedule.wednesday'), value: WeekDay.Wednesday },
468
- { label: this.t.translate('crmx.schedule.thursday'), value: WeekDay.Thursday },
469
- { label: this.t.translate('crmx.schedule.friday'), value: WeekDay.Friday },
470
- { label: this.t.translate('crmx.schedule.saturday'), value: WeekDay.Saturday }
694
+ { label: this.t.translate('crmx.components.schedule_sunday'), value: WeekDay.Sunday },
695
+ { label: this.t.translate('crmx.components.schedule_monday'), value: WeekDay.Monday },
696
+ { label: this.t.translate('crmx.components.schedule_tuesday'), value: WeekDay.Tuesday },
697
+ { label: this.t.translate('crmx.components.schedule_wednesday'), value: WeekDay.Wednesday },
698
+ { label: this.t.translate('crmx.components.schedule_thursday'), value: WeekDay.Thursday },
699
+ { label: this.t.translate('crmx.components.schedule_friday'), value: WeekDay.Friday },
700
+ { label: this.t.translate('crmx.components.schedule_saturday'), value: WeekDay.Saturday }
471
701
  ];
472
702
  this.repeatWhenOptions = [
473
- { label: this.t.translate('crmx.schedule.repeat_in_day'), value: RepeatWhen.InDay },
474
- { label: this.t.translate('crmx.schedule.repeat_in_ordinal_week_day'), value: RepeatWhen.InOrdinalWeekDay }
703
+ { label: this.t.translate('crmx.components.schedule_repeat_in_day'), value: RepeatWhen.InDay },
704
+ { label: this.t.translate('crmx.components.schedule_repeat_in_ordinal_week_day'), value: RepeatWhen.InOrdinalWeekDay }
475
705
  ];
476
706
  this.ordinalOptions = [
477
- { label: this.t.translate('crmx.schedule.ordinal_first'), value: OrdinalWeekDay.First },
478
- { label: this.t.translate('crmx.schedule.ordinal_second'), value: OrdinalWeekDay.Second },
479
- { label: this.t.translate('crmx.schedule.ordinal_third'), value: OrdinalWeekDay.Third },
480
- { label: this.t.translate('crmx.schedule.ordinal_fourth'), value: OrdinalWeekDay.Fourth },
481
- { label: this.t.translate('crmx.schedule.ordinal_last'), value: OrdinalWeekDay.Last }
707
+ { label: this.t.translate('crmx.components.schedule_ordinal_first'), value: OrdinalWeekDay.First },
708
+ { label: this.t.translate('crmx.components.schedule_ordinal_second'), value: OrdinalWeekDay.Second },
709
+ { label: this.t.translate('crmx.components.schedule_ordinal_third'), value: OrdinalWeekDay.Third },
710
+ { label: this.t.translate('crmx.components.schedule_ordinal_fourth'), value: OrdinalWeekDay.Fourth },
711
+ { label: this.t.translate('crmx.components.schedule_ordinal_last'), value: OrdinalWeekDay.Last }
482
712
  ];
483
713
  this.monthOptions = Object.values(Month).map(m => ({
484
- label: this.t.translate(`crmx.schedule.${m.toLowerCase()}`), value: m
714
+ label: this.t.translate(`crmx.components.schedule_${m.toLowerCase()}`), value: m
485
715
  }));
486
716
  }
487
717
  initDetailFields() {
488
718
  const now = new Date();
489
719
  const defaultStart = this.getDefaultStartTime(now);
490
720
  const defaultEnd = this.getDefaultEndTime(defaultStart);
721
+ const fullRow = { xl: 12, lg: 12, md: 12, sm: 12 };
722
+ const halfRow = { xl: 6, lg: 6, md: 6, sm: 12 };
491
723
  this.scheduleDetailFields = [
492
- {
493
- field: 'name', label: this.t.translate('crmx.schedule.name'), type: 'text',
494
- required: true, validators: [Validators.required, Validators.maxLength(this.MAX_NAME_LENGTH)],
495
- placeholder: this.t.translate('crmx.schedule.enter_name'), maxLength: this.MAX_NAME_LENGTH,
496
- size: { xl: 12, lg: 12, md: 12, sm: 12 }
497
- },
498
- {
499
- field: 'priority', label: this.t.translate('crmx.schedule.priority'), type: 'dropdown',
500
- required: true, validators: [Validators.required],
501
- options: this.priorityOptions, optionLabel: 'label', optionValue: 'value',
502
- defaultValue: SchedulePriority.Medium, size: { xl: 12, lg: 12, md: 12, sm: 12 }
503
- },
504
- {
505
- field: 'type', label: this.t.translate('crmx.schedule.type'), type: 'lookup',
506
- lookupService: this.scheduleTypeService, lookupDisplayField: 'name', lookupValueField: 'id',
507
- lookupSearchFields: ['name'], showClear: true, lookupAutocomplete: true,
508
- lookupColumns: [{ field: 'name', header: this.t.translate('crmx.schedule.name') }],
509
- lookupFilters: "status = 'ACTIVE'",
510
- placeholder: this.t.translate('crmx.schedule.select_type'), size: { xl: 12, lg: 12, md: 12, sm: 12 }
511
- },
512
- {
513
- field: 'startDate', label: this.t.translate('crmx.schedule.start_date'), type: 'date',
514
- required: true, validators: [Validators.required],
515
- defaultValue: this.formatDate(now),
516
- size: (v) => v['withRecurrence'] ? { xl: 6, lg: 6, md: 6, sm: 12 } : { xl: 12, lg: 12, md: 12, sm: 12 }
517
- },
518
- {
519
- field: 'endDate', label: this.t.translate('crmx.schedule.end_date'), type: 'date',
520
- visibleWhen: (v) => v['withRecurrence'] === true,
521
- size: { xl: 6, lg: 6, md: 6, sm: 12 }
522
- },
523
- {
524
- field: 'startTime', label: this.t.translate('crmx.schedule.start_time'), type: 'time',
525
- defaultValue: defaultStart,
526
- visibleWhen: (v) => v['allDay'] !== true,
527
- size: { xl: 6, lg: 6, md: 6, sm: 12 }
528
- },
529
- {
530
- field: 'endTime', label: this.t.translate('crmx.schedule.end_time'), type: 'time',
531
- defaultValue: defaultEnd,
532
- visibleWhen: (v) => v['allDay'] !== true,
533
- size: { xl: 6, lg: 6, md: 6, sm: 12 }
534
- },
535
- {
536
- field: 'allDay', label: this.t.translate('crmx.schedule.all_day'), type: 'checkbox',
537
- defaultValue: false, size: { xl: 6, lg: 6, md: 6, sm: 12 }
538
- },
539
- {
540
- field: 'withRecurrence', label: this.t.translate('crmx.schedule.with_recurrence'), type: 'checkbox',
541
- defaultValue: false, size: { xl: 6, lg: 6, md: 6, sm: 12 }
542
- },
543
- {
544
- field: 'comments', label: this.t.translate('crmx.schedule.comments'), type: 'textarea',
545
- placeholder: this.t.translate('crmx.schedule.enter_comments'), rows: 3,
546
- size: { xl: 12, lg: 12, md: 12, sm: 12 }
547
- }
724
+ { field: 'name', label: this.t.translate('crmx.components.schedule_name'), type: 'text', required: true, validators: [Validators.required, Validators.maxLength(MAX_NAME_LENGTH)], placeholder: this.t.translate('crmx.components.schedule_enter_name'), maxLength: MAX_NAME_LENGTH, size: fullRow },
725
+ { field: 'priority', label: this.t.translate('crmx.components.schedule_priority'), type: 'dropdown', required: true, validators: [Validators.required], options: this.priorityOptions, optionLabel: 'label', optionValue: 'value', defaultValue: SchedulePriority.Medium, size: fullRow },
726
+ { field: 'type', label: this.t.translate('crmx.components.schedule_type'), type: 'lookup', lookupService: this.scheduleTypeService, lookupDisplayField: 'name', lookupValueField: 'id', lookupSearchFields: ['name'], showClear: true, lookupAutocomplete: true, lookupColumns: [{ field: 'name', header: this.t.translate('crmx.components.schedule_name') }], lookupFilters: "status = 'ACTIVE'", placeholder: this.t.translate('crmx.components.schedule_select_type'), size: fullRow },
727
+ { field: 'startDate', label: this.t.translate('crmx.components.schedule_start_date'), type: 'date', required: true, validators: [Validators.required], defaultValue: formatDateToString(now), size: (v) => v['withRecurrence'] ? halfRow : fullRow },
728
+ { field: 'endDate', label: this.t.translate('crmx.components.schedule_end_date'), type: 'date', visibleWhen: (v) => v['withRecurrence'] === true, size: halfRow },
729
+ { field: 'startTime', label: this.t.translate('crmx.components.schedule_start_time'), type: 'time', defaultValue: defaultStart, visibleWhen: (v) => v['allDay'] !== true, size: halfRow },
730
+ { field: 'endTime', label: this.t.translate('crmx.components.schedule_end_time'), type: 'time', defaultValue: defaultEnd, visibleWhen: (v) => v['allDay'] !== true, size: halfRow },
731
+ { field: 'allDay', label: this.t.translate('crmx.components.schedule_all_day'), type: 'checkbox', defaultValue: false, size: halfRow },
732
+ { field: 'withRecurrence', label: this.t.translate('crmx.components.schedule_with_recurrence'), type: 'checkbox', defaultValue: false, size: halfRow },
733
+ { field: 'comments', label: this.t.translate('crmx.components.schedule_comments'), type: 'textarea', placeholder: this.t.translate('crmx.components.schedule_enter_comments'), rows: 3, size: fullRow }
548
734
  ];
549
735
  }
550
- initForm() {
551
- const now = new Date();
552
- const currentDayOfWeek = this.getCurrentWeekDay(now);
553
- const currentMonth = this.getCurrentMonth(now);
554
- const defaultStart = this.getDefaultStartTime(now);
555
- const defaultEnd = this.getDefaultEndTime(defaultStart);
556
- this.scheduleForm = this.fb.group({
557
- id: [null],
558
- name: ['', [Validators.required, Validators.maxLength(this.MAX_NAME_LENGTH)]],
559
- type: [null],
560
- priority: [SchedulePriority.Medium, Validators.required],
561
- allDay: [false],
562
- withRecurrence: [false],
563
- startDate: [this.formatDate(now), Validators.required],
564
- endDate: [null],
565
- startTime: [defaultStart],
566
- endTime: [defaultEnd],
567
- recurrence: [ScheduleRecurrence.Daily],
568
- recurrenceInterval: [1],
569
- weekDays: [[currentDayOfWeek]],
570
- repeatWhen: [RepeatWhen.InDay],
571
- repeatWhenDay: [now.getDate()],
572
- repeatWhenOrdinalWeekDay: [this.getOrdinalForDate(now)],
573
- repeatWhenWeekMonth: [currentDayOfWeek],
574
- repeatWhenMonth: [currentMonth],
575
- comments: ['']
576
- });
577
- }
578
736
  onDetailFormReady(form) {
579
737
  this.scheduleForm = form;
580
- // Add recurrence fields
738
+ this.addRecurrenceControls();
739
+ this.scheduleForm.valueChanges.subscribe(() => this.recurrenceChange$.next());
740
+ this.setupRecurrenceFormWatchers();
741
+ }
742
+ /** S121: Add braces to all if statements */
743
+ addRecurrenceControls() {
744
+ const now = new Date();
581
745
  if (!this.scheduleForm.contains('id')) {
582
746
  this.scheduleForm.addControl('id', this.fb.control(null));
583
747
  }
@@ -588,179 +752,218 @@ class ScheduleFormComponent {
588
752
  this.scheduleForm.addControl('recurrenceInterval', this.fb.control(1));
589
753
  }
590
754
  if (!this.scheduleForm.contains('weekDays')) {
591
- this.scheduleForm.addControl('weekDays', this.fb.control([this.getCurrentWeekDay(new Date())]));
755
+ this.scheduleForm.addControl('weekDays', this.fb.control([getCurrentWeekDay(now)]));
592
756
  }
593
757
  if (!this.scheduleForm.contains('repeatWhen')) {
594
758
  this.scheduleForm.addControl('repeatWhen', this.fb.control(RepeatWhen.InDay));
595
759
  }
596
760
  if (!this.scheduleForm.contains('repeatWhenDay')) {
597
- this.scheduleForm.addControl('repeatWhenDay', this.fb.control(new Date().getDate()));
761
+ this.scheduleForm.addControl('repeatWhenDay', this.fb.control(now.getDate()));
598
762
  }
599
763
  if (!this.scheduleForm.contains('repeatWhenOrdinalWeekDay')) {
600
- this.scheduleForm.addControl('repeatWhenOrdinalWeekDay', this.fb.control(this.getOrdinalForDate(new Date())));
764
+ this.scheduleForm.addControl('repeatWhenOrdinalWeekDay', this.fb.control(getOrdinalForDate(now)));
601
765
  }
602
766
  if (!this.scheduleForm.contains('repeatWhenWeekMonth')) {
603
- this.scheduleForm.addControl('repeatWhenWeekMonth', this.fb.control(this.getCurrentWeekDay(new Date())));
767
+ this.scheduleForm.addControl('repeatWhenWeekMonth', this.fb.control(getCurrentWeekDay(now)));
604
768
  }
605
769
  if (!this.scheduleForm.contains('repeatWhenMonth')) {
606
- this.scheduleForm.addControl('repeatWhenMonth', this.fb.control(this.getCurrentMonth(new Date())));
770
+ this.scheduleForm.addControl('repeatWhenMonth', this.fb.control(getCurrentMonth(now)));
607
771
  }
608
- // Watch for changes
609
- this.scheduleForm.valueChanges.subscribe(() => {
610
- this.recurrenceChange$.next();
611
- });
612
- this.setupRecurrenceFieldsWatchers();
613
772
  }
614
- setupRecurrenceFieldsWatchers() {
615
- const d = new Date();
773
+ /**
774
+ * S1541: Break setupRecurrenceFormWatchers into smaller helpers
775
+ * to reduce cyclomatic complexity
776
+ */
777
+ setupRecurrenceFormWatchers() {
778
+ const d = this.selectedDate || new Date();
779
+ this.watchRecurrenceChanges(d);
780
+ this.watchRepeatWhenChanges(d);
781
+ this.watchWithRecurrenceChanges(d);
782
+ }
783
+ watchRecurrenceChanges(d) {
616
784
  this.scheduleForm.get('recurrence')?.valueChanges.subscribe((rec) => {
617
- this.handleRecurrenceChange(rec, d);
618
- });
619
- this.scheduleForm.get('repeatWhen')?.valueChanges.subscribe((rw) => {
620
- this.handleRepeatWhenChange(rw, d);
621
- });
622
- this.scheduleForm.get('withRecurrence')?.valueChanges.subscribe((wr) => {
623
- this.handleWithRecurrenceChange(wr, d);
785
+ this.handleRecurrenceWeekDays(rec, d);
786
+ this.handleRecurrenceMonthlyYearly(rec, d);
787
+ this.handleRecurrenceYearlyMonth(rec, d);
788
+ this.recurrenceChange$.next();
624
789
  });
625
790
  }
626
- handleRecurrenceChange(rec, d) {
627
- this.updateWeekDaysForRecurrence(rec, d);
628
- this.updateRepeatFieldsForRecurrence(rec, d);
629
- this.updateMonthFieldForRecurrence(rec, d);
630
- this.recurrenceChange$.next();
631
- }
632
- updateWeekDaysForRecurrence(rec, d) {
791
+ handleRecurrenceWeekDays(rec, d) {
633
792
  if (rec === ScheduleRecurrence.Weekly) {
634
793
  const current = this.scheduleForm.get('weekDays')?.value;
635
794
  if (!current || current.length === 0) {
636
- this.scheduleForm.patchValue({ weekDays: [this.getCurrentWeekDay(d)] }, { emitEvent: false });
795
+ this.scheduleForm.patchValue({ weekDays: [getCurrentWeekDay(d)] }, { emitEvent: false });
637
796
  }
638
797
  }
639
798
  else {
640
799
  this.scheduleForm.patchValue({ weekDays: [] }, { emitEvent: false });
641
800
  }
642
801
  }
643
- updateRepeatFieldsForRecurrence(rec, d) {
644
- if (rec === ScheduleRecurrence.Monthly || rec === ScheduleRecurrence.Yearly) {
802
+ handleRecurrenceMonthlyYearly(rec, d) {
803
+ if (rec === ScheduleRecurrence.Monthly ||
804
+ rec === ScheduleRecurrence.Yearly) {
645
805
  this.scheduleForm.patchValue({
646
- repeatWhen: this.scheduleForm.get('repeatWhen')?.value || RepeatWhen.InDay,
647
- repeatWhenDay: this.scheduleForm.get('repeatWhenDay')?.value || d.getDate(),
648
- repeatWhenOrdinalWeekDay: this.scheduleForm.get('repeatWhenOrdinalWeekDay')?.value || this.getOrdinalForDate(d),
649
- repeatWhenWeekMonth: this.scheduleForm.get('repeatWhenWeekMonth')?.value || this.getCurrentWeekDay(d)
806
+ repeatWhen: this.scheduleForm.get('repeatWhen')?.value ?? RepeatWhen.InDay,
807
+ repeatWhenDay: this.scheduleForm.get('repeatWhenDay')?.value ?? d.getDate(),
808
+ repeatWhenOrdinalWeekDay: this.scheduleForm.get('repeatWhenOrdinalWeekDay')?.value
809
+ ?? getOrdinalForDate(d),
810
+ repeatWhenWeekMonth: this.scheduleForm.get('repeatWhenWeekMonth')?.value
811
+ ?? getCurrentWeekDay(d)
650
812
  }, { emitEvent: false });
651
813
  }
652
814
  else {
653
815
  this.scheduleForm.patchValue({
654
- repeatWhen: null, repeatWhenDay: null, repeatWhenOrdinalWeekDay: null,
655
- repeatWhenWeekMonth: null, repeatWhenMonth: null
816
+ repeatWhen: null,
817
+ repeatWhenDay: null,
818
+ repeatWhenOrdinalWeekDay: null,
819
+ repeatWhenWeekMonth: null,
820
+ repeatWhenMonth: null
656
821
  }, { emitEvent: false });
657
822
  }
658
823
  }
659
- updateMonthFieldForRecurrence(rec, d) {
824
+ handleRecurrenceYearlyMonth(rec, d) {
660
825
  if (rec === ScheduleRecurrence.Yearly) {
661
826
  this.scheduleForm.patchValue({
662
- repeatWhenMonth: this.scheduleForm.get('repeatWhenMonth')?.value || this.getCurrentMonth(d)
827
+ repeatWhenMonth: this.scheduleForm.get('repeatWhenMonth')?.value
828
+ ?? getCurrentMonth(d)
663
829
  }, { emitEvent: false });
664
830
  }
665
831
  else {
666
832
  this.scheduleForm.patchValue({ repeatWhenMonth: null }, { emitEvent: false });
667
833
  }
668
834
  }
669
- handleRepeatWhenChange(rw, d) {
670
- if (rw === RepeatWhen.InDay) {
671
- this.scheduleForm.patchValue({
672
- repeatWhenDay: this.scheduleForm.get('repeatWhenDay')?.value || d.getDate(),
673
- repeatWhenOrdinalWeekDay: null, repeatWhenWeekMonth: null
674
- }, { emitEvent: false });
675
- }
676
- else {
677
- this.scheduleForm.patchValue({
678
- repeatWhenDay: null,
679
- repeatWhenOrdinalWeekDay: this.scheduleForm.get('repeatWhenOrdinalWeekDay')?.value || this.getOrdinalForDate(d),
680
- repeatWhenWeekMonth: this.scheduleForm.get('repeatWhenWeekMonth')?.value || this.getCurrentWeekDay(d)
681
- }, { emitEvent: false });
682
- }
835
+ watchRepeatWhenChanges(d) {
836
+ this.scheduleForm.get('repeatWhen')?.valueChanges.subscribe((rw) => {
837
+ if (rw === RepeatWhen.InDay) {
838
+ this.scheduleForm.patchValue({
839
+ repeatWhenDay: this.scheduleForm.get('repeatWhenDay')?.value ?? d.getDate(),
840
+ repeatWhenOrdinalWeekDay: null,
841
+ repeatWhenWeekMonth: null
842
+ }, { emitEvent: false });
843
+ }
844
+ else if (rw === RepeatWhen.InOrdinalWeekDay) {
845
+ this.scheduleForm.patchValue({
846
+ repeatWhenDay: null,
847
+ repeatWhenOrdinalWeekDay: this.scheduleForm.get('repeatWhenOrdinalWeekDay')?.value
848
+ ?? getOrdinalForDate(d),
849
+ repeatWhenWeekMonth: this.scheduleForm.get('repeatWhenWeekMonth')?.value
850
+ ?? getCurrentWeekDay(d)
851
+ }, { emitEvent: false });
852
+ }
853
+ else {
854
+ // No action needed for other repeatWhen values
855
+ }
856
+ this.recurrenceChange$.next();
857
+ });
858
+ }
859
+ watchWithRecurrenceChanges(d) {
860
+ this.scheduleForm.get('withRecurrence')?.valueChanges.subscribe(() => {
861
+ const enabled = this.scheduleForm.get('withRecurrence')?.value === true;
862
+ if (enabled) {
863
+ this.onRecurrenceEnabled(d);
864
+ }
865
+ else {
866
+ this.onRecurrenceDisabled();
867
+ }
868
+ });
869
+ }
870
+ onRecurrenceEnabled(d) {
871
+ this.resetRecurrenceDefaults(d);
683
872
  this.recurrenceChange$.next();
684
873
  }
685
- handleWithRecurrenceChange(wr, d) {
686
- if (!wr) {
687
- this.recurrenceDescription = '';
688
- }
689
- else {
690
- this.resetRecurrenceDefaults(d);
691
- this.recurrenceChange$.next();
692
- }
874
+ onRecurrenceDisabled() {
875
+ this.recurrenceDescription = '';
693
876
  }
694
- setupRecurrenceDescriptionWatcher() {
695
- this.recurrenceChange$.pipe(debounceTime(this.DEBOUNCE_TIME_MS)).subscribe(() => {
696
- this.fetchRecurrenceDescription();
877
+ initForm() {
878
+ const now = new Date();
879
+ const defaultStart = this.getDefaultStartTime(now);
880
+ const defaultEnd = this.getDefaultEndTime(defaultStart);
881
+ this.scheduleForm = this.fb.group({
882
+ id: [null],
883
+ name: ['', [Validators.required, Validators.maxLength(MAX_NAME_LENGTH)]],
884
+ type: [null],
885
+ priority: [SchedulePriority.Medium, Validators.required],
886
+ allDay: [false],
887
+ withRecurrence: [false],
888
+ startDate: [
889
+ formatDateToString(this.selectedDate || now),
890
+ Validators.required
891
+ ],
892
+ endDate: [null],
893
+ startTime: [defaultStart],
894
+ endTime: [defaultEnd],
895
+ recurrence: [ScheduleRecurrence.Daily],
896
+ recurrenceInterval: [1],
897
+ weekDays: [[getCurrentWeekDay(now)]],
898
+ repeatWhen: [RepeatWhen.InDay],
899
+ repeatWhenDay: [now.getDate()],
900
+ repeatWhenOrdinalWeekDay: [getOrdinalForDate(now)],
901
+ repeatWhenWeekMonth: [getCurrentWeekDay(now)],
902
+ repeatWhenMonth: [getCurrentMonth(now)],
903
+ comments: ['']
697
904
  });
698
905
  }
906
+ setupRecurrenceDescriptionWatcher() {
907
+ this.recurrenceChange$.pipe(debounceTime(DEBOUNCE_MS)).subscribe(() => this.fetchRecurrenceDescription());
908
+ }
699
909
  fetchRecurrenceDescription() {
700
- if (!this.canFetchRecurrenceDescription()) {
910
+ if (!this.scheduleForm) {
701
911
  return;
702
912
  }
703
- const payload = this.buildRecurrencePayload();
704
- this.scheduleService.generateRecurrenceDescription(payload).subscribe({
705
- next: (r) => { this.recurrenceDescription = r.description || ''; },
706
- error: () => { this.recurrenceDescription = ''; }
707
- });
708
- }
709
- canFetchRecurrenceDescription() {
710
- if (!this.scheduleForm || !this.scheduleService) {
711
- return false;
712
- }
713
913
  const v = this.scheduleForm.value;
714
914
  if (!v.withRecurrence || !v.startDate) {
715
915
  this.recurrenceDescription = '';
716
- return false;
916
+ return;
717
917
  }
718
- return true;
918
+ this.scheduleService.generateRecurrenceDescription(this.buildRecurrencePayload(v)).subscribe({
919
+ next: (r) => {
920
+ this.recurrenceDescription = r.description ?? '';
921
+ },
922
+ error: () => {
923
+ this.recurrenceDescription = '';
924
+ }
925
+ });
719
926
  }
720
- buildRecurrencePayload() {
721
- const v = this.scheduleForm.value;
927
+ buildRecurrencePayload(v) {
722
928
  return {
723
- startDate: this.toDateString(v.startDate),
724
- endDate: v.endDate ? this.toDateString(v.endDate) : null,
725
- startTime: v.startTime ? this.toTimeString(v.startTime) : null,
726
- endTime: v.endTime ? this.toTimeString(v.endTime) : null,
727
- allDay: v.allDay || false,
728
- withRecurrence: v.withRecurrence || false,
729
- recurrenceInterval: v.recurrenceInterval || 1,
730
- recurrence: v.recurrence,
731
- weekDays: v.weekDays || null,
732
- repeatWhen: v.repeatWhen || null,
733
- repeatWhenDay: v.repeatWhenDay || null,
734
- repeatWhenOrdinalWeekDay: v.repeatWhenOrdinalWeekDay || null,
735
- repeatWhenWeekMonth: v.repeatWhenWeekMonth || null,
736
- repeatWhenMonth: v.repeatWhenMonth || null
929
+ ...this.buildDateTimePayload(v),
930
+ allDay: v['allDay'] || false,
931
+ withRecurrence: true,
932
+ recurrenceInterval: v['recurrenceInterval'] || 1,
933
+ recurrence: v['recurrence'],
934
+ ...this.buildNullableRecurrenceFields(v)
737
935
  };
738
936
  }
739
- loadScheduleData() {
740
- if (!this.scheduleData || !this.scheduleService) {
741
- return;
742
- }
743
- this.entityDataForForm = { ...this.scheduleData, type: this.scheduleData.type || null };
744
- if (this.scheduleData.id) {
745
- this.loadParticipants(this.scheduleData.id);
746
- }
747
- setTimeout(() => {
748
- if (this.scheduleForm && this.scheduleData) {
749
- this.scheduleForm.patchValue({
750
- id: this.scheduleData.id,
751
- recurrence: this.scheduleData.recurrence,
752
- recurrenceInterval: this.scheduleData.recurrenceInterval,
753
- weekDays: this.scheduleData.weekDays,
754
- repeatWhen: this.scheduleData.repeatWhen,
755
- repeatWhenDay: this.scheduleData.repeatWhenDay,
756
- repeatWhenOrdinalWeekDay: this.scheduleData.repeatWhenOrdinalWeekDay,
757
- repeatWhenWeekMonth: this.scheduleData.repeatWhenWeekMonth,
758
- repeatWhenMonth: this.scheduleData.repeatWhenMonth
759
- });
937
+ buildDateTimePayload(v) {
938
+ return {
939
+ startDate: toDateString(v['startDate']),
940
+ endDate: v['endDate'] ? toDateString(v['endDate']) : null,
941
+ startTime: v['startTime'] ? toTimeString(v['startTime']) : null,
942
+ endTime: v['endTime'] ? toTimeString(v['endTime']) : null
943
+ };
944
+ }
945
+ buildNullableRecurrenceFields(v) {
946
+ return {
947
+ weekDays: v['weekDays'] ?? null,
948
+ repeatWhen: v['repeatWhen'] ?? null,
949
+ repeatWhenDay: v['repeatWhenDay'] ?? null,
950
+ repeatWhenOrdinalWeekDay: v['repeatWhenOrdinalWeekDay'] ?? null,
951
+ repeatWhenWeekMonth: v['repeatWhenWeekMonth'] ?? null,
952
+ repeatWhenMonth: v['repeatWhenMonth'] ?? null
953
+ };
954
+ }
955
+ loadScheduleTypes() {
956
+ this.scheduleTypeService.list({
957
+ size: 100,
958
+ filterQuery: "status = 'ACTIVE'"
959
+ }).subscribe({
960
+ next: (r) => {
961
+ this.scheduleTypes = r.contents;
760
962
  }
761
963
  });
762
964
  }
763
- resetForm() {
965
+ openNew() {
966
+ this.isEditing = false;
764
967
  const now = new Date();
765
968
  const defaultStart = this.getDefaultStartTime(now);
766
969
  const defaultEnd = this.getDefaultEndTime(defaultStart);
@@ -769,220 +972,279 @@ class ScheduleFormComponent {
769
972
  this.detailFormComponent.resetForm();
770
973
  }
771
974
  this.entityDataForForm = {
772
- startDate: this.formatDate(now),
975
+ startDate: formatDateToString(this.selectedDate || now),
773
976
  priority: SchedulePriority.Medium,
774
977
  allDay: false,
775
978
  withRecurrence: false,
776
979
  startTime: defaultStart,
777
980
  endTime: defaultEnd
778
981
  };
779
- this.resetRecurrenceDefaults(now);
982
+ this.resetRecurrenceDefaults(this.selectedDate || now);
780
983
  this.recurrenceDescription = '';
984
+ this.participants = [];
781
985
  this.addedParticipants = [];
782
986
  this.selectedParticipantLookup = null;
987
+ this.visible = true;
988
+ this.visibleChange.emit(true);
783
989
  }
784
- resetRecurrenceDefaults(date) {
785
- if (!this.scheduleForm) {
786
- return;
787
- }
788
- const d = date || new Date();
789
- const patchValues = {
790
- id: null,
791
- recurrence: ScheduleRecurrence.Daily,
792
- recurrenceInterval: 1,
793
- weekDays: [this.getCurrentWeekDay(d)],
794
- repeatWhen: RepeatWhen.InDay,
795
- repeatWhenDay: d.getDate(),
796
- repeatWhenOrdinalWeekDay: this.getOrdinalForDate(d),
797
- repeatWhenWeekMonth: this.getCurrentWeekDay(d),
798
- repeatWhenMonth: this.getCurrentMonth(d)
799
- };
800
- this.scheduleForm.patchValue(patchValues);
990
+ openEdit(scheduleId) {
991
+ this.isEditing = true;
992
+ this.participants = [];
993
+ this.addedParticipants = [];
994
+ this.selectedParticipantLookup = null;
995
+ this.scheduleService.get(scheduleId).subscribe({
996
+ next: (data) => {
997
+ this.entityDataForForm = { ...data, type: data.type ?? null };
998
+ this.loadParticipants(scheduleId);
999
+ this.visible = true;
1000
+ this.visibleChange.emit(true);
1001
+ setTimeout(() => {
1002
+ if (this.scheduleForm) {
1003
+ this.scheduleForm.patchValue({
1004
+ id: data.id,
1005
+ recurrence: data.recurrence,
1006
+ recurrenceInterval: data.recurrenceInterval,
1007
+ weekDays: data.weekDays,
1008
+ repeatWhen: data.repeatWhen,
1009
+ repeatWhenDay: data.repeatWhenDay,
1010
+ repeatWhenOrdinalWeekDay: data.repeatWhenOrdinalWeekDay,
1011
+ repeatWhenWeekMonth: data.repeatWhenWeekMonth,
1012
+ repeatWhenMonth: data.repeatWhenMonth
1013
+ });
1014
+ }
1015
+ });
1016
+ }
1017
+ });
801
1018
  }
802
- // Participants
803
1019
  loadParticipants(scheduleId) {
804
- if (!this.scheduleService) {
805
- return;
806
- }
807
1020
  this.participantsLoading = true;
808
1021
  this.scheduleService.listParticipants(scheduleId).subscribe({
809
1022
  next: (r) => {
810
- const participants = r.contents || [];
811
- this.addedParticipants = participants
812
- .filter((p) => !p.organizer)
813
- .map((p) => this.participantToLookup(p))
1023
+ this.participants = r.contents ?? [];
1024
+ this.addedParticipants = this.participants
1025
+ .filter(p => !p.organizer)
1026
+ .map(p => this.participantToLookup(p))
814
1027
  .filter((p) => p !== null);
815
1028
  this.participantsLoading = false;
816
1029
  },
817
- error: () => { this.participantsLoading = false; }
1030
+ error: () => {
1031
+ this.participantsLoading = false;
1032
+ }
818
1033
  });
819
1034
  }
820
1035
  participantToLookup(p) {
821
1036
  if (p.collaborator) {
822
- return { id: p.collaborator.id, name: p.collaborator.name, origin: 'COLLABORATOR' };
1037
+ return {
1038
+ id: p.collaborator.id,
1039
+ name: p.collaborator.name,
1040
+ origin: 'COLLABORATOR'
1041
+ };
823
1042
  }
824
1043
  if (p.account) {
825
- return { id: p.account.id, name: p.account.name, origin: 'ACCOUNT' };
1044
+ return {
1045
+ id: p.account.id,
1046
+ name: p.account.name,
1047
+ origin: 'ACCOUNT'
1048
+ };
826
1049
  }
827
1050
  if (p.accountContact) {
828
1051
  return {
829
- id: p.accountContact.id, name: p.accountContact.name,
830
- referenceName: p.accountContact.account?.name, referenceId: p.accountContact.account?.id,
1052
+ id: p.accountContact.id,
1053
+ name: p.accountContact.name,
1054
+ referenceName: p.accountContact.account?.name,
1055
+ referenceId: p.accountContact.account?.id,
831
1056
  origin: 'ACCOUNT_CONTACT'
832
1057
  };
833
1058
  }
834
1059
  if (p.externalParticipant) {
835
1060
  return {
836
- id: p.externalParticipant.id, name: p.externalParticipant.name, origin: 'EXTERNAL_PARTICIPANT'
1061
+ id: p.externalParticipant.id,
1062
+ name: p.externalParticipant.name,
1063
+ origin: 'EXTERNAL_PARTICIPANT'
837
1064
  };
838
1065
  }
839
1066
  return null;
840
1067
  }
841
1068
  onSearchParticipants(event) {
842
- if (!this.scheduleService) {
843
- return;
844
- }
845
- const query = event.query || '';
846
- this.scheduleService.searchParticipantLookup(query, this.MIN_SEARCH_RESULTS).subscribe({
1069
+ this.scheduleService.searchParticipantLookup(event.query ?? '', PARTICIPANT_SEARCH_LIMIT).subscribe({
847
1070
  next: (r) => {
848
1071
  const addedIds = new Set(this.addedParticipants.map(p => p.id + p.origin));
849
- this.participantSuggestions = (r.contents || []).filter((p) => !addedIds.has(p.id + p.origin));
1072
+ this.participantSuggestions = (r.contents ?? [])
1073
+ .filter(p => !addedIds.has(p.id + p.origin));
850
1074
  },
851
- error: () => { this.participantSuggestions = []; }
1075
+ error: () => {
1076
+ this.participantSuggestions = [];
1077
+ }
852
1078
  });
853
1079
  }
854
1080
  onSelectParticipant(participant) {
855
- const alreadyAdded = this.addedParticipants.some(p => p.id === participant.id && p.origin === participant.origin);
856
- if (!alreadyAdded) {
1081
+ if (!this.addedParticipants.some(p => p.id === participant.id && p.origin === participant.origin)) {
857
1082
  this.addedParticipants = [...this.addedParticipants, participant];
858
1083
  }
859
- setTimeout(() => { this.selectedParticipantLookup = null; });
1084
+ setTimeout(() => {
1085
+ this.selectedParticipantLookup = null;
1086
+ });
860
1087
  }
861
1088
  onRemoveParticipant(participant) {
862
1089
  this.addedParticipants = this.addedParticipants.filter(p => !(p.id === participant.id && p.origin === participant.origin));
863
1090
  }
864
- getOriginLabel(origin) {
865
- switch (origin) {
866
- case 'ACCOUNT': return this.t.translate('crmx.schedule.participant_account');
867
- case 'ACCOUNT_CONTACT': return this.t.translate('crmx.schedule.participant_account_contact');
868
- case 'COLLABORATOR': return this.t.translate('crmx.schedule.participant_collaborator');
869
- case 'EXTERNAL_PARTICIPANT': return this.t.translate('crmx.schedule.participant_external');
870
- default: return origin;
871
- }
872
- }
873
- getOriginIcon(origin) {
874
- switch (origin) {
875
- case 'ACCOUNT': return 'pi pi-building';
876
- case 'ACCOUNT_CONTACT': return 'pi pi-id-card';
877
- case 'COLLABORATOR': return 'pi pi-user';
878
- case 'EXTERNAL_PARTICIPANT': return 'pi pi-user-plus';
879
- default: return 'pi pi-user';
880
- }
881
- }
882
- // Save
883
- handleSave() {
1091
+ /**
1092
+ * S1541: Break onSave into smaller helpers to reduce complexity
1093
+ * S121/S2681: Add braces to all if statements
1094
+ */
1095
+ onSave() {
884
1096
  if (this.scheduleForm.invalid) {
885
1097
  this.scheduleForm.markAllAsTouched();
886
1098
  return;
887
1099
  }
888
- const formValue = this.scheduleForm.value;
1100
+ const payload = this.buildSavePayload();
1101
+ const op = this.isEditing
1102
+ ? this.scheduleService.update(payload['id'], payload)
1103
+ : this.scheduleService.insert(payload);
1104
+ op.pipe(switchMap((result) => this.scheduleService.manageParticipants(this.isEditing ? payload['id'] : result?.['id'], this.buildManageParticipantsPayload()))).subscribe({
1105
+ next: () => {
1106
+ this.visible = false;
1107
+ this.visibleChange.emit(false);
1108
+ this.saved.emit();
1109
+ }
1110
+ });
1111
+ }
1112
+ buildSavePayload() {
889
1113
  const payload = {
890
- ...formValue,
891
- type: formValue.type ? formValue.type : null,
892
- whenOccurs: this.recurrenceDescription || null
1114
+ ...this.scheduleForm.value,
1115
+ type: this.scheduleForm.value.type ?? null,
1116
+ whenOccurs: this.recurrenceDescription ?? null
893
1117
  };
894
- // Format dates and times
895
- if (payload.startDate) {
896
- payload.startDate = this.toDateString(payload.startDate);
897
- }
898
- if (payload.endDate) {
899
- payload.endDate = this.toDateString(payload.endDate);
900
- }
901
- if (payload.startTime) {
902
- payload.startTime = this.toTimeString(payload.startTime);
903
- }
904
- if (payload.endTime) {
905
- payload.endTime = this.toTimeString(payload.endTime);
906
- }
907
- // Clean recurrence fields
908
- if (!payload.withRecurrence) {
909
- payload.endDate = null;
910
- payload.recurrenceInterval = null;
911
- payload.weekDays = null;
912
- payload.repeatWhen = null;
913
- payload.repeatWhenDay = null;
914
- payload.repeatWhenOrdinalWeekDay = null;
915
- payload.repeatWhenWeekMonth = null;
916
- payload.repeatWhenMonth = null;
1118
+ if (payload['startDate']) {
1119
+ payload['startDate'] = toDateString(payload['startDate']);
1120
+ }
1121
+ if (payload['endDate']) {
1122
+ payload['endDate'] = toDateString(payload['endDate']);
1123
+ }
1124
+ if (payload['startTime']) {
1125
+ payload['startTime'] = toTimeString(payload['startTime']);
1126
+ }
1127
+ if (payload['endTime']) {
1128
+ payload['endTime'] = toTimeString(payload['endTime']);
1129
+ }
1130
+ if (!payload['withRecurrence']) {
1131
+ this.clearRecurrencePayload(payload);
917
1132
  }
918
1133
  else {
919
1134
  this.cleanRecurrenceFields(payload);
920
1135
  }
921
- if (payload.allDay) {
922
- payload.startTime = null;
923
- payload.endTime = null;
924
- }
925
- this.onSave.emit({ payload, participants: this.buildManageParticipantsPayload() });
926
- }
927
- cleanRecurrenceFields(payload) {
928
- const rec = payload.recurrence;
929
- if (rec !== ScheduleRecurrence.Weekly) {
930
- payload.weekDays = null;
931
- }
932
- if (rec === ScheduleRecurrence.Daily || rec === ScheduleRecurrence.Weekly) {
933
- payload.repeatWhen = null;
934
- payload.repeatWhenDay = null;
935
- payload.repeatWhenOrdinalWeekDay = null;
936
- payload.repeatWhenWeekMonth = null;
937
- payload.repeatWhenMonth = null;
938
- }
939
- if (rec === ScheduleRecurrence.Monthly) {
940
- payload.repeatWhenMonth = null;
941
- if (payload.repeatWhen === RepeatWhen.InDay) {
942
- payload.repeatWhenOrdinalWeekDay = null;
943
- payload.repeatWhenWeekMonth = null;
944
- }
945
- else {
946
- payload.repeatWhenDay = null;
947
- }
948
- }
949
- if (rec === ScheduleRecurrence.Yearly) {
950
- if (payload.repeatWhen === RepeatWhen.InDay) {
951
- payload.repeatWhenOrdinalWeekDay = null;
952
- payload.repeatWhenWeekMonth = null;
953
- }
954
- else {
955
- payload.repeatWhenDay = null;
956
- }
1136
+ if (payload['allDay']) {
1137
+ payload['startTime'] = null;
1138
+ payload['endTime'] = null;
957
1139
  }
1140
+ return payload;
1141
+ }
1142
+ clearRecurrencePayload(payload) {
1143
+ payload['endDate'] = null;
1144
+ payload['recurrenceInterval'] = null;
1145
+ payload['weekDays'] = null;
1146
+ payload['repeatWhen'] = null;
1147
+ payload['repeatWhenDay'] = null;
1148
+ payload['repeatWhenOrdinalWeekDay'] = null;
1149
+ payload['repeatWhenWeekMonth'] = null;
1150
+ payload['repeatWhenMonth'] = null;
1151
+ }
1152
+ onCancel() {
1153
+ this.visible = false;
1154
+ this.visibleChange.emit(false);
958
1155
  }
959
1156
  buildManageParticipantsPayload() {
960
- const accountsId = [];
961
- const accountContactsId = [];
962
- const collaboratorsId = [];
963
- const externalParticipantsId = [];
1157
+ const a = [];
1158
+ const ac = [];
1159
+ const c = [];
1160
+ const e = [];
964
1161
  for (const p of this.addedParticipants) {
965
- if (p.origin === 'ACCOUNT') {
966
- accountsId.push(p.id);
967
- }
968
- else if (p.origin === 'ACCOUNT_CONTACT') {
969
- accountContactsId.push(p.id);
970
- }
971
- else if (p.origin === 'COLLABORATOR') {
972
- collaboratorsId.push(p.id);
973
- }
974
- else if (p.origin === 'EXTERNAL_PARTICIPANT') {
975
- externalParticipantsId.push(p.id);
1162
+ switch (p.origin) {
1163
+ case 'ACCOUNT': {
1164
+ a.push(p.id);
1165
+ break;
1166
+ }
1167
+ case 'ACCOUNT_CONTACT': {
1168
+ ac.push(p.id);
1169
+ break;
1170
+ }
1171
+ case 'COLLABORATOR': {
1172
+ c.push(p.id);
1173
+ break;
1174
+ }
1175
+ case 'EXTERNAL_PARTICIPANT': {
1176
+ e.push(p.id);
1177
+ break;
1178
+ }
976
1179
  }
977
1180
  }
978
- return { accountsId, accountContactsId, collaboratorsId, externalParticipantsId };
1181
+ return {
1182
+ accountsId: a,
1183
+ accountContactsId: ac,
1184
+ collaboratorsId: c,
1185
+ externalParticipantsId: e
1186
+ };
979
1187
  }
980
- handleCancel() {
981
- this.visible = false;
982
- this.visibleChange.emit(false);
983
- this.onCancel.emit();
1188
+ /**
1189
+ * S1541: Break cleanRecurrenceFields into smaller helpers
1190
+ * S121/S2681: Add braces to all if statements
1191
+ */
1192
+ cleanRecurrenceFields(p) {
1193
+ const r = p['recurrence'];
1194
+ if (r !== ScheduleRecurrence.Weekly) {
1195
+ p['weekDays'] = null;
1196
+ }
1197
+ this.cleanDailyWeeklyFields(p, r);
1198
+ this.cleanMonthlyFields(p, r);
1199
+ this.cleanYearlyFields(p, r);
1200
+ }
1201
+ cleanDailyWeeklyFields(p, r) {
1202
+ if (r === ScheduleRecurrence.Daily ||
1203
+ r === ScheduleRecurrence.Weekly) {
1204
+ p['repeatWhen'] = null;
1205
+ p['repeatWhenDay'] = null;
1206
+ p['repeatWhenOrdinalWeekDay'] = null;
1207
+ p['repeatWhenWeekMonth'] = null;
1208
+ p['repeatWhenMonth'] = null;
1209
+ }
1210
+ }
1211
+ cleanMonthlyFields(p, r) {
1212
+ if (r === ScheduleRecurrence.Monthly) {
1213
+ p['repeatWhenMonth'] = null;
1214
+ this.cleanRepeatWhenFields(p);
1215
+ }
1216
+ }
1217
+ cleanYearlyFields(p, r) {
1218
+ if (r === ScheduleRecurrence.Yearly) {
1219
+ this.cleanRepeatWhenFields(p);
1220
+ }
1221
+ }
1222
+ cleanRepeatWhenFields(p) {
1223
+ if (p['repeatWhen'] === RepeatWhen.InDay) {
1224
+ p['repeatWhenOrdinalWeekDay'] = null;
1225
+ p['repeatWhenWeekMonth'] = null;
1226
+ }
1227
+ else {
1228
+ p['repeatWhenDay'] = null;
1229
+ }
1230
+ }
1231
+ resetRecurrenceDefaults(date) {
1232
+ if (!this.scheduleForm) {
1233
+ return;
1234
+ }
1235
+ const d = date || new Date();
1236
+ this.scheduleForm.patchValue({
1237
+ id: null,
1238
+ recurrence: ScheduleRecurrence.Daily,
1239
+ recurrenceInterval: 1,
1240
+ weekDays: [getCurrentWeekDay(d)],
1241
+ repeatWhen: RepeatWhen.InDay,
1242
+ repeatWhenDay: d.getDate(),
1243
+ repeatWhenOrdinalWeekDay: getOrdinalForDate(d),
1244
+ repeatWhenWeekMonth: getCurrentWeekDay(d),
1245
+ repeatWhenMonth: getCurrentMonth(d)
1246
+ });
984
1247
  }
985
- // Getters for template
986
1248
  get showRecurrenceFields() {
987
1249
  return this.scheduleForm?.get('withRecurrence')?.value === true;
988
1250
  }
@@ -996,135 +1258,53 @@ class ScheduleFormComponent {
996
1258
  return this.currentRecurrence === ScheduleRecurrence.Weekly;
997
1259
  }
998
1260
  get showRepeatWhen() {
999
- return this.currentRecurrence === ScheduleRecurrence.Monthly ||
1000
- this.currentRecurrence === ScheduleRecurrence.Yearly;
1261
+ return (this.currentRecurrence === ScheduleRecurrence.Monthly ||
1262
+ this.currentRecurrence === ScheduleRecurrence.Yearly);
1001
1263
  }
1002
1264
  get showRepeatWhenDay() {
1003
1265
  return this.showRepeatWhen && this.currentRepeatWhen === RepeatWhen.InDay;
1004
1266
  }
1005
1267
  get showOrdinalFields() {
1006
- return this.showRepeatWhen && this.currentRepeatWhen === RepeatWhen.InOrdinalWeekDay;
1268
+ return (this.showRepeatWhen &&
1269
+ this.currentRepeatWhen === RepeatWhen.InOrdinalWeekDay);
1007
1270
  }
1008
1271
  get showMonthField() {
1009
1272
  return this.currentRecurrence === ScheduleRecurrence.Yearly;
1010
1273
  }
1011
- // Helper methods
1012
- formatDate(d) {
1013
- return d.toISOString().split('T')[0];
1014
- }
1015
- toDateString(value) {
1016
- if (!value) {
1017
- return value;
1018
- }
1019
- if (value instanceof Date) {
1020
- return this.formatDate(value);
1021
- }
1022
- const str = String(value);
1023
- return str.length > 10 ? str.substring(0, 10) : str;
1024
- }
1025
- toTimeString(value) {
1026
- if (!value) {
1027
- return value;
1028
- }
1029
- if (value instanceof Date) {
1030
- return `${String(value.getHours()).padStart(2, '0')}:${String(value.getMinutes()).padStart(2, '0')}:00`;
1031
- }
1032
- const str = String(value);
1033
- if (str.includes('T')) {
1034
- const d = new Date(str);
1035
- return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:00`;
1036
- }
1037
- if (str.length === 5) {
1038
- return str + this.TIME_SECONDS_SUFFIX;
1039
- }
1040
- else {
1041
- return str;
1042
- }
1043
- }
1274
+ getOriginLabel(o) { return getOriginLabel(this.t, o); }
1275
+ getOriginIcon(o) { return getOriginIcon(o); }
1276
+ getParticipantName(p) { return getParticipantName(p); }
1277
+ getParticipantType(p) { return getParticipantType(this.t, p); }
1278
+ getParticipantTypeIcon(p) { return getParticipantTypeIcon(p); }
1279
+ getPrioritySeverity(p) { return getPrioritySeverity(p); }
1280
+ getPriorityLabel(p) { return getPriorityLabel(this.t, p); }
1281
+ getConfirmationSeverity(c) { return getConfirmationSeverity(c); }
1282
+ getConfirmationLabel(c) { return getConfirmationLabel(this.t, c); }
1044
1283
  getDefaultStartTime(d) {
1045
- let h = d.getHours();
1046
- let m = d.getMinutes();
1047
- if (m < this.MINUTES_HALF_HOUR) {
1048
- m = this.MINUTES_HALF_HOUR;
1049
- }
1050
- else {
1051
- h += 1;
1052
- m = 0;
1053
- }
1054
- if (h >= this.HOURS_IN_DAY) {
1055
- h = 0;
1056
- }
1057
- return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:00`;
1058
- }
1059
- getDefaultEndTime(startTime) {
1060
- const [hStr, mStr] = startTime.split(':');
1061
- let h = parseInt(hStr, 10);
1062
- let m = parseInt(mStr, 10) + this.MINUTES_HALF_HOUR;
1063
- if (m >= this.MINUTES_IN_HOUR) {
1064
- h += 1;
1065
- m -= this.MINUTES_IN_HOUR;
1066
- }
1067
- if (h >= this.HOURS_IN_DAY) {
1068
- h = 0;
1069
- }
1070
- return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:00`;
1071
- }
1072
- getCurrentWeekDay(d) {
1073
- return [
1074
- WeekDay.Sunday, WeekDay.Monday, WeekDay.Tuesday, WeekDay.Wednesday,
1075
- WeekDay.Thursday, WeekDay.Friday, WeekDay.Saturday
1076
- ][d.getDay()];
1077
- }
1078
- getCurrentMonth(d) {
1079
- return [
1080
- Month.January, Month.February, Month.March, Month.April, Month.May, Month.June,
1081
- Month.July, Month.August, Month.September, Month.October, Month.November, Month.December
1082
- ][d.getMonth()];
1083
- }
1084
- getOrdinalForDate(d) {
1085
- const dayOfMonth = d.getDate();
1086
- const weekNum = Math.ceil(dayOfMonth / this.DAYS_IN_WEEK);
1087
- const lastDay = new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
1088
- const isLast = dayOfMonth + this.DAYS_IN_WEEK > lastDay;
1089
- if (isLast && weekNum >= this.ORDINAL_WEEK_THRESHOLD) {
1090
- return OrdinalWeekDay.Last;
1091
- }
1092
- if (weekNum === 1) {
1093
- return OrdinalWeekDay.First;
1094
- }
1095
- else if (weekNum === 2) {
1096
- return OrdinalWeekDay.Second;
1097
- }
1098
- else if (weekNum === this.WEEK_DAYS_IN_MONTH) {
1099
- return OrdinalWeekDay.Third;
1100
- }
1101
- else if (weekNum === this.ORDINAL_WEEK_THRESHOLD) {
1102
- return OrdinalWeekDay.Fourth;
1103
- }
1104
- else {
1105
- return OrdinalWeekDay.Last;
1106
- }
1284
+ return getDefaultStartTime(d);
1107
1285
  }
1108
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleFormComponent, deps: [{ token: i1$1.FormBuilder }, { token: i2.TranslationService }, { token: ScheduleService }, { token: ScheduleTypeService }], target: i0.ɵɵFactoryTarget.Component });
1109
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ScheduleFormComponent, isStandalone: true, selector: "s-schedule-form", inputs: { visible: "visible", scheduleData: "scheduleData" }, outputs: { visibleChange: "visibleChange", onSave: "onSave", onCancel: "onCancel" }, viewQueries: [{ propertyName: "detailFormComponent", first: true, predicate: ["detailForm"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<p-drawer [(visible)]=\"visible\" position=\"right\" [styleClass]=\"'drawer-style'\" [modal]=\"true\">\n <ng-template pTemplate=\"header\">\n <span class=\"drawer-title\">\n <i class=\"pi pi-calendar\"></i>\n {{ isEditing ? ('crmx.schedule.schedule_edit' | translate) : ('crmx.schedule.schedule_new' | translate) }}\n </span>\n </ng-template>\n\n <div class=\"drawer-layout\">\n <!-- Left: Form -->\n <div class=\"drawer-left\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-info-circle\"></i>\n <span>{{ 'crmx.schedule.schedule_details' | translate }}</span>\n </div>\n <sia-dynamic-form\n #detailForm\n [sections]=\"[{ fields: scheduleDetailFields }]\"\n [entityData]=\"entityDataForForm\"\n [mode]=\"'form'\"\n [showSubmitButton]=\"false\"\n [showCancelButton]=\"false\"\n (formReady)=\"onDetailFormReady($event)\"\n ></sia-dynamic-form>\n </div>\n\n <!-- Right: Recurrence + Participants -->\n <div class=\"drawer-right\">\n <!-- Recurrence Config -->\n <div class=\"drawer-section\" *ngIf=\"showRecurrenceFields\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-replay\"></i>\n <span>{{ 'crmx.schedule.recurrence_config' | translate }}</span>\n </div>\n <form [formGroup]=\"scheduleForm\" class=\"drawer-form\">\n <div class=\"form-row\">\n <div class=\"form-field flex-1\">\n <label for=\"recurrence-select\">\n {{ 'crmx.schedule.recurrence' | translate }}\n </label>\n <p-dropdown \n inputId=\"recurrence-select\"\n formControlName=\"recurrence\" \n [options]=\"recurrenceOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n <div class=\"form-field flex-1\">\n <label for=\"recurrence-interval-input\">\n {{ 'crmx.schedule.recurrence_interval' | translate }}\n </label>\n <p-inputNumber \n inputId=\"recurrence-interval-input\"\n formControlName=\"recurrenceInterval\" \n [min]=\"1\" \n [max]=\"99\" \n class=\"w-full\">\n </p-inputNumber>\n </div>\n </div>\n <div class=\"form-row\" *ngIf=\"showWeekDays\">\n <div class=\"form-field flex-1\">\n <label for=\"week-days-select\">\n {{ 'crmx.schedule.week_days' | translate }}\n </label>\n <p-multiSelect \n inputId=\"week-days-select\"\n formControlName=\"weekDays\" \n [options]=\"weekDayOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n [placeholder]=\"'crmx.schedule.select_week_day' | translate\" \n class=\"w-full\">\n </p-multiSelect>\n </div>\n </div>\n <div class=\"form-row\" *ngIf=\"showRepeatWhen\">\n <div class=\"form-field flex-1\">\n <label for=\"repeat-when-select\">\n {{ 'crmx.schedule.repeat_when' | translate }}\n </label>\n <p-dropdown \n inputId=\"repeat-when-select\"\n formControlName=\"repeatWhen\" \n [options]=\"repeatWhenOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n <div class=\"form-field flex-1\" *ngIf=\"showRepeatWhenDay\">\n <label for=\"repeat-when-day-input\">\n {{ 'crmx.schedule.repeat_when_day' | translate }}\n </label>\n <p-inputNumber \n inputId=\"repeat-when-day-input\"\n formControlName=\"repeatWhenDay\" \n [min]=\"1\" \n [max]=\"31\" \n class=\"w-full\">\n </p-inputNumber>\n </div>\n <div class=\"form-field flex-1\" *ngIf=\"showOrdinalFields\">\n <label for=\"ordinal-week-day-select\">\n {{ 'crmx.schedule.ordinal_week_day' | translate }}\n </label>\n <p-dropdown \n inputId=\"ordinal-week-day-select\"\n formControlName=\"repeatWhenOrdinalWeekDay\" \n [options]=\"ordinalOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n <div class=\"form-field flex-1\" *ngIf=\"showOrdinalFields\">\n <label for=\"week-month-select\">\n {{ 'crmx.schedule.week_month' | translate }}\n </label>\n <p-dropdown \n inputId=\"week-month-select\"\n formControlName=\"repeatWhenWeekMonth\" \n [options]=\"weekDayOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n </div>\n <div class=\"form-row\" *ngIf=\"showMonthField\">\n <div class=\"form-field flex-1\">\n <label for=\"repeat-month-select\">\n {{ 'crmx.schedule.repeat_month' | translate }}\n </label>\n <p-dropdown \n inputId=\"repeat-month-select\"\n formControlName=\"repeatWhenMonth\" \n [options]=\"monthOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n </div>\n </form>\n <div class=\"recurrence-description\" *ngIf=\"recurrenceDescription\">\n <i class=\"pi pi-info-circle\"></i>\n <span>{{ recurrenceDescription }}</span>\n </div>\n </div>\n\n <p-divider></p-divider>\n\n <!-- Participants -->\n <div class=\"drawer-section\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-users\"></i>\n <span>{{ 'crmx.schedule.participants' | translate }}</span>\n </div>\n\n <!-- Autocomplete search -->\n <div class=\"participant-search\">\n <p-autoComplete\n [(ngModel)]=\"selectedParticipantLookup\"\n [suggestions]=\"participantSuggestions\"\n (completeMethod)=\"onSearchParticipants($event)\"\n (onSelect)=\"onSelectParticipant($event.value)\"\n (onFocus)=\"onSearchParticipants({ query: '' })\"\n optionLabel=\"name\"\n [placeholder]=\"'crmx.schedule.search_participant' | translate\"\n [minLength]=\"0\"\n [forceSelection]=\"true\"\n [showClear]=\"true\"\n [fluid]=\"true\"\n >\n <ng-template let-item pTemplate=\"item\">\n <div class=\"participant-suggestion\">\n <i [class]=\"getOriginIcon(item.origin)\"></i>\n <div class=\"participant-suggestion-info\">\n <span class=\"participant-suggestion-name\">{{ item.name }}</span>\n <span class=\"participant-suggestion-detail\" *ngIf=\"item.referenceName\">{{ item.referenceName }}</span>\n </div>\n <span class=\"participant-suggestion-origin\">{{ getOriginLabel(item.origin) }}</span>\n </div>\n </ng-template>\n </p-autoComplete>\n </div>\n\n <sia-loading \n *ngIf=\"participantsLoading\" \n variant=\"dots\" \n color=\"primary\" \n [size]=\"32\" \n padding=\"1.5rem 0\">\n </sia-loading>\n <div *ngIf=\"!participantsLoading && addedParticipants.length === 0\" class=\"participants-empty\">\n <i class=\"pi pi-users\"></i>\n <p>{{ 'crmx.schedule.no_participants' | translate }}</p>\n </div>\n <p-table *ngIf=\"!participantsLoading && addedParticipants.length > 0\" \n [value]=\"addedParticipants\" styleClass=\"p-datatable-sm p-datatable-striped\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"col\">{{ 'crmx.schedule.name' | translate }}</th>\n <th scope=\"col\" class=\"table-header-col\">\n {{ 'crmx.schedule.participant_type' | translate }}\n </th>\n <th scope=\"col\" class=\"table-action-col\"></th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-p>\n <tr>\n <td>\n <div class=\"participant-name-cell\">\n <span>{{ p.name }}</span>\n <span *ngIf=\"p.referenceName\" class=\"participant-reference\">{{ p.referenceName }}</span>\n </div>\n </td>\n <td>\n <div class=\"participant-type-cell\">\n <i [class]=\"getOriginIcon(p.origin)\"></i>\n <span>{{ getOriginLabel(p.origin) }}</span>\n </div>\n </td>\n <td>\n <p-button icon=\"pi pi-trash\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" \n (onClick)=\"onRemoveParticipant(p)\" \n [pTooltip]=\"'crmx.schedule.remove' | translate\" tooltipPosition=\"top\"></p-button>\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n </div>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"drawer-footer\">\n <p-button [label]=\"'crmx.schedule.cancel' | translate\" icon=\"pi pi-times\" \n severity=\"secondary\" [outlined]=\"true\" (onClick)=\"handleCancel()\"></p-button>\n <p-button [label]=\"'crmx.schedule.save' | translate\" icon=\"pi pi-check\" \n (onClick)=\"handleSave()\"></p-button>\n </div>\n </ng-template>\n</p-drawer>\n", styles: [".drawer-title{display:flex;align-items:center;gap:.75rem;font-size:1.15rem;font-weight:600;color:var(--p-text-color)}.drawer-title i{color:var(--p-primary-color)}.drawer-layout{display:flex;gap:0;height:100%}.drawer-left{width:380px;min-width:380px;border-right:1px solid var(--p-surface-200);padding:0 1.5rem 1.5rem 0;overflow-y:auto}.drawer-right{flex:1;padding:0 0 0 1.5rem;overflow-y:auto}.drawer-section-header{display:flex;align-items:center;gap:.5rem;padding-bottom:1rem;margin-bottom:1rem;border-bottom:1px solid var(--p-surface-200);font-weight:600;font-size:.95rem;color:var(--p-text-color)}.drawer-section-header i{color:var(--p-primary-color);font-size:1rem}.drawer-form{display:flex;flex-direction:column;gap:1rem}.drawer-form .form-field{display:flex;flex-direction:column;gap:.375rem}.drawer-form .form-field label{font-weight:500;font-size:.8rem;color:var(--p-text-secondary-color);text-transform:uppercase;letter-spacing:.3px}.drawer-form .form-row{display:flex;gap:1rem}.drawer-form .form-row.checkboxes{gap:2rem;padding:.5rem 0}.drawer-form .form-check{display:flex;align-items:center;gap:.5rem}.drawer-form .form-check label{font-size:.875rem;font-weight:500;margin:0;text-transform:none;letter-spacing:0}.drawer-section{margin-bottom:1.5rem}.recurrence-description{display:flex;align-items:flex-start;gap:.5rem;margin-top:1rem;padding:.75rem 1rem;background:var(--p-primary-50);border-left:3px solid var(--p-primary-color);border-radius:4px;font-size:.85rem;color:var(--p-text-color);line-height:1.4}.recurrence-description i{color:var(--p-primary-color);margin-top:.1rem;flex-shrink:0}.participants-empty{display:flex;flex-direction:column;align-items:center;padding:2rem;text-align:center;color:var(--p-text-secondary-color);border:1px dashed var(--p-surface-300);border-radius:8px}.participants-empty i{font-size:2rem;margin-bottom:.5rem;opacity:.4}.participants-empty p{margin:0}.participant-name-cell{display:flex;align-items:center;gap:.5rem}.participant-name-cell .organizer-tag{font-size:.7rem}.participant-type-cell{display:flex;align-items:center;gap:.5rem;font-size:.85rem;color:var(--p-text-secondary-color)}.participant-type-cell i{font-size:.9rem}.drawer-footer{display:flex;gap:.75rem;justify-content:flex-end}.table-header-col{width:10rem}.table-action-col{width:4rem}@media (max-width: 768px){.drawer-layout{flex-direction:column}.drawer-left{width:100%;min-width:100%;border-right:none;border-bottom:1px solid var(--p-surface-200);padding:0 0 1.5rem}.drawer-right{padding:1.5rem 0 0}}.participant-search{margin-bottom:1rem}.participant-search :host ::ng-deep .p-autocomplete{width:100%;display:flex}.participant-search :host ::ng-deep .p-autocomplete-input{width:100%}.participant-suggestion{display:flex;align-items:center;gap:.75rem;padding:.25rem 0}.participant-suggestion i{font-size:1.1rem;color:var(--p-text-secondary-color)}.participant-suggestion-info{display:flex;flex-direction:column;flex:1;min-width:0}.participant-suggestion-name{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.participant-suggestion-detail{font-size:.8rem;color:var(--p-text-secondary-color)}.participant-suggestion-origin{font-size:.75rem;color:var(--p-text-secondary-color);white-space:nowrap}.participant-reference{font-size:.8rem;color:var(--p-text-secondary-color);margin-left:.25rem}.drawer-style{width:85vw;max-width:1200px}:host-context(.p-dark) .drawer-left{border-color:var(--p-surface-300)}:host-context(.p-dark) .drawer-section-header{border-color:var(--p-surface-300)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i6.Drawer, selector: "p-drawer", inputs: ["appendTo", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "directive", type: i2$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i8.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i9.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i10.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled", "fluid"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i11.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i12.Divider, selector: "p-divider", inputs: ["style", "styleClass", "layout", "type", "align"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i13.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "virtualRowHeight", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i14.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "delay", "style", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "disabled", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "maxlength", "name", "required", "size", "appendTo", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "field", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "itemSize", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "variant", "fluid"], outputs: ["completeMethod", "onSelect", "onUnselect", "onFocus", "onBlur", "onDropdownClick", "onClear", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i15.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: LoadingComponent, selector: "sia-loading", inputs: ["variant", "color", "size", "text", "padding"] }, { kind: "component", type: DynamicFormComponent, selector: "sia-dynamic-form", inputs: ["sections", "entityData", "mode", "displayMode", "visible", "dialogConfig", "drawerConfig", "showSubmitButton", "showCancelButton", "submitButtonLabel", "cancelButtonLabel", "submitButtonIcon", "cancelButtonIcon"], outputs: ["formReady", "formSubmit", "visibleChange", "onCancel", "fieldSave"] }] });
1286
+ getDefaultEndTime(st) {
1287
+ return getDefaultEndTime(st);
1288
+ }
1289
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleFormComponent, deps: [{ token: i1$1.FormBuilder }, { token: ScheduleService }, { token: ScheduleTypeService }, { token: CurrentCollaboratorService }, { token: i5.TranslationService }], target: i0.ɵɵFactoryTarget.Component });
1290
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ScheduleFormComponent, isStandalone: true, selector: "s-schedule-form", inputs: { visible: "visible", selectedDate: "selectedDate" }, outputs: { visibleChange: "visibleChange", saved: "saved" }, viewQueries: [{ propertyName: "detailFormComponent", first: true, predicate: ["detailForm"], descendants: true }], ngImport: i0, template: "<!-- Schedule Drawer -->\n<p-drawer\n [(visible)]=\"visible\"\n position=\"right\"\n styleClass=\"schedule-drawer\"\n [modal]=\"true\"\n (onHide)=\"onCancel()\"\n>\n <ng-template pTemplate=\"header\">\n <span class=\"drawer-title\">\n <i class=\"pi pi-calendar\"></i>\n {{\n isEditing\n ? ('crmx.components.schedule_schedule_edit' | translate)\n : ('crmx.components.schedule_schedule_new' | translate)\n }}\n </span>\n </ng-template>\n\n <div class=\"drawer-layout\" *ngIf=\"scheduleForm\">\n <!-- Left: Form -->\n <div class=\"drawer-left\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-info-circle\"></i>\n <span>\n {{ 'crmx.components.schedule_schedule_details' | translate }}\n </span>\n </div>\n <sia-dynamic-form\n #detailForm\n [sections]=\"[{ fields: scheduleDetailFields }]\"\n [entityData]=\"entityDataForForm\"\n [mode]=\"'form'\"\n [showSubmitButton]=\"false\"\n [showCancelButton]=\"false\"\n (formReady)=\"onDetailFormReady($event)\"\n ></sia-dynamic-form>\n </div>\n\n <!-- Right: Recurrence + Participants -->\n <div class=\"drawer-right\">\n <div\n class=\"drawer-section\"\n *ngIf=\"showRecurrenceFields\"\n >\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-replay\"></i>\n <span>\n {{\n 'crmx.components.schedule_recurrence_config'\n | translate\n }}\n </span>\n </div>\n <form\n [formGroup]=\"scheduleForm\"\n class=\"drawer-form\"\n >\n <div class=\"form-row\">\n <div class=\"form-field flex-1\">\n <label for=\"recurrence\">\n {{ 'crmx.components.schedule_recurrence' | translate }}\n </label>\n <p-dropdown\n id=\"recurrence\"\n formControlName=\"recurrence\"\n [options]=\"recurrenceOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n <div class=\"form-field flex-1\">\n <label for=\"recurrenceInterval\">\n {{\n 'crmx.components.schedule_recurrence_interval'\n | translate\n }}\n </label>\n <p-inputNumber\n id=\"recurrenceInterval\"\n formControlName=\"recurrenceInterval\"\n [min]=\"1\"\n [max]=\"99\"\n class=\"w-full\"\n ></p-inputNumber>\n </div>\n </div>\n <div\n class=\"form-row\"\n *ngIf=\"showWeekDays\"\n >\n <div class=\"form-field flex-1\">\n <label for=\"weekDays\">\n {{ 'crmx.components.schedule_week_days' | translate }}\n </label>\n <p-multiSelect\n id=\"weekDays\"\n formControlName=\"weekDays\"\n [options]=\"weekDayOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"\n 'crmx.components.schedule_select_week_day'\n | translate\n \"\n class=\"w-full\"\n ></p-multiSelect>\n </div>\n </div>\n <div\n class=\"form-row\"\n *ngIf=\"showRepeatWhen\"\n >\n <div class=\"form-field flex-1\">\n <label for=\"repeatWhen\">\n {{\n 'crmx.components.schedule_repeat_when' | translate\n }}\n </label>\n <p-dropdown\n id=\"repeatWhen\"\n formControlName=\"repeatWhen\"\n [options]=\"repeatWhenOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n <div\n class=\"form-field flex-1\"\n *ngIf=\"showRepeatWhenDay\"\n >\n <label for=\"repeatWhenDay\">\n {{\n 'crmx.components.schedule_repeat_when_day'\n | translate\n }}\n </label>\n <p-inputNumber\n id=\"repeatWhenDay\"\n formControlName=\"repeatWhenDay\"\n [min]=\"1\"\n [max]=\"31\"\n class=\"w-full\"\n ></p-inputNumber>\n </div>\n <div\n class=\"form-field flex-1\"\n *ngIf=\"showOrdinalFields\"\n >\n <label for=\"repeatWhenOrdinalWeekDay\">\n {{\n 'crmx.components.schedule_ordinal_week_day'\n | translate\n }}\n </label>\n <p-dropdown\n id=\"repeatWhenOrdinalWeekDay\"\n formControlName=\"repeatWhenOrdinalWeekDay\"\n [options]=\"ordinalOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n <div\n class=\"form-field flex-1\"\n *ngIf=\"showOrdinalFields\"\n >\n <label for=\"repeatWhenWeekMonth\">\n {{\n 'crmx.components.schedule_week_month' | translate\n }}\n </label>\n <p-dropdown\n id=\"repeatWhenWeekMonth\"\n formControlName=\"repeatWhenWeekMonth\"\n [options]=\"weekDayOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n </div>\n <div\n class=\"form-row\"\n *ngIf=\"showMonthField\"\n >\n <div class=\"form-field flex-1\">\n <label for=\"repeatWhenMonth\">\n {{\n 'crmx.components.schedule_repeat_month' | translate\n }}\n </label>\n <p-dropdown\n id=\"repeatWhenMonth\"\n formControlName=\"repeatWhenMonth\"\n [options]=\"monthOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n </div>\n </form>\n <div\n class=\"recurrence-description\"\n *ngIf=\"recurrenceDescription\"\n >\n <i class=\"pi pi-info-circle\"></i>\n <span>{{ recurrenceDescription }}</span>\n </div>\n </div>\n\n <p-divider></p-divider>\n\n <!-- Participants -->\n <div class=\"drawer-section\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-users\"></i>\n <span>\n {{ 'crmx.components.schedule_participants' | translate }}\n </span>\n </div>\n <div class=\"participant-search\">\n <p-autoComplete\n [(ngModel)]=\"selectedParticipantLookup\"\n [ngModelOptions]=\"{standalone: true}\"\n [suggestions]=\"participantSuggestions\"\n (completeMethod)=\"\n onSearchParticipants($event)\n \"\n (onSelect)=\"\n onSelectParticipant($event.value)\n \"\n (onFocus)=\"\n onSearchParticipants({ query: '' })\n \"\n optionLabel=\"name\"\n [placeholder]=\"\n 'crmx.components.schedule_search_participant'\n | translate\n \"\n [minLength]=\"0\"\n [forceSelection]=\"true\"\n [showClear]=\"true\"\n [fluid]=\"true\"\n >\n <ng-template\n let-item\n pTemplate=\"item\"\n >\n <div class=\"participant-suggestion\">\n <i\n [class]=\"getOriginIcon(item.origin)\"\n ></i>\n <div\n class=\"participant-suggestion-info\"\n >\n <span\n class=\"participant-suggestion-name\"\n >\n {{ item.name }}\n </span>\n <span\n class=\"participant-suggestion-detail\"\n *ngIf=\"item.referenceName\"\n >\n {{ item.referenceName }}\n </span>\n </div>\n <span\n class=\"participant-suggestion-origin\"\n >\n {{ getOriginLabel(item.origin) }}\n </span>\n </div>\n </ng-template>\n </p-autoComplete>\n </div>\n <div\n *ngIf=\"\n !participantsLoading &&\n addedParticipants.length === 0\n \"\n class=\"participants-empty\"\n >\n <i class=\"pi pi-users\"></i>\n <p>\n {{\n 'crmx.components.schedule_no_participants'\n | translate\n }}\n </p>\n </div>\n <p-table\n *ngIf=\"\n !participantsLoading &&\n addedParticipants.length > 0\n \"\n [value]=\"addedParticipants\"\n styleClass=\"p-datatable-sm p-datatable-striped\"\n >\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"col\">\n {{ 'crmx.components.schedule_name' | translate }}\n </th>\n <th\n scope=\"col\"\n class=\"col-participant-type\"\n >\n {{\n 'crmx.components.schedule_participant_type'\n | translate\n }}\n </th>\n <th\n scope=\"col\"\n class=\"col-actions\"\n ></th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-p>\n <tr>\n <td>\n <div class=\"participant-name-cell\">\n <span>{{ p.name }}</span>\n <span\n *ngIf=\"p.referenceName\"\n class=\"participant-reference\"\n >\n {{ p.referenceName }}\n </span>\n </div>\n </td>\n <td>\n <div class=\"participant-type-cell\">\n <i\n [class]=\"getOriginIcon(p.origin)\"\n ></i>\n <span>\n {{ getOriginLabel(p.origin) }}\n </span>\n </div>\n </td>\n <td>\n <p-button\n icon=\"pi pi-trash\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"danger\"\n (onClick)=\"onRemoveParticipant(p)\"\n [pTooltip]=\"\n 'crmx.components.schedule_remove' | translate\n \"\n tooltipPosition=\"top\"\n ></p-button>\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n </div>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"drawer-footer\">\n <p-button\n [label]=\"'crmx.components.schedule_cancel' | translate\"\n icon=\"pi pi-times\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (onClick)=\"onCancel()\"\n ></p-button>\n <p-button\n [label]=\"'crmx.components.schedule_save' | translate\"\n icon=\"pi pi-check\"\n (onClick)=\"onSave()\"\n ></p-button>\n </div>\n </ng-template>\n</p-drawer>\n", styles: [":host ::ng-deep .schedule-drawer{width:85vw;max-width:1200px}.col-participant-type{width:10rem}.col-actions{width:4rem}.drawer-title{display:flex;align-items:center;gap:.75rem;font-size:1.15rem;font-weight:600;color:var(--p-text-color)}.drawer-title i{color:var(--p-primary-color)}.drawer-layout{display:flex;gap:0;height:100%}.drawer-left{width:380px;min-width:380px;border-right:1px solid var(--p-surface-200);padding:0 1.5rem 1.5rem 0;overflow-y:auto}.drawer-right{flex:1;padding:0 0 0 1.5rem;overflow-y:auto}.drawer-section-header{display:flex;align-items:center;gap:.5rem;padding-bottom:1rem;margin-bottom:1rem;border-bottom:1px solid var(--p-surface-200);font-weight:600;font-size:.95rem;color:var(--p-text-color)}.drawer-section-header i{color:var(--p-primary-color);font-size:1rem}.drawer-form{display:flex;flex-direction:column;gap:1rem}.drawer-form .form-field{display:flex;flex-direction:column;gap:.375rem}.drawer-form .form-field label{font-weight:500;font-size:.8rem;color:var(--p-text-secondary-color);text-transform:uppercase;letter-spacing:.3px}.drawer-form .form-row{display:flex;gap:1rem}.drawer-form .form-row.checkboxes{gap:2rem;padding:.5rem 0}.drawer-form .form-check{display:flex;align-items:center;gap:.5rem}.drawer-form .form-check label{font-size:.875rem;font-weight:500;margin:0;text-transform:none;letter-spacing:0}.drawer-section{margin-bottom:1.5rem}.recurrence-description{display:flex;align-items:flex-start;gap:.5rem;margin-top:1rem;padding:.75rem 1rem;background:var(--p-primary-50);border-left:3px solid var(--p-primary-color);border-radius:4px;font-size:.85rem;color:var(--p-text-color);line-height:1.4}.recurrence-description i{color:var(--p-primary-color);margin-top:.1rem;flex-shrink:0}.participants-empty{display:flex;flex-direction:column;align-items:center;padding:2rem;text-align:center;color:var(--p-text-secondary-color);border:1px dashed var(--p-surface-300);border-radius:8px}.participants-empty i{font-size:2rem;margin-bottom:.5rem;opacity:.4}.participants-empty p{margin:0}.participant-name-cell{display:flex;align-items:center;gap:.5rem}.participant-type-cell{display:flex;align-items:center;gap:.5rem;font-size:.85rem;color:var(--p-text-secondary-color)}.participant-type-cell i{font-size:.9rem}.drawer-footer{display:flex;gap:.75rem;justify-content:flex-end}.participant-search{margin-bottom:1rem}.participant-search :host ::ng-deep .p-autocomplete{width:100%;display:flex}.participant-search :host ::ng-deep .p-autocomplete-input{width:100%}.participant-suggestion{display:flex;align-items:center;gap:.75rem;padding:.25rem 0}.participant-suggestion i{font-size:1.1rem;color:var(--p-text-secondary-color)}.participant-suggestion-info{display:flex;flex-direction:column;flex:1;min-width:0}.participant-suggestion-name{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.participant-suggestion-detail{font-size:.8rem;color:var(--p-text-secondary-color)}.participant-suggestion-origin{font-size:.75rem;color:var(--p-text-secondary-color);white-space:nowrap}.participant-reference{font-size:.8rem;color:var(--p-text-secondary-color);margin-left:.25rem}.detail-dialog-body{display:flex;flex-direction:column;gap:.5rem}.detail-dialog-row{display:flex;align-items:center;gap:.75rem;padding:.4rem 0}.detail-label{font-weight:500;color:var(--p-text-secondary-color);min-width:8rem}@media (max-width: 768px){.drawer-layout{flex-direction:column}.drawer-left{width:100%;min-width:100%;border-right:none;border-bottom:1px solid var(--p-surface-200);padding:0 0 1.5rem}.drawer-right{padding:1.5rem 0 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i7.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i8.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i9.Drawer, selector: "p-drawer", inputs: ["appendTo", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i10.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i11.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled", "fluid"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i12.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: TagModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i13.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i14.Divider, selector: "p-divider", inputs: ["style", "styleClass", "layout", "type", "align"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i15.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "virtualRowHeight", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i16.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "delay", "style", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "disabled", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "maxlength", "name", "required", "size", "appendTo", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "field", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "itemSize", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "variant", "fluid"], outputs: ["completeMethod", "onSelect", "onUnselect", "onFocus", "onBlur", "onDropdownClick", "onClear", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: DynamicFormComponent, selector: "sia-dynamic-form", inputs: ["sections", "entityData", "mode", "displayMode", "visible", "dialogConfig", "drawerConfig", "showSubmitButton", "showCancelButton", "submitButtonLabel", "cancelButtonLabel", "submitButtonIcon", "cancelButtonIcon"], outputs: ["formReady", "formSubmit", "visibleChange", "onCancel", "fieldSave"] }] });
1110
1291
  }
1111
1292
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleFormComponent, decorators: [{
1112
1293
  type: Component,
1113
1294
  args: [{ selector: 's-schedule-form', standalone: true, imports: [
1114
1295
  CommonModule, FormsModule, ReactiveFormsModule,
1115
- DrawerModule, ButtonModule, DropdownModule, InputNumberModule,
1116
- MultiSelectModule, DividerModule, TableModule, AutoCompleteModule,
1117
- TooltipModule, TranslatePipe, LoadingComponent, DynamicFormComponent
1118
- ], template: "<p-drawer [(visible)]=\"visible\" position=\"right\" [styleClass]=\"'drawer-style'\" [modal]=\"true\">\n <ng-template pTemplate=\"header\">\n <span class=\"drawer-title\">\n <i class=\"pi pi-calendar\"></i>\n {{ isEditing ? ('crmx.schedule.schedule_edit' | translate) : ('crmx.schedule.schedule_new' | translate) }}\n </span>\n </ng-template>\n\n <div class=\"drawer-layout\">\n <!-- Left: Form -->\n <div class=\"drawer-left\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-info-circle\"></i>\n <span>{{ 'crmx.schedule.schedule_details' | translate }}</span>\n </div>\n <sia-dynamic-form\n #detailForm\n [sections]=\"[{ fields: scheduleDetailFields }]\"\n [entityData]=\"entityDataForForm\"\n [mode]=\"'form'\"\n [showSubmitButton]=\"false\"\n [showCancelButton]=\"false\"\n (formReady)=\"onDetailFormReady($event)\"\n ></sia-dynamic-form>\n </div>\n\n <!-- Right: Recurrence + Participants -->\n <div class=\"drawer-right\">\n <!-- Recurrence Config -->\n <div class=\"drawer-section\" *ngIf=\"showRecurrenceFields\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-replay\"></i>\n <span>{{ 'crmx.schedule.recurrence_config' | translate }}</span>\n </div>\n <form [formGroup]=\"scheduleForm\" class=\"drawer-form\">\n <div class=\"form-row\">\n <div class=\"form-field flex-1\">\n <label for=\"recurrence-select\">\n {{ 'crmx.schedule.recurrence' | translate }}\n </label>\n <p-dropdown \n inputId=\"recurrence-select\"\n formControlName=\"recurrence\" \n [options]=\"recurrenceOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n <div class=\"form-field flex-1\">\n <label for=\"recurrence-interval-input\">\n {{ 'crmx.schedule.recurrence_interval' | translate }}\n </label>\n <p-inputNumber \n inputId=\"recurrence-interval-input\"\n formControlName=\"recurrenceInterval\" \n [min]=\"1\" \n [max]=\"99\" \n class=\"w-full\">\n </p-inputNumber>\n </div>\n </div>\n <div class=\"form-row\" *ngIf=\"showWeekDays\">\n <div class=\"form-field flex-1\">\n <label for=\"week-days-select\">\n {{ 'crmx.schedule.week_days' | translate }}\n </label>\n <p-multiSelect \n inputId=\"week-days-select\"\n formControlName=\"weekDays\" \n [options]=\"weekDayOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n [placeholder]=\"'crmx.schedule.select_week_day' | translate\" \n class=\"w-full\">\n </p-multiSelect>\n </div>\n </div>\n <div class=\"form-row\" *ngIf=\"showRepeatWhen\">\n <div class=\"form-field flex-1\">\n <label for=\"repeat-when-select\">\n {{ 'crmx.schedule.repeat_when' | translate }}\n </label>\n <p-dropdown \n inputId=\"repeat-when-select\"\n formControlName=\"repeatWhen\" \n [options]=\"repeatWhenOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n <div class=\"form-field flex-1\" *ngIf=\"showRepeatWhenDay\">\n <label for=\"repeat-when-day-input\">\n {{ 'crmx.schedule.repeat_when_day' | translate }}\n </label>\n <p-inputNumber \n inputId=\"repeat-when-day-input\"\n formControlName=\"repeatWhenDay\" \n [min]=\"1\" \n [max]=\"31\" \n class=\"w-full\">\n </p-inputNumber>\n </div>\n <div class=\"form-field flex-1\" *ngIf=\"showOrdinalFields\">\n <label for=\"ordinal-week-day-select\">\n {{ 'crmx.schedule.ordinal_week_day' | translate }}\n </label>\n <p-dropdown \n inputId=\"ordinal-week-day-select\"\n formControlName=\"repeatWhenOrdinalWeekDay\" \n [options]=\"ordinalOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n <div class=\"form-field flex-1\" *ngIf=\"showOrdinalFields\">\n <label for=\"week-month-select\">\n {{ 'crmx.schedule.week_month' | translate }}\n </label>\n <p-dropdown \n inputId=\"week-month-select\"\n formControlName=\"repeatWhenWeekMonth\" \n [options]=\"weekDayOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n </div>\n <div class=\"form-row\" *ngIf=\"showMonthField\">\n <div class=\"form-field flex-1\">\n <label for=\"repeat-month-select\">\n {{ 'crmx.schedule.repeat_month' | translate }}\n </label>\n <p-dropdown \n inputId=\"repeat-month-select\"\n formControlName=\"repeatWhenMonth\" \n [options]=\"monthOptions\" \n optionLabel=\"label\" \n optionValue=\"value\" \n class=\"w-full\">\n </p-dropdown>\n </div>\n </div>\n </form>\n <div class=\"recurrence-description\" *ngIf=\"recurrenceDescription\">\n <i class=\"pi pi-info-circle\"></i>\n <span>{{ recurrenceDescription }}</span>\n </div>\n </div>\n\n <p-divider></p-divider>\n\n <!-- Participants -->\n <div class=\"drawer-section\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-users\"></i>\n <span>{{ 'crmx.schedule.participants' | translate }}</span>\n </div>\n\n <!-- Autocomplete search -->\n <div class=\"participant-search\">\n <p-autoComplete\n [(ngModel)]=\"selectedParticipantLookup\"\n [suggestions]=\"participantSuggestions\"\n (completeMethod)=\"onSearchParticipants($event)\"\n (onSelect)=\"onSelectParticipant($event.value)\"\n (onFocus)=\"onSearchParticipants({ query: '' })\"\n optionLabel=\"name\"\n [placeholder]=\"'crmx.schedule.search_participant' | translate\"\n [minLength]=\"0\"\n [forceSelection]=\"true\"\n [showClear]=\"true\"\n [fluid]=\"true\"\n >\n <ng-template let-item pTemplate=\"item\">\n <div class=\"participant-suggestion\">\n <i [class]=\"getOriginIcon(item.origin)\"></i>\n <div class=\"participant-suggestion-info\">\n <span class=\"participant-suggestion-name\">{{ item.name }}</span>\n <span class=\"participant-suggestion-detail\" *ngIf=\"item.referenceName\">{{ item.referenceName }}</span>\n </div>\n <span class=\"participant-suggestion-origin\">{{ getOriginLabel(item.origin) }}</span>\n </div>\n </ng-template>\n </p-autoComplete>\n </div>\n\n <sia-loading \n *ngIf=\"participantsLoading\" \n variant=\"dots\" \n color=\"primary\" \n [size]=\"32\" \n padding=\"1.5rem 0\">\n </sia-loading>\n <div *ngIf=\"!participantsLoading && addedParticipants.length === 0\" class=\"participants-empty\">\n <i class=\"pi pi-users\"></i>\n <p>{{ 'crmx.schedule.no_participants' | translate }}</p>\n </div>\n <p-table *ngIf=\"!participantsLoading && addedParticipants.length > 0\" \n [value]=\"addedParticipants\" styleClass=\"p-datatable-sm p-datatable-striped\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"col\">{{ 'crmx.schedule.name' | translate }}</th>\n <th scope=\"col\" class=\"table-header-col\">\n {{ 'crmx.schedule.participant_type' | translate }}\n </th>\n <th scope=\"col\" class=\"table-action-col\"></th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-p>\n <tr>\n <td>\n <div class=\"participant-name-cell\">\n <span>{{ p.name }}</span>\n <span *ngIf=\"p.referenceName\" class=\"participant-reference\">{{ p.referenceName }}</span>\n </div>\n </td>\n <td>\n <div class=\"participant-type-cell\">\n <i [class]=\"getOriginIcon(p.origin)\"></i>\n <span>{{ getOriginLabel(p.origin) }}</span>\n </div>\n </td>\n <td>\n <p-button icon=\"pi pi-trash\" [rounded]=\"true\" [text]=\"true\" severity=\"danger\" \n (onClick)=\"onRemoveParticipant(p)\" \n [pTooltip]=\"'crmx.schedule.remove' | translate\" tooltipPosition=\"top\"></p-button>\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n </div>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"drawer-footer\">\n <p-button [label]=\"'crmx.schedule.cancel' | translate\" icon=\"pi pi-times\" \n severity=\"secondary\" [outlined]=\"true\" (onClick)=\"handleCancel()\"></p-button>\n <p-button [label]=\"'crmx.schedule.save' | translate\" icon=\"pi pi-check\" \n (onClick)=\"handleSave()\"></p-button>\n </div>\n </ng-template>\n</p-drawer>\n", styles: [".drawer-title{display:flex;align-items:center;gap:.75rem;font-size:1.15rem;font-weight:600;color:var(--p-text-color)}.drawer-title i{color:var(--p-primary-color)}.drawer-layout{display:flex;gap:0;height:100%}.drawer-left{width:380px;min-width:380px;border-right:1px solid var(--p-surface-200);padding:0 1.5rem 1.5rem 0;overflow-y:auto}.drawer-right{flex:1;padding:0 0 0 1.5rem;overflow-y:auto}.drawer-section-header{display:flex;align-items:center;gap:.5rem;padding-bottom:1rem;margin-bottom:1rem;border-bottom:1px solid var(--p-surface-200);font-weight:600;font-size:.95rem;color:var(--p-text-color)}.drawer-section-header i{color:var(--p-primary-color);font-size:1rem}.drawer-form{display:flex;flex-direction:column;gap:1rem}.drawer-form .form-field{display:flex;flex-direction:column;gap:.375rem}.drawer-form .form-field label{font-weight:500;font-size:.8rem;color:var(--p-text-secondary-color);text-transform:uppercase;letter-spacing:.3px}.drawer-form .form-row{display:flex;gap:1rem}.drawer-form .form-row.checkboxes{gap:2rem;padding:.5rem 0}.drawer-form .form-check{display:flex;align-items:center;gap:.5rem}.drawer-form .form-check label{font-size:.875rem;font-weight:500;margin:0;text-transform:none;letter-spacing:0}.drawer-section{margin-bottom:1.5rem}.recurrence-description{display:flex;align-items:flex-start;gap:.5rem;margin-top:1rem;padding:.75rem 1rem;background:var(--p-primary-50);border-left:3px solid var(--p-primary-color);border-radius:4px;font-size:.85rem;color:var(--p-text-color);line-height:1.4}.recurrence-description i{color:var(--p-primary-color);margin-top:.1rem;flex-shrink:0}.participants-empty{display:flex;flex-direction:column;align-items:center;padding:2rem;text-align:center;color:var(--p-text-secondary-color);border:1px dashed var(--p-surface-300);border-radius:8px}.participants-empty i{font-size:2rem;margin-bottom:.5rem;opacity:.4}.participants-empty p{margin:0}.participant-name-cell{display:flex;align-items:center;gap:.5rem}.participant-name-cell .organizer-tag{font-size:.7rem}.participant-type-cell{display:flex;align-items:center;gap:.5rem;font-size:.85rem;color:var(--p-text-secondary-color)}.participant-type-cell i{font-size:.9rem}.drawer-footer{display:flex;gap:.75rem;justify-content:flex-end}.table-header-col{width:10rem}.table-action-col{width:4rem}@media (max-width: 768px){.drawer-layout{flex-direction:column}.drawer-left{width:100%;min-width:100%;border-right:none;border-bottom:1px solid var(--p-surface-200);padding:0 0 1.5rem}.drawer-right{padding:1.5rem 0 0}}.participant-search{margin-bottom:1rem}.participant-search :host ::ng-deep .p-autocomplete{width:100%;display:flex}.participant-search :host ::ng-deep .p-autocomplete-input{width:100%}.participant-suggestion{display:flex;align-items:center;gap:.75rem;padding:.25rem 0}.participant-suggestion i{font-size:1.1rem;color:var(--p-text-secondary-color)}.participant-suggestion-info{display:flex;flex-direction:column;flex:1;min-width:0}.participant-suggestion-name{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.participant-suggestion-detail{font-size:.8rem;color:var(--p-text-secondary-color)}.participant-suggestion-origin{font-size:.75rem;color:var(--p-text-secondary-color);white-space:nowrap}.participant-reference{font-size:.8rem;color:var(--p-text-secondary-color);margin-left:.25rem}.drawer-style{width:85vw;max-width:1200px}:host-context(.p-dark) .drawer-left{border-color:var(--p-surface-300)}:host-context(.p-dark) .drawer-section-header{border-color:var(--p-surface-300)}\n"] }]
1119
- }], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: i2.TranslationService }, { type: ScheduleService }, { type: ScheduleTypeService }], propDecorators: { visible: [{
1296
+ ButtonModule, DialogModule, DrawerModule, DropdownModule,
1297
+ InputNumberModule, MultiSelectModule, TagModule, TooltipModule,
1298
+ DividerModule, TableModule, AutoCompleteModule,
1299
+ TranslatePipe, DynamicFormComponent
1300
+ ], template: "<!-- Schedule Drawer -->\n<p-drawer\n [(visible)]=\"visible\"\n position=\"right\"\n styleClass=\"schedule-drawer\"\n [modal]=\"true\"\n (onHide)=\"onCancel()\"\n>\n <ng-template pTemplate=\"header\">\n <span class=\"drawer-title\">\n <i class=\"pi pi-calendar\"></i>\n {{\n isEditing\n ? ('crmx.components.schedule_schedule_edit' | translate)\n : ('crmx.components.schedule_schedule_new' | translate)\n }}\n </span>\n </ng-template>\n\n <div class=\"drawer-layout\" *ngIf=\"scheduleForm\">\n <!-- Left: Form -->\n <div class=\"drawer-left\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-info-circle\"></i>\n <span>\n {{ 'crmx.components.schedule_schedule_details' | translate }}\n </span>\n </div>\n <sia-dynamic-form\n #detailForm\n [sections]=\"[{ fields: scheduleDetailFields }]\"\n [entityData]=\"entityDataForForm\"\n [mode]=\"'form'\"\n [showSubmitButton]=\"false\"\n [showCancelButton]=\"false\"\n (formReady)=\"onDetailFormReady($event)\"\n ></sia-dynamic-form>\n </div>\n\n <!-- Right: Recurrence + Participants -->\n <div class=\"drawer-right\">\n <div\n class=\"drawer-section\"\n *ngIf=\"showRecurrenceFields\"\n >\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-replay\"></i>\n <span>\n {{\n 'crmx.components.schedule_recurrence_config'\n | translate\n }}\n </span>\n </div>\n <form\n [formGroup]=\"scheduleForm\"\n class=\"drawer-form\"\n >\n <div class=\"form-row\">\n <div class=\"form-field flex-1\">\n <label for=\"recurrence\">\n {{ 'crmx.components.schedule_recurrence' | translate }}\n </label>\n <p-dropdown\n id=\"recurrence\"\n formControlName=\"recurrence\"\n [options]=\"recurrenceOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n <div class=\"form-field flex-1\">\n <label for=\"recurrenceInterval\">\n {{\n 'crmx.components.schedule_recurrence_interval'\n | translate\n }}\n </label>\n <p-inputNumber\n id=\"recurrenceInterval\"\n formControlName=\"recurrenceInterval\"\n [min]=\"1\"\n [max]=\"99\"\n class=\"w-full\"\n ></p-inputNumber>\n </div>\n </div>\n <div\n class=\"form-row\"\n *ngIf=\"showWeekDays\"\n >\n <div class=\"form-field flex-1\">\n <label for=\"weekDays\">\n {{ 'crmx.components.schedule_week_days' | translate }}\n </label>\n <p-multiSelect\n id=\"weekDays\"\n formControlName=\"weekDays\"\n [options]=\"weekDayOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"\n 'crmx.components.schedule_select_week_day'\n | translate\n \"\n class=\"w-full\"\n ></p-multiSelect>\n </div>\n </div>\n <div\n class=\"form-row\"\n *ngIf=\"showRepeatWhen\"\n >\n <div class=\"form-field flex-1\">\n <label for=\"repeatWhen\">\n {{\n 'crmx.components.schedule_repeat_when' | translate\n }}\n </label>\n <p-dropdown\n id=\"repeatWhen\"\n formControlName=\"repeatWhen\"\n [options]=\"repeatWhenOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n <div\n class=\"form-field flex-1\"\n *ngIf=\"showRepeatWhenDay\"\n >\n <label for=\"repeatWhenDay\">\n {{\n 'crmx.components.schedule_repeat_when_day'\n | translate\n }}\n </label>\n <p-inputNumber\n id=\"repeatWhenDay\"\n formControlName=\"repeatWhenDay\"\n [min]=\"1\"\n [max]=\"31\"\n class=\"w-full\"\n ></p-inputNumber>\n </div>\n <div\n class=\"form-field flex-1\"\n *ngIf=\"showOrdinalFields\"\n >\n <label for=\"repeatWhenOrdinalWeekDay\">\n {{\n 'crmx.components.schedule_ordinal_week_day'\n | translate\n }}\n </label>\n <p-dropdown\n id=\"repeatWhenOrdinalWeekDay\"\n formControlName=\"repeatWhenOrdinalWeekDay\"\n [options]=\"ordinalOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n <div\n class=\"form-field flex-1\"\n *ngIf=\"showOrdinalFields\"\n >\n <label for=\"repeatWhenWeekMonth\">\n {{\n 'crmx.components.schedule_week_month' | translate\n }}\n </label>\n <p-dropdown\n id=\"repeatWhenWeekMonth\"\n formControlName=\"repeatWhenWeekMonth\"\n [options]=\"weekDayOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n </div>\n <div\n class=\"form-row\"\n *ngIf=\"showMonthField\"\n >\n <div class=\"form-field flex-1\">\n <label for=\"repeatWhenMonth\">\n {{\n 'crmx.components.schedule_repeat_month' | translate\n }}\n </label>\n <p-dropdown\n id=\"repeatWhenMonth\"\n formControlName=\"repeatWhenMonth\"\n [options]=\"monthOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n </div>\n </form>\n <div\n class=\"recurrence-description\"\n *ngIf=\"recurrenceDescription\"\n >\n <i class=\"pi pi-info-circle\"></i>\n <span>{{ recurrenceDescription }}</span>\n </div>\n </div>\n\n <p-divider></p-divider>\n\n <!-- Participants -->\n <div class=\"drawer-section\">\n <div class=\"drawer-section-header\">\n <i class=\"pi pi-users\"></i>\n <span>\n {{ 'crmx.components.schedule_participants' | translate }}\n </span>\n </div>\n <div class=\"participant-search\">\n <p-autoComplete\n [(ngModel)]=\"selectedParticipantLookup\"\n [ngModelOptions]=\"{standalone: true}\"\n [suggestions]=\"participantSuggestions\"\n (completeMethod)=\"\n onSearchParticipants($event)\n \"\n (onSelect)=\"\n onSelectParticipant($event.value)\n \"\n (onFocus)=\"\n onSearchParticipants({ query: '' })\n \"\n optionLabel=\"name\"\n [placeholder]=\"\n 'crmx.components.schedule_search_participant'\n | translate\n \"\n [minLength]=\"0\"\n [forceSelection]=\"true\"\n [showClear]=\"true\"\n [fluid]=\"true\"\n >\n <ng-template\n let-item\n pTemplate=\"item\"\n >\n <div class=\"participant-suggestion\">\n <i\n [class]=\"getOriginIcon(item.origin)\"\n ></i>\n <div\n class=\"participant-suggestion-info\"\n >\n <span\n class=\"participant-suggestion-name\"\n >\n {{ item.name }}\n </span>\n <span\n class=\"participant-suggestion-detail\"\n *ngIf=\"item.referenceName\"\n >\n {{ item.referenceName }}\n </span>\n </div>\n <span\n class=\"participant-suggestion-origin\"\n >\n {{ getOriginLabel(item.origin) }}\n </span>\n </div>\n </ng-template>\n </p-autoComplete>\n </div>\n <div\n *ngIf=\"\n !participantsLoading &&\n addedParticipants.length === 0\n \"\n class=\"participants-empty\"\n >\n <i class=\"pi pi-users\"></i>\n <p>\n {{\n 'crmx.components.schedule_no_participants'\n | translate\n }}\n </p>\n </div>\n <p-table\n *ngIf=\"\n !participantsLoading &&\n addedParticipants.length > 0\n \"\n [value]=\"addedParticipants\"\n styleClass=\"p-datatable-sm p-datatable-striped\"\n >\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"col\">\n {{ 'crmx.components.schedule_name' | translate }}\n </th>\n <th\n scope=\"col\"\n class=\"col-participant-type\"\n >\n {{\n 'crmx.components.schedule_participant_type'\n | translate\n }}\n </th>\n <th\n scope=\"col\"\n class=\"col-actions\"\n ></th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-p>\n <tr>\n <td>\n <div class=\"participant-name-cell\">\n <span>{{ p.name }}</span>\n <span\n *ngIf=\"p.referenceName\"\n class=\"participant-reference\"\n >\n {{ p.referenceName }}\n </span>\n </div>\n </td>\n <td>\n <div class=\"participant-type-cell\">\n <i\n [class]=\"getOriginIcon(p.origin)\"\n ></i>\n <span>\n {{ getOriginLabel(p.origin) }}\n </span>\n </div>\n </td>\n <td>\n <p-button\n icon=\"pi pi-trash\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"danger\"\n (onClick)=\"onRemoveParticipant(p)\"\n [pTooltip]=\"\n 'crmx.components.schedule_remove' | translate\n \"\n tooltipPosition=\"top\"\n ></p-button>\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n </div>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"drawer-footer\">\n <p-button\n [label]=\"'crmx.components.schedule_cancel' | translate\"\n icon=\"pi pi-times\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (onClick)=\"onCancel()\"\n ></p-button>\n <p-button\n [label]=\"'crmx.components.schedule_save' | translate\"\n icon=\"pi pi-check\"\n (onClick)=\"onSave()\"\n ></p-button>\n </div>\n </ng-template>\n</p-drawer>\n", styles: [":host ::ng-deep .schedule-drawer{width:85vw;max-width:1200px}.col-participant-type{width:10rem}.col-actions{width:4rem}.drawer-title{display:flex;align-items:center;gap:.75rem;font-size:1.15rem;font-weight:600;color:var(--p-text-color)}.drawer-title i{color:var(--p-primary-color)}.drawer-layout{display:flex;gap:0;height:100%}.drawer-left{width:380px;min-width:380px;border-right:1px solid var(--p-surface-200);padding:0 1.5rem 1.5rem 0;overflow-y:auto}.drawer-right{flex:1;padding:0 0 0 1.5rem;overflow-y:auto}.drawer-section-header{display:flex;align-items:center;gap:.5rem;padding-bottom:1rem;margin-bottom:1rem;border-bottom:1px solid var(--p-surface-200);font-weight:600;font-size:.95rem;color:var(--p-text-color)}.drawer-section-header i{color:var(--p-primary-color);font-size:1rem}.drawer-form{display:flex;flex-direction:column;gap:1rem}.drawer-form .form-field{display:flex;flex-direction:column;gap:.375rem}.drawer-form .form-field label{font-weight:500;font-size:.8rem;color:var(--p-text-secondary-color);text-transform:uppercase;letter-spacing:.3px}.drawer-form .form-row{display:flex;gap:1rem}.drawer-form .form-row.checkboxes{gap:2rem;padding:.5rem 0}.drawer-form .form-check{display:flex;align-items:center;gap:.5rem}.drawer-form .form-check label{font-size:.875rem;font-weight:500;margin:0;text-transform:none;letter-spacing:0}.drawer-section{margin-bottom:1.5rem}.recurrence-description{display:flex;align-items:flex-start;gap:.5rem;margin-top:1rem;padding:.75rem 1rem;background:var(--p-primary-50);border-left:3px solid var(--p-primary-color);border-radius:4px;font-size:.85rem;color:var(--p-text-color);line-height:1.4}.recurrence-description i{color:var(--p-primary-color);margin-top:.1rem;flex-shrink:0}.participants-empty{display:flex;flex-direction:column;align-items:center;padding:2rem;text-align:center;color:var(--p-text-secondary-color);border:1px dashed var(--p-surface-300);border-radius:8px}.participants-empty i{font-size:2rem;margin-bottom:.5rem;opacity:.4}.participants-empty p{margin:0}.participant-name-cell{display:flex;align-items:center;gap:.5rem}.participant-type-cell{display:flex;align-items:center;gap:.5rem;font-size:.85rem;color:var(--p-text-secondary-color)}.participant-type-cell i{font-size:.9rem}.drawer-footer{display:flex;gap:.75rem;justify-content:flex-end}.participant-search{margin-bottom:1rem}.participant-search :host ::ng-deep .p-autocomplete{width:100%;display:flex}.participant-search :host ::ng-deep .p-autocomplete-input{width:100%}.participant-suggestion{display:flex;align-items:center;gap:.75rem;padding:.25rem 0}.participant-suggestion i{font-size:1.1rem;color:var(--p-text-secondary-color)}.participant-suggestion-info{display:flex;flex-direction:column;flex:1;min-width:0}.participant-suggestion-name{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.participant-suggestion-detail{font-size:.8rem;color:var(--p-text-secondary-color)}.participant-suggestion-origin{font-size:.75rem;color:var(--p-text-secondary-color);white-space:nowrap}.participant-reference{font-size:.8rem;color:var(--p-text-secondary-color);margin-left:.25rem}.detail-dialog-body{display:flex;flex-direction:column;gap:.5rem}.detail-dialog-row{display:flex;align-items:center;gap:.75rem;padding:.4rem 0}.detail-label{font-weight:500;color:var(--p-text-secondary-color);min-width:8rem}@media (max-width: 768px){.drawer-layout{flex-direction:column}.drawer-left{width:100%;min-width:100%;border-right:none;border-bottom:1px solid var(--p-surface-200);padding:0 0 1.5rem}.drawer-right{padding:1.5rem 0 0}}\n"] }]
1301
+ }], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: ScheduleService }, { type: ScheduleTypeService }, { type: CurrentCollaboratorService }, { type: i5.TranslationService }], propDecorators: { visible: [{
1120
1302
  type: Input
1121
- }], scheduleData: [{
1303
+ }], selectedDate: [{
1122
1304
  type: Input
1123
1305
  }], visibleChange: [{
1124
1306
  type: Output
1125
- }], onSave: [{
1126
- type: Output
1127
- }], onCancel: [{
1307
+ }], saved: [{
1128
1308
  type: Output
1129
1309
  }], detailFormComponent: [{
1130
1310
  type: ViewChild,
@@ -1132,189 +1312,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1132
1312
  }] } });
1133
1313
 
1134
1314
  class ScheduleDetailComponent {
1315
+ scheduleService;
1135
1316
  t;
1136
- confirmationService;
1137
1317
  visible = false;
1138
- schedule = null;
1139
- showAcceptButton = false;
1140
- showRejectButton = false;
1141
- showCancelButton = false;
1142
- showEditButton = true;
1143
- showDeleteButton = false;
1144
1318
  visibleChange = new EventEmitter();
1145
- onAction = new EventEmitter();
1146
- onClose = new EventEmitter();
1147
- constructor(t, confirmationService) {
1319
+ schedule = null;
1320
+ scheduleData = null;
1321
+ participants = [];
1322
+ participantsLoading = false;
1323
+ loading = false;
1324
+ constructor(scheduleService, t) {
1325
+ this.scheduleService = scheduleService;
1148
1326
  this.t = t;
1149
- this.confirmationService = confirmationService;
1150
- }
1151
- get dialogHeader() {
1152
- return this.schedule?.name ?? this.t.translate('sr.schedule.schedule_details');
1153
1327
  }
1154
- closeDialog() {
1155
- this.visible = false;
1156
- this.visibleChange.emit(false);
1157
- this.onClose.emit();
1158
- }
1159
- editSchedule() {
1160
- if (this.schedule) {
1161
- this.onAction.emit({ type: 'edit', schedule: this.schedule });
1162
- }
1163
- }
1164
- acceptSchedule() {
1165
- if (!this.schedule)
1166
- return;
1167
- this.confirmAction('sr.schedule.confirm_accept', 'pi pi-question-circle', 'accept');
1168
- }
1169
- rejectSchedule() {
1170
- if (!this.schedule)
1171
- return;
1172
- this.confirmAction('sr.schedule.confirm_reject', 'pi pi-exclamation-triangle', 'reject');
1173
- }
1174
- cancelSchedule() {
1175
- if (!this.schedule)
1176
- return;
1177
- this.confirmAction('sr.schedule.confirm_cancel', 'pi pi-exclamation-triangle', 'cancel');
1178
- }
1179
- deleteSchedule() {
1180
- if (!this.schedule)
1181
- return;
1182
- this.confirmAction('sr.schedule.confirm_delete', 'pi pi-exclamation-triangle', 'delete');
1183
- }
1184
- confirmAction(messageKey, icon, type) {
1185
- this.confirmationService.confirm({
1186
- message: this.t.translate(messageKey),
1187
- header: this.t.translate('sr.schedule.confirmation'),
1188
- icon,
1189
- acceptLabel: this.t.translate('sr.schedule.yes'),
1190
- rejectLabel: this.t.translate('sr.schedule.no'),
1191
- accept: () => {
1192
- if (this.schedule) {
1193
- this.onAction.emit({ type, schedule: this.schedule });
1194
- }
1195
- }
1328
+ open(scheduleId) {
1329
+ this.schedule = null;
1330
+ this.scheduleData = null;
1331
+ this.participants = [];
1332
+ this.loading = true;
1333
+ this.participantsLoading = true;
1334
+ this.visible = true;
1335
+ this.visibleChange.emit(true);
1336
+ this.scheduleService.get(scheduleId).subscribe({
1337
+ next: (data) => {
1338
+ this.scheduleData = data;
1339
+ this.schedule = {
1340
+ id: data.id, name: data.name,
1341
+ scheduleType: data.type ?? null,
1342
+ withRecurrence: data.withRecurrence,
1343
+ whenOccurs: data.whenOccurs ?? '',
1344
+ allDay: data.allDay, startTime: data.startTime,
1345
+ endTime: data.endTime, priority: data.priority
1346
+ };
1347
+ this.loading = false;
1348
+ },
1349
+ error: () => { this.loading = false; }
1350
+ });
1351
+ this.scheduleService.listParticipants(scheduleId).subscribe({
1352
+ next: (r) => { this.participants = r.contents ?? []; this.participantsLoading = false; },
1353
+ error: () => { this.participantsLoading = false; }
1196
1354
  });
1197
1355
  }
1198
- formatDate(date) {
1199
- if (!date) {
1200
- return this.t.translate('sr.schedule.not_informed');
1201
- }
1202
- try {
1203
- const dateObj = new Date(date);
1204
- if (isNaN(dateObj.getTime())) {
1205
- return this.t.translate('sr.schedule.invalid_date');
1206
- }
1207
- return dateObj.toLocaleString('pt-BR', {
1208
- day: '2-digit', month: '2-digit', year: 'numeric',
1209
- hour: '2-digit', minute: '2-digit'
1210
- });
1211
- }
1212
- catch {
1213
- return this.t.translate('sr.schedule.invalid_date');
1214
- }
1215
- }
1216
- getPriorityLabel(priority) {
1217
- if (!priority) {
1218
- return this.t.translate('sr.schedule.not_informed');
1219
- }
1220
- const labels = {
1221
- [SchedulePriority.Low]: this.t.translate('sr.schedule.priority_low'),
1222
- [SchedulePriority.Medium]: this.t.translate('sr.schedule.priority_medium'),
1223
- [SchedulePriority.High]: this.t.translate('sr.schedule.priority_high'),
1224
- [SchedulePriority.Critical]: this.t.translate('sr.schedule.priority_critical')
1225
- };
1226
- return labels[priority] ?? priority;
1227
- }
1228
- getPrioritySeverity(priority) {
1229
- if (!priority) {
1230
- return 'info';
1231
- }
1232
- const severities = {
1233
- [SchedulePriority.Low]: 'info',
1234
- [SchedulePriority.Medium]: 'success',
1235
- [SchedulePriority.High]: 'warn',
1236
- [SchedulePriority.Critical]: 'danger'
1237
- };
1238
- return severities[priority] ?? 'info';
1239
- }
1240
- getRecurrenceLabel(recurrence) {
1241
- if (!recurrence) {
1242
- return this.t.translate('sr.schedule.recurrence_none');
1243
- }
1244
- const labels = {
1245
- 'NONE': this.t.translate('sr.schedule.recurrence_none'),
1246
- 'DAILY': this.t.translate('sr.schedule.recurrence_daily'),
1247
- 'WEEKLY': this.t.translate('sr.schedule.recurrence_weekly'),
1248
- 'MONTHLY': this.t.translate('sr.schedule.recurrence_monthly'),
1249
- 'YEARLY': this.t.translate('sr.schedule.recurrence_yearly'),
1250
- 'CUSTOM': this.t.translate('sr.schedule.recurrence_custom')
1251
- };
1252
- return labels[recurrence] ?? recurrence;
1253
- }
1254
- getOrganizerName() {
1255
- const organizer = this.schedule?.participants?.find((p) => p.organizer);
1256
- return organizer?.collaborator?.name ?? this.t.translate('sr.schedule.not_informed');
1257
- }
1258
- getParticipantsCount() {
1259
- return this.schedule?.participants?.filter((p) => !p.organizer).length ?? 0;
1260
- }
1261
- getParticipantsList() {
1262
- const participants = this.schedule?.participants?.filter((p) => !p.organizer) ?? [];
1263
- if (participants.length === 0) {
1264
- return this.t.translate('sr.schedule.no_participants');
1265
- }
1266
- return participants.map((p) => p.collaborator?.name ?? this.t.translate('sr.schedule.no_name')).join(', ');
1267
- }
1268
- getConfirmationLabel(confirmation) {
1269
- if (!confirmation) {
1270
- return '';
1271
- }
1272
- const labels = {
1273
- 'CONFIRMED': this.t.translate('sr.schedule.status_accepted'),
1274
- 'DECLINED': this.t.translate('sr.schedule.status_rejected')
1275
- };
1276
- return labels[confirmation] ?? this.t.translate('sr.schedule.status_pending');
1277
- }
1278
- getConfirmationSeverity(confirmation) {
1279
- const severities = {
1280
- 'CONFIRMED': 'success',
1281
- 'DECLINED': 'danger'
1282
- };
1283
- return severities[confirmation ?? ''] ?? 'warn';
1284
- }
1285
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleDetailComponent, deps: [{ token: i2.TranslationService }, { token: i2$1.ConfirmationService }], target: i0.ɵɵFactoryTarget.Component });
1286
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ScheduleDetailComponent, isStandalone: true, selector: "s-schedule-detail", inputs: { visible: "visible", schedule: "schedule", showAcceptButton: "showAcceptButton", showRejectButton: "showRejectButton", showCancelButton: "showCancelButton", showEditButton: "showEditButton", showDeleteButton: "showDeleteButton" }, outputs: { visibleChange: "visibleChange", onAction: "onAction", onClose: "onClose" }, providers: [ConfirmationService], ngImport: i0, template: "<p-dialog\n [(visible)]=\"visible\"\n [modal]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [styleClass]=\"'schedule-detail-dialog'\"\n [header]=\"dialogHeader\"\n (onHide)=\"closeDialog()\">\n \n <ng-template pTemplate=\"header\">\n <div class=\"dialog-header\">\n <h3>{{ dialogHeader }}</h3>\n <p-tag \n *ngIf=\"schedule?.priority\"\n [severity]=\"getPrioritySeverity(schedule?.priority)\"\n [value]=\"getPriorityLabel(schedule?.priority)\">\n </p-tag>\n </div>\n </ng-template>\n\n <div class=\"schedule-detail-content\" *ngIf=\"schedule\">\n \n <!-- Informa\u00E7\u00F5es B\u00E1sicas -->\n <div class=\"detail-section\">\n <h4 class=\"section-title\">{{ 'sr.schedule.basic_info' | translate }}</h4>\n \n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-calendar\"></i>\n {{ 'sr.schedule.type' | translate }}:\n </span>\n <span class=\"detail-value\">{{ schedule.type?.name ?? ('sr.schedule.not_informed' | translate) }}</span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-clock\"></i>\n {{ 'sr.schedule.when_occurs' | translate }}:\n </span>\n <span class=\"detail-value\">{{ schedule.whenOccurs }}</span>\n </div>\n\n <div class=\"detail-row\" *ngIf=\"schedule.duration\">\n <span class=\"detail-label\">\n <i class=\"pi pi-hourglass\"></i>\n {{ 'sr.schedule.duration' | translate }}:\n </span>\n <span class=\"detail-value\">{{ schedule.duration }} {{ 'sr.schedule.minutes' | translate }}</span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-refresh\"></i>\n {{ 'sr.schedule.recurrence' | translate }}:\n </span>\n <span class=\"detail-value\">{{ getRecurrenceLabel(schedule.recurrence) }}</span>\n </div>\n </div>\n\n <p-divider></p-divider>\n\n <!-- Descri\u00E7\u00E3o -->\n <div class=\"detail-section\" *ngIf=\"schedule.description\">\n <h4 class=\"section-title\">{{ 'sr.schedule.description' | translate }}</h4>\n <p class=\"description-text\">{{ schedule.description }}</p>\n </div>\n\n <p-divider *ngIf=\"schedule.description\"></p-divider>\n\n <!-- Participantes -->\n <div class=\"detail-section\">\n <h4 class=\"section-title\">{{ 'sr.schedule.participants' | translate }}</h4>\n \n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-user\"></i>\n {{ 'sr.schedule.organizer' | translate }}:\n </span>\n <span class=\"detail-value\">{{ getOrganizerName() }}</span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-users\"></i>\n {{ 'sr.schedule.participants' | translate }} ({{ getParticipantsCount() }}):\n </span>\n </div>\n \n <div class=\"participants-list\" *ngIf=\"getParticipantsCount() > 0\">\n <div class=\"participant-item\" *ngFor=\"let participant of schedule.participants\">\n <ng-container *ngIf=\"!participant.organizer\">\n <i class=\"pi pi-user\"></i>\n <span>{{ participant.collaborator?.name ?? ('sr.schedule.no_name' | translate) }}</span>\n <p-tag \n *ngIf=\"participant.confirmation\"\n [severity]=\"getConfirmationSeverity(participant.confirmation)\"\n [value]=\"getConfirmationLabel(participant.confirmation)\"\n styleClass=\"participant-status\">\n </p-tag>\n </ng-container>\n </div>\n </div>\n <p class=\"no-participants\" *ngIf=\"getParticipantsCount() === 0\">\n {{ 'sr.schedule.no_participants_besides_organizer' | translate }}\n </p>\n </div>\n\n <p-divider></p-divider>\n\n <!-- Local -->\n <div class=\"detail-section\" *ngIf=\"schedule.location\">\n <h4 class=\"section-title\">{{ 'sr.schedule.location' | translate }}</h4>\n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-map-marker\"></i>\n {{ 'sr.schedule.address' | translate }}:\n </span>\n <span class=\"detail-value\">{{ schedule.location }}</span>\n </div>\n </div>\n\n <!-- Observa\u00E7\u00F5es -->\n <div class=\"detail-section\" *ngIf=\"schedule.observations\">\n <h4 class=\"section-title\">{{ 'sr.schedule.notes' | translate }}</h4>\n <p class=\"observations-text\">{{ schedule.observations }}</p>\n </div>\n\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <div class=\"footer-left\">\n <button \n *ngIf=\"showDeleteButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.delete' | translate\" \n icon=\"pi pi-trash\"\n class=\"p-button-danger p-button-text\"\n (click)=\"deleteSchedule()\">\n </button>\n </div>\n <div class=\"footer-right\">\n <button \n *ngIf=\"showRejectButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.reject' | translate\" \n icon=\"pi pi-times\"\n class=\"p-button-warning\"\n (click)=\"rejectSchedule()\">\n </button>\n <button \n *ngIf=\"showCancelButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.cancel' | translate\" \n icon=\"pi pi-ban\"\n class=\"p-button-secondary\"\n (click)=\"cancelSchedule()\">\n </button>\n <button \n *ngIf=\"showAcceptButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.accept' | translate\" \n icon=\"pi pi-check\"\n class=\"p-button-success\"\n (click)=\"acceptSchedule()\">\n </button>\n <button \n *ngIf=\"showEditButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.edit_schedule' | translate\" \n icon=\"pi pi-pencil\"\n (click)=\"editSchedule()\">\n </button>\n <button \n pButton type=\"button\" \n [label]=\"'sr.schedule.close' | translate\" \n icon=\"pi pi-times\"\n class=\"p-button-text\"\n (click)=\"closeDialog()\">\n </button>\n </div>\n </div>\n </ng-template>\n\n</p-dialog>\n\n<p-confirmDialog></p-confirmDialog>\n", styles: [".dialog-header{display:flex;align-items:center;justify-content:space-between;width:100%;gap:1rem}.dialog-header h3{margin:0;font-size:1.25rem;font-weight:600;flex:1}.schedule-detail-content{padding:.5rem 0}.detail-section{margin-bottom:1rem}.detail-section .section-title{font-size:1rem;font-weight:600;margin:0 0 1rem;color:var(--text-color)}.detail-section .detail-row{display:flex;align-items:flex-start;margin-bottom:.75rem;gap:.5rem}.detail-section .detail-row .detail-label{display:flex;align-items:center;gap:.5rem;font-weight:500;color:var(--text-color-secondary);min-width:140px;flex-shrink:0}.detail-section .detail-row .detail-label i{font-size:.875rem}.detail-section .detail-row .detail-value{color:var(--text-color);flex:1}.detail-section .description-text,.detail-section .observations-text{color:var(--text-color);line-height:1.6;margin:0;white-space:pre-wrap}.detail-section .participants-list{margin-top:.5rem;display:flex;flex-direction:column;gap:.5rem}.detail-section .participants-list .participant-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:var(--surface-50);border-radius:4px}.detail-section .participants-list .participant-item i{color:var(--text-color-secondary);font-size:.875rem}.detail-section .participants-list .participant-item span{flex:1;color:var(--text-color)}.detail-section .participants-list .participant-item .participant-status{font-size:.75rem}.detail-section .no-participants{color:var(--text-color-secondary);font-style:italic;margin:.5rem 0 0}.dialog-footer{display:flex;justify-content:space-between;align-items:center;width:100%;gap:.5rem}.dialog-footer .footer-left{display:flex;gap:.5rem}.dialog-footer .footer-right{display:flex;gap:.5rem;margin-left:auto}:host ::ng-deep .schedule-detail-dialog{width:600px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i2$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i8.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i6$1.Tag, selector: "p-tag", inputs: ["style", "styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i12.Divider, selector: "p-divider", inputs: ["style", "styleClass", "layout", "type", "align"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "component", type: i8$1.ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "visible", "position"], outputs: ["onHide"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
1356
+ onClose() { this.visible = false; this.visibleChange.emit(false); }
1357
+ getParticipantName(p) { return getParticipantName(p); }
1358
+ getParticipantType(p) { return getParticipantType(this.t, p); }
1359
+ getParticipantTypeIcon(p) { return getParticipantTypeIcon(p); }
1360
+ getPrioritySeverity(p) { return getPrioritySeverity(p); }
1361
+ getPriorityLabel(p) { return getPriorityLabel(this.t, p); }
1362
+ getConfirmationSeverity(c) { return getConfirmationSeverity(c); }
1363
+ getConfirmationLabel(c) { return getConfirmationLabel(this.t, c); }
1364
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleDetailComponent, deps: [{ token: ScheduleService }, { token: i5.TranslationService }], target: i0.ɵɵFactoryTarget.Component });
1365
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ScheduleDetailComponent, isStandalone: true, selector: "s-schedule-detail", inputs: { visible: "visible" }, outputs: { visibleChange: "visibleChange" }, ngImport: i0, template: "<p-dialog\n [(visible)]=\"visible\"\n [header]=\"schedule?.name || ''\"\n [modal]=\"true\"\n styleClass=\"detail-dialog\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n (onHide)=\"onClose()\"\n>\n <div class=\"detail-dialog-body\" *ngIf=\"schedule\">\n <div\n class=\"detail-dialog-section\"\n *ngIf=\"scheduleData\"\n >\n <div class=\"detail-dialog-row\">\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_priority' | translate }}\n </span>\n <p-tag\n [value]=\"getPriorityLabel(schedule.priority)\"\n [severity]=\"getPrioritySeverity(schedule.priority)\"\n ></p-tag>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"schedule.scheduleType\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_type' | translate }}\n </span>\n <span>{{ schedule.scheduleType.name }}</span>\n </div>\n <div class=\"detail-dialog-row\">\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_start_date' | translate }}\n </span>\n <span>{{ scheduleData.startDate }}</span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"scheduleData.endDate\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_end_date' | translate }}\n </span>\n <span>{{ scheduleData.endDate }}</span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"!schedule.allDay && schedule.startTime\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_start_time' | translate }}\n </span>\n <span>\n {{ schedule.startTime }} - {{ schedule.endTime }}\n </span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"schedule.allDay\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_start_time' | translate }}\n </span>\n <span>\n {{ 'crmx.components.schedule_all_day' | translate }}\n </span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"schedule.whenOccurs\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_recurrence' | translate }}\n </span>\n <span>{{ schedule.whenOccurs }}</span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"scheduleData.comments\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_comments' | translate }}\n </span>\n <span>{{ scheduleData.comments }}</span>\n </div>\n </div>\n <p-divider *ngIf=\"scheduleData\"></p-divider>\n <div\n class=\"detail-dialog-section\"\n *ngIf=\"scheduleData\"\n >\n <div class=\"detail-section-header\">\n <i class=\"pi pi-users\"></i>\n <span>\n {{ 'crmx.components.schedule_participants' | translate }}\n </span>\n </div>\n <p-table\n [value]=\"participants\"\n [loading]=\"participantsLoading\"\n styleClass=\"p-datatable-sm p-datatable-striped\"\n >\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"col\">\n {{ 'crmx.components.schedule_name' | translate }}\n </th>\n <th\n scope=\"col\"\n class=\"col-participant-type\"\n >\n {{ 'crmx.components.schedule_participant_type' | translate }}\n </th>\n <th\n scope=\"col\"\n class=\"col-status\"\n >\n {{ 'crmx.components.schedule_status' | translate }}\n </th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-p>\n <tr>\n <td>\n <span>{{ getParticipantName(p) }}</span>\n </td>\n <td>\n <div class=\"participant-type-cell\">\n <i\n [class]=\"getParticipantTypeIcon(p)\"\n ></i>\n <span>\n {{ getParticipantType(p) }}\n </span>\n </div>\n </td>\n <td>\n <p-tag\n *ngIf=\"p.organizer\"\n [value]=\"\n 'crmx.components.schedule_participant_organizer_label'\n | translate\n \"\n severity=\"info\"\n ></p-tag>\n <p-tag\n *ngIf=\"!p.organizer\"\n [value]=\"\n getConfirmationLabel(p.confirmation)\n \"\n [severity]=\"\n getConfirmationSeverity(p.confirmation)\n \"\n ></p-tag>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"emptymessage\">\n <tr>\n <td colspan=\"3\">\n <div class=\"participants-empty\">\n <i class=\"pi pi-users\"></i>\n <p>\n {{\n 'crmx.components.schedule_no_participants'\n | translate\n }}\n </p>\n </div>\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n </div>\n</p-dialog>\n", styles: [":host ::ng-deep .detail-dialog{width:600px}.detail-dialog-body{display:flex;flex-direction:column;gap:.5rem}.detail-dialog-row{display:flex;align-items:center;gap:.75rem;padding:.4rem 0}.detail-label{font-weight:500;color:var(--p-text-secondary-color);min-width:8rem}.detail-section-header{display:flex;align-items:center;gap:.5rem;padding-bottom:1rem;margin-bottom:1rem;border-bottom:1px solid var(--p-surface-200);font-weight:600;font-size:.95rem;color:var(--p-text-color)}.detail-section-header i{color:var(--p-primary-color);font-size:1rem}.participant-type-cell{display:flex;align-items:center;gap:.5rem;font-size:.85rem;color:var(--p-text-secondary-color)}.participant-type-cell i{font-size:.9rem}.col-participant-type{width:10rem}.col-status{width:8rem}.participants-empty{display:flex;flex-direction:column;align-items:center;padding:2rem;text-align:center;color:var(--p-text-secondary-color);border:1px dashed var(--p-surface-300);border-radius:8px}.participants-empty i{font-size:2rem;margin-bottom:.5rem;opacity:.4}.participants-empty p{margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i8.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i14.Divider, selector: "p-divider", inputs: ["style", "styleClass", "layout", "type", "align"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i7$1.Tag, selector: "p-tag", inputs: ["style", "styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i15.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "virtualRowHeight", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
1287
1366
  }
1288
1367
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScheduleDetailComponent, decorators: [{
1289
1368
  type: Component,
1290
- args: [{ selector: 's-schedule-detail', standalone: true, imports: [
1291
- CommonModule, DialogModule, ButtonModule, TagModule,
1292
- DividerModule, TooltipModule, ConfirmDialogModule, TranslatePipe
1293
- ], providers: [ConfirmationService], template: "<p-dialog\n [(visible)]=\"visible\"\n [modal]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [styleClass]=\"'schedule-detail-dialog'\"\n [header]=\"dialogHeader\"\n (onHide)=\"closeDialog()\">\n \n <ng-template pTemplate=\"header\">\n <div class=\"dialog-header\">\n <h3>{{ dialogHeader }}</h3>\n <p-tag \n *ngIf=\"schedule?.priority\"\n [severity]=\"getPrioritySeverity(schedule?.priority)\"\n [value]=\"getPriorityLabel(schedule?.priority)\">\n </p-tag>\n </div>\n </ng-template>\n\n <div class=\"schedule-detail-content\" *ngIf=\"schedule\">\n \n <!-- Informa\u00E7\u00F5es B\u00E1sicas -->\n <div class=\"detail-section\">\n <h4 class=\"section-title\">{{ 'sr.schedule.basic_info' | translate }}</h4>\n \n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-calendar\"></i>\n {{ 'sr.schedule.type' | translate }}:\n </span>\n <span class=\"detail-value\">{{ schedule.type?.name ?? ('sr.schedule.not_informed' | translate) }}</span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-clock\"></i>\n {{ 'sr.schedule.when_occurs' | translate }}:\n </span>\n <span class=\"detail-value\">{{ schedule.whenOccurs }}</span>\n </div>\n\n <div class=\"detail-row\" *ngIf=\"schedule.duration\">\n <span class=\"detail-label\">\n <i class=\"pi pi-hourglass\"></i>\n {{ 'sr.schedule.duration' | translate }}:\n </span>\n <span class=\"detail-value\">{{ schedule.duration }} {{ 'sr.schedule.minutes' | translate }}</span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-refresh\"></i>\n {{ 'sr.schedule.recurrence' | translate }}:\n </span>\n <span class=\"detail-value\">{{ getRecurrenceLabel(schedule.recurrence) }}</span>\n </div>\n </div>\n\n <p-divider></p-divider>\n\n <!-- Descri\u00E7\u00E3o -->\n <div class=\"detail-section\" *ngIf=\"schedule.description\">\n <h4 class=\"section-title\">{{ 'sr.schedule.description' | translate }}</h4>\n <p class=\"description-text\">{{ schedule.description }}</p>\n </div>\n\n <p-divider *ngIf=\"schedule.description\"></p-divider>\n\n <!-- Participantes -->\n <div class=\"detail-section\">\n <h4 class=\"section-title\">{{ 'sr.schedule.participants' | translate }}</h4>\n \n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-user\"></i>\n {{ 'sr.schedule.organizer' | translate }}:\n </span>\n <span class=\"detail-value\">{{ getOrganizerName() }}</span>\n </div>\n\n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-users\"></i>\n {{ 'sr.schedule.participants' | translate }} ({{ getParticipantsCount() }}):\n </span>\n </div>\n \n <div class=\"participants-list\" *ngIf=\"getParticipantsCount() > 0\">\n <div class=\"participant-item\" *ngFor=\"let participant of schedule.participants\">\n <ng-container *ngIf=\"!participant.organizer\">\n <i class=\"pi pi-user\"></i>\n <span>{{ participant.collaborator?.name ?? ('sr.schedule.no_name' | translate) }}</span>\n <p-tag \n *ngIf=\"participant.confirmation\"\n [severity]=\"getConfirmationSeverity(participant.confirmation)\"\n [value]=\"getConfirmationLabel(participant.confirmation)\"\n styleClass=\"participant-status\">\n </p-tag>\n </ng-container>\n </div>\n </div>\n <p class=\"no-participants\" *ngIf=\"getParticipantsCount() === 0\">\n {{ 'sr.schedule.no_participants_besides_organizer' | translate }}\n </p>\n </div>\n\n <p-divider></p-divider>\n\n <!-- Local -->\n <div class=\"detail-section\" *ngIf=\"schedule.location\">\n <h4 class=\"section-title\">{{ 'sr.schedule.location' | translate }}</h4>\n <div class=\"detail-row\">\n <span class=\"detail-label\">\n <i class=\"pi pi-map-marker\"></i>\n {{ 'sr.schedule.address' | translate }}:\n </span>\n <span class=\"detail-value\">{{ schedule.location }}</span>\n </div>\n </div>\n\n <!-- Observa\u00E7\u00F5es -->\n <div class=\"detail-section\" *ngIf=\"schedule.observations\">\n <h4 class=\"section-title\">{{ 'sr.schedule.notes' | translate }}</h4>\n <p class=\"observations-text\">{{ schedule.observations }}</p>\n </div>\n\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <div class=\"footer-left\">\n <button \n *ngIf=\"showDeleteButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.delete' | translate\" \n icon=\"pi pi-trash\"\n class=\"p-button-danger p-button-text\"\n (click)=\"deleteSchedule()\">\n </button>\n </div>\n <div class=\"footer-right\">\n <button \n *ngIf=\"showRejectButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.reject' | translate\" \n icon=\"pi pi-times\"\n class=\"p-button-warning\"\n (click)=\"rejectSchedule()\">\n </button>\n <button \n *ngIf=\"showCancelButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.cancel' | translate\" \n icon=\"pi pi-ban\"\n class=\"p-button-secondary\"\n (click)=\"cancelSchedule()\">\n </button>\n <button \n *ngIf=\"showAcceptButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.accept' | translate\" \n icon=\"pi pi-check\"\n class=\"p-button-success\"\n (click)=\"acceptSchedule()\">\n </button>\n <button \n *ngIf=\"showEditButton\"\n pButton type=\"button\" \n [label]=\"'sr.schedule.edit_schedule' | translate\" \n icon=\"pi pi-pencil\"\n (click)=\"editSchedule()\">\n </button>\n <button \n pButton type=\"button\" \n [label]=\"'sr.schedule.close' | translate\" \n icon=\"pi pi-times\"\n class=\"p-button-text\"\n (click)=\"closeDialog()\">\n </button>\n </div>\n </div>\n </ng-template>\n\n</p-dialog>\n\n<p-confirmDialog></p-confirmDialog>\n", styles: [".dialog-header{display:flex;align-items:center;justify-content:space-between;width:100%;gap:1rem}.dialog-header h3{margin:0;font-size:1.25rem;font-weight:600;flex:1}.schedule-detail-content{padding:.5rem 0}.detail-section{margin-bottom:1rem}.detail-section .section-title{font-size:1rem;font-weight:600;margin:0 0 1rem;color:var(--text-color)}.detail-section .detail-row{display:flex;align-items:flex-start;margin-bottom:.75rem;gap:.5rem}.detail-section .detail-row .detail-label{display:flex;align-items:center;gap:.5rem;font-weight:500;color:var(--text-color-secondary);min-width:140px;flex-shrink:0}.detail-section .detail-row .detail-label i{font-size:.875rem}.detail-section .detail-row .detail-value{color:var(--text-color);flex:1}.detail-section .description-text,.detail-section .observations-text{color:var(--text-color);line-height:1.6;margin:0;white-space:pre-wrap}.detail-section .participants-list{margin-top:.5rem;display:flex;flex-direction:column;gap:.5rem}.detail-section .participants-list .participant-item{display:flex;align-items:center;gap:.5rem;padding:.5rem;background:var(--surface-50);border-radius:4px}.detail-section .participants-list .participant-item i{color:var(--text-color-secondary);font-size:.875rem}.detail-section .participants-list .participant-item span{flex:1;color:var(--text-color)}.detail-section .participants-list .participant-item .participant-status{font-size:.75rem}.detail-section .no-participants{color:var(--text-color-secondary);font-style:italic;margin:.5rem 0 0}.dialog-footer{display:flex;justify-content:space-between;align-items:center;width:100%;gap:.5rem}.dialog-footer .footer-left{display:flex;gap:.5rem}.dialog-footer .footer-right{display:flex;gap:.5rem;margin-left:auto}:host ::ng-deep .schedule-detail-dialog{width:600px}\n"] }]
1294
- }], ctorParameters: () => [{ type: i2.TranslationService }, { type: i2$1.ConfirmationService }], propDecorators: { visible: [{
1295
- type: Input
1296
- }], schedule: [{
1297
- type: Input
1298
- }], showAcceptButton: [{
1299
- type: Input
1300
- }], showRejectButton: [{
1301
- type: Input
1302
- }], showCancelButton: [{
1303
- type: Input
1304
- }], showEditButton: [{
1305
- type: Input
1306
- }], showDeleteButton: [{
1369
+ args: [{ selector: 's-schedule-detail', standalone: true, imports: [CommonModule, DialogModule, DividerModule, TagModule, TableModule, TranslatePipe], template: "<p-dialog\n [(visible)]=\"visible\"\n [header]=\"schedule?.name || ''\"\n [modal]=\"true\"\n styleClass=\"detail-dialog\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n (onHide)=\"onClose()\"\n>\n <div class=\"detail-dialog-body\" *ngIf=\"schedule\">\n <div\n class=\"detail-dialog-section\"\n *ngIf=\"scheduleData\"\n >\n <div class=\"detail-dialog-row\">\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_priority' | translate }}\n </span>\n <p-tag\n [value]=\"getPriorityLabel(schedule.priority)\"\n [severity]=\"getPrioritySeverity(schedule.priority)\"\n ></p-tag>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"schedule.scheduleType\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_type' | translate }}\n </span>\n <span>{{ schedule.scheduleType.name }}</span>\n </div>\n <div class=\"detail-dialog-row\">\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_start_date' | translate }}\n </span>\n <span>{{ scheduleData.startDate }}</span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"scheduleData.endDate\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_end_date' | translate }}\n </span>\n <span>{{ scheduleData.endDate }}</span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"!schedule.allDay && schedule.startTime\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_start_time' | translate }}\n </span>\n <span>\n {{ schedule.startTime }} - {{ schedule.endTime }}\n </span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"schedule.allDay\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_start_time' | translate }}\n </span>\n <span>\n {{ 'crmx.components.schedule_all_day' | translate }}\n </span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"schedule.whenOccurs\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_recurrence' | translate }}\n </span>\n <span>{{ schedule.whenOccurs }}</span>\n </div>\n <div\n class=\"detail-dialog-row\"\n *ngIf=\"scheduleData.comments\"\n >\n <span class=\"detail-label\">\n {{ 'crmx.components.schedule_comments' | translate }}\n </span>\n <span>{{ scheduleData.comments }}</span>\n </div>\n </div>\n <p-divider *ngIf=\"scheduleData\"></p-divider>\n <div\n class=\"detail-dialog-section\"\n *ngIf=\"scheduleData\"\n >\n <div class=\"detail-section-header\">\n <i class=\"pi pi-users\"></i>\n <span>\n {{ 'crmx.components.schedule_participants' | translate }}\n </span>\n </div>\n <p-table\n [value]=\"participants\"\n [loading]=\"participantsLoading\"\n styleClass=\"p-datatable-sm p-datatable-striped\"\n >\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"col\">\n {{ 'crmx.components.schedule_name' | translate }}\n </th>\n <th\n scope=\"col\"\n class=\"col-participant-type\"\n >\n {{ 'crmx.components.schedule_participant_type' | translate }}\n </th>\n <th\n scope=\"col\"\n class=\"col-status\"\n >\n {{ 'crmx.components.schedule_status' | translate }}\n </th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-p>\n <tr>\n <td>\n <span>{{ getParticipantName(p) }}</span>\n </td>\n <td>\n <div class=\"participant-type-cell\">\n <i\n [class]=\"getParticipantTypeIcon(p)\"\n ></i>\n <span>\n {{ getParticipantType(p) }}\n </span>\n </div>\n </td>\n <td>\n <p-tag\n *ngIf=\"p.organizer\"\n [value]=\"\n 'crmx.components.schedule_participant_organizer_label'\n | translate\n \"\n severity=\"info\"\n ></p-tag>\n <p-tag\n *ngIf=\"!p.organizer\"\n [value]=\"\n getConfirmationLabel(p.confirmation)\n \"\n [severity]=\"\n getConfirmationSeverity(p.confirmation)\n \"\n ></p-tag>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"emptymessage\">\n <tr>\n <td colspan=\"3\">\n <div class=\"participants-empty\">\n <i class=\"pi pi-users\"></i>\n <p>\n {{\n 'crmx.components.schedule_no_participants'\n | translate\n }}\n </p>\n </div>\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n </div>\n</p-dialog>\n", styles: [":host ::ng-deep .detail-dialog{width:600px}.detail-dialog-body{display:flex;flex-direction:column;gap:.5rem}.detail-dialog-row{display:flex;align-items:center;gap:.75rem;padding:.4rem 0}.detail-label{font-weight:500;color:var(--p-text-secondary-color);min-width:8rem}.detail-section-header{display:flex;align-items:center;gap:.5rem;padding-bottom:1rem;margin-bottom:1rem;border-bottom:1px solid var(--p-surface-200);font-weight:600;font-size:.95rem;color:var(--p-text-color)}.detail-section-header i{color:var(--p-primary-color);font-size:1rem}.participant-type-cell{display:flex;align-items:center;gap:.5rem;font-size:.85rem;color:var(--p-text-secondary-color)}.participant-type-cell i{font-size:.9rem}.col-participant-type{width:10rem}.col-status{width:8rem}.participants-empty{display:flex;flex-direction:column;align-items:center;padding:2rem;text-align:center;color:var(--p-text-secondary-color);border:1px dashed var(--p-surface-300);border-radius:8px}.participants-empty i{font-size:2rem;margin-bottom:.5rem;opacity:.4}.participants-empty p{margin:0}\n"] }]
1370
+ }], ctorParameters: () => [{ type: ScheduleService }, { type: i5.TranslationService }], propDecorators: { visible: [{
1307
1371
  type: Input
1308
1372
  }], visibleChange: [{
1309
1373
  type: Output
1310
- }], onAction: [{
1311
- type: Output
1312
- }], onClose: [{
1313
- type: Output
1314
1374
  }] } });
1315
1375
 
1316
- // Components
1317
-
1318
1376
  /*
1319
1377
  * Public API Surface of @senior-gestao-relacionamento/angular-components
1320
1378
  */
@@ -1323,5 +1381,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1323
1381
  * Generated bundle index. Do not edit.
1324
1382
  */
1325
1383
 
1326
- export { AngularComponentsModule, CurrentCollaboratorService, Month, OrdinalWeekDay, ParticipantConfirmation, RepeatWhen, ScheduleDetailComponent, ScheduleFormComponent, SchedulePriority, ScheduleRecurrence, ScheduleService, ScheduleTypeService, StorageService, WeekDay };
1384
+ export { AngularComponentsModule, CurrentCollaboratorService, Month, OrdinalWeekDay, ParticipantConfirmation, RepeatWhen, ScheduleDetailComponent, ScheduleFormComponent, SchedulePriority, ScheduleRecurrence, ScheduleService, ScheduleTypeService, Status, StorageService, WeekDay };
1327
1385
  //# sourceMappingURL=senior-gestao-relacionamento-angular-components.mjs.map