newportsite 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/newportsite-1.1.3.tgz +0 -0
  2. package/ng-package.json +7 -0
  3. package/obfuscate.js +70 -0
  4. package/package.json +15 -0
  5. package/src/lib/app.component.ts +47 -0
  6. package/src/lib/app.routing.ts +38 -0
  7. package/src/lib/auth/alert.component.html +5 -0
  8. package/src/lib/auth/alert.component.ts +24 -0
  9. package/src/lib/auth/auth.component.html +1 -0
  10. package/src/lib/auth/auth.component.ts +10 -0
  11. package/src/lib/auth/auth.routes.ts +16 -0
  12. package/src/lib/auth/index.ts +4 -0
  13. package/src/lib/auth/login.component.html +87 -0
  14. package/src/lib/auth/login.component.ts +158 -0
  15. package/src/lib/auth/models/index.ts +1 -0
  16. package/src/lib/auth/models/user.ts +25 -0
  17. package/src/lib/auth/register.component.html +157 -0
  18. package/src/lib/auth/register.component.ts +219 -0
  19. package/src/lib/auth/services/alert.service.ts +47 -0
  20. package/src/lib/auth/services/auth.service.ts +28 -0
  21. package/src/lib/auth/services/index.ts +3 -0
  22. package/src/lib/auth/services/user.service.spec.ts +112 -0
  23. package/src/lib/auth/services/user.service.ts +47 -0
  24. package/src/lib/common/card.component.html +72 -0
  25. package/src/lib/common/card.component.ts +102 -0
  26. package/src/lib/common/commands.component.html +8 -0
  27. package/src/lib/common/commands.component.ts +42 -0
  28. package/src/lib/common/context.component.html +9 -0
  29. package/src/lib/common/context.component.ts +38 -0
  30. package/src/lib/common/grid.component.html +20 -0
  31. package/src/lib/common/grid.component.ts +747 -0
  32. package/src/lib/common/index.ts +9 -0
  33. package/src/lib/common/loader.component.html +5 -0
  34. package/src/lib/common/loader.component.ts +27 -0
  35. package/src/lib/common/lookup.component.html +29 -0
  36. package/src/lib/common/lookup.component.ts +115 -0
  37. package/src/lib/common/messagebox.component.html +39 -0
  38. package/src/lib/common/messagebox.component.ts +74 -0
  39. package/src/lib/common/theme-toggle.component.ts +139 -0
  40. package/src/lib/config.ts +62 -0
  41. package/src/lib/containers/default-layout/default-layout.component.html +191 -0
  42. package/src/lib/containers/default-layout/default-layout.component.ts +158 -0
  43. package/src/lib/containers/default-layout/index.ts +1 -0
  44. package/src/lib/containers/index.ts +1 -0
  45. package/src/lib/directives/component.draggable.ts +80 -0
  46. package/src/lib/directives/index.ts +2 -0
  47. package/src/lib/directives/input.directive.spec.ts +158 -0
  48. package/src/lib/directives/input.directive.ts +210 -0
  49. package/src/lib/home/dashboard/dashboard.component.html +38 -0
  50. package/src/lib/home/dashboard/dashboard.component.ts +50 -0
  51. package/src/lib/home/dashboard/index.ts +1 -0
  52. package/src/lib/home/index.component.html +1 -0
  53. package/src/lib/home/index.component.ts +10 -0
  54. package/src/lib/home/index.routes.ts +29 -0
  55. package/src/lib/home/index.ts +1 -0
  56. package/src/lib/home/info/index.ts +1 -0
  57. package/src/lib/home/info/info.component.css +476 -0
  58. package/src/lib/home/info/info.component.html +174 -0
  59. package/src/lib/home/info/info.component.ts +287 -0
  60. package/src/lib/home/model/article.component.html +10 -0
  61. package/src/lib/home/model/article.component.ts +50 -0
  62. package/src/lib/home/model/barchart.component.html +8 -0
  63. package/src/lib/home/model/barchart.component.ts +59 -0
  64. package/src/lib/home/model/index.ts +7 -0
  65. package/src/lib/home/model/itemdetail.component.html +25 -0
  66. package/src/lib/home/model/itemdetail.component.ts +93 -0
  67. package/src/lib/home/model/itemtab.component.html +25 -0
  68. package/src/lib/home/model/itemtab.component.ts +105 -0
  69. package/src/lib/home/model/model.component.html +121 -0
  70. package/src/lib/home/model/model.component.ts +510 -0
  71. package/src/lib/home/model/modeltoolbar.component.html +111 -0
  72. package/src/lib/home/model/modeltoolbar.component.ts +157 -0
  73. package/src/lib/home/model/navigation.component.html +86 -0
  74. package/src/lib/home/model/navigation.component.ts +247 -0
  75. package/src/lib/home/model/services/index.ts +1 -0
  76. package/src/lib/home/model/services/model.service.spec.ts +423 -0
  77. package/src/lib/home/model/services/model.service.ts +319 -0
  78. package/src/lib/home/modelsearch/index.ts +1 -0
  79. package/src/lib/home/modelsearch/modelsearch.component.html +124 -0
  80. package/src/lib/home/modelsearch/modelsearch.component.ts +453 -0
  81. package/src/lib/interfaces/data.interface.ts +131 -0
  82. package/src/lib/interfaces/index.ts +2 -0
  83. package/src/lib/interfaces/item.interface.ts +438 -0
  84. package/src/lib/players/lookup/lookup.directive.ts +6 -0
  85. package/src/lib/players/lookup/lookup.item.component.ts +37 -0
  86. package/src/lib/players/lookup/lookup.item.ts +9 -0
  87. package/src/lib/players/lookup/lookup.player.component.ts +59 -0
  88. package/src/lib/players/lookup/lookup.selector.component.ts +41 -0
  89. package/src/lib/players/model/model.directive.ts +6 -0
  90. package/src/lib/players/model/model.item.component.spec.ts +311 -0
  91. package/src/lib/players/model/model.item.component.ts +3457 -0
  92. package/src/lib/players/model/model.item.ts +9 -0
  93. package/src/lib/players/model/model.player.component.ts +109 -0
  94. package/src/lib/players/model/model.selector.component.ts +59 -0
  95. package/src/lib/scheduler/scheduler.component.html +13 -0
  96. package/src/lib/scheduler/scheduler.component.scss +6 -0
  97. package/src/lib/scheduler/scheduler.component.ts +296 -0
  98. package/src/lib/scheduler/scheduler.routes.ts +15 -0
  99. package/src/lib/scheduler/schedulerdialog.component.html +72 -0
  100. package/src/lib/scheduler/schedulerdialog.component.ts +208 -0
  101. package/src/lib/scheduler/services/scheduler.service.ts +133 -0
  102. package/src/lib/services/auth-state.service.ts +129 -0
  103. package/src/lib/services/auth.interceptor.spec.ts +144 -0
  104. package/src/lib/services/auth.interceptor.ts +44 -0
  105. package/src/lib/services/cache.service.spec.ts +143 -0
  106. package/src/lib/services/cache.service.ts +71 -0
  107. package/src/lib/services/global-error-handler.spec.ts +39 -0
  108. package/src/lib/services/global-error-handler.ts +28 -0
  109. package/src/lib/services/global.service.spec.ts +801 -0
  110. package/src/lib/services/global.service.ts +724 -0
  111. package/src/lib/services/message.service.ts +556 -0
  112. package/src/lib/services/theme.service.ts +96 -0
  113. package/src/lib/template/authtemplate.component.html +6 -0
  114. package/src/lib/template/authtemplate.component.ts +13 -0
  115. package/src/lib/template/basetemplate.component.html +7 -0
  116. package/src/lib/template/basetemplate.component.ts +13 -0
  117. package/src/lib/template/index.ts +3 -0
  118. package/src/lib/template/modeltemplate.component.html +7 -0
  119. package/src/lib/template/modeltemplate.component.ts +21 -0
  120. package/src/lib/utils/piva.spec.ts +56 -0
  121. package/src/lib/utils/piva.ts +29 -0
  122. package/src/lib/validators/email.validator.spec.ts +57 -0
  123. package/src/lib/validators/email.validator.ts +17 -0
  124. package/src/lib/validators/equalPasswords.validator.spec.ts +54 -0
  125. package/src/lib/validators/equalPasswords.validator.ts +17 -0
  126. package/src/lib/validators/index.ts +2 -0
  127. package/src/lib/version.ts +1 -0
  128. package/src/public-api.ts +64 -0
  129. package/src/typings.d.ts +2 -0
  130. package/tsconfig.lib.json +18 -0
  131. package/tsconfig.lib.prod.json +9 -0
@@ -0,0 +1,9 @@
1
+ import { Type } from '@angular/core';
2
+ import { ItemInterface } from '../../interfaces/index';
3
+
4
+ export class ModelItem {
5
+ constructor(
6
+ public component: Type<any>,
7
+ public data: ItemInterface
8
+ ) {}
9
+ }
@@ -0,0 +1,109 @@
1
+ import {
2
+ Component,
3
+ input,
4
+ output,
5
+ effect,
6
+ untracked,
7
+ ChangeDetectionStrategy,
8
+ viewChild,
9
+ OnInit,
10
+ DestroyRef,
11
+ inject,
12
+ } from '@angular/core';
13
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
14
+ import { ModelDirective } from './model.directive';
15
+ import { ModelItem } from './model.item';
16
+ import { ItemInterface, ItemCommandInterface } from '../../interfaces/index';
17
+ import { GlobalService } from '../../services/global.service';
18
+
19
+ @Component({
20
+ selector: 'modelplayer',
21
+ template: `<ng-template mdModel></ng-template>`,
22
+ changeDetection: ChangeDetectionStrategy.OnPush,
23
+ imports: [ModelDirective],
24
+ })
25
+ export class ModelPlayerComponent implements OnInit {
26
+ private gsv = inject(GlobalService);
27
+
28
+ readonly model = input<ModelItem>();
29
+ readonly command = input<ItemCommandInterface>();
30
+ readonly viewList = input<boolean>();
31
+ readonly lookupValue = input<any>();
32
+ readonly dialogValue = input<any>();
33
+ readonly scale = input<number>();
34
+
35
+ readonly modelHost = viewChild.required(ModelDirective);
36
+ readonly commandsChanged = output<ItemCommandInterface[]>();
37
+
38
+ private componentRef!: any;
39
+ private destroyRef = inject(DestroyRef);
40
+
41
+ constructor() {
42
+ effect(() => {
43
+ const m = this.model();
44
+ if (!m) return;
45
+ this.gsv.setLoaderState(true);
46
+ const viewContainerRef = this.modelHost().viewContainerRef;
47
+ viewContainerRef.clear();
48
+ if (this.componentRef) {
49
+ this.componentRef.destroy();
50
+ this.componentRef = undefined;
51
+ }
52
+ this.componentRef = viewContainerRef.createComponent(m.component);
53
+ (this.componentRef.instance as ItemInterface).initItem?.(m.data);
54
+ });
55
+ effect(() => {
56
+ const cmd = this.command();
57
+ if (cmd && this.componentRef) {
58
+ (this.componentRef.instance as ItemInterface).sendCommand?.(cmd);
59
+ }
60
+ });
61
+ effect(() => {
62
+ const vl = this.viewList();
63
+ if (vl !== undefined && this.componentRef) {
64
+ (this.componentRef.instance as ItemInterface).setViewList?.(vl);
65
+ }
66
+ });
67
+ effect(() => {
68
+ const lv = this.lookupValue();
69
+ if (lv && this.componentRef) {
70
+ // untracked() exits the reactive context so that signal writes inside
71
+ // lookupResult (e.g. this._showlookup.set(false)) do not throw the
72
+ // "Writing to signals is not allowed in an effect" error, which would
73
+ // abort the call mid-way and leave showlookup=true (UI frozen).
74
+ untracked(() =>
75
+ (this.componentRef.instance as ItemInterface).lookupResult?.(lv)
76
+ );
77
+ }
78
+ });
79
+ effect(() => {
80
+ const dv = this.dialogValue();
81
+ if (dv && this.componentRef) {
82
+ untracked(() =>
83
+ (this.componentRef.instance as ItemInterface).dialogResult?.(dv)
84
+ );
85
+ }
86
+ });
87
+ effect(() => {
88
+ const s = this.scale();
89
+ if (s && this.componentRef) {
90
+ (this.componentRef.instance as ItemInterface).setScale?.(s);
91
+ }
92
+ });
93
+ }
94
+
95
+ /** Lifecycle: subscribes to toolbar command changes and re-emits them as output events. */
96
+ public ngOnInit() {
97
+ this.gsv
98
+ .getItemCommands()
99
+ .pipe(takeUntilDestroyed(this.destroyRef))
100
+ .subscribe(commands => {
101
+ this.OnCommandChanged(commands);
102
+ });
103
+ }
104
+
105
+ /** Re-emits a command array change to the parent (model.component) via commandsChanged output. */
106
+ public OnCommandChanged(commands: ItemCommandInterface[]) {
107
+ this.commandsChanged.emit(commands);
108
+ }
109
+ }
@@ -0,0 +1,59 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ effect,
5
+ input,
6
+ output,
7
+ signal,
8
+ } from '@angular/core';
9
+ import { ModelItemComponent } from './model.item.component';
10
+ import { ModelItem } from './model.item';
11
+ import { ItemInterface, ItemCommandInterface } from '../../interfaces/index';
12
+ import { ModelPlayerComponent } from './model.player.component';
13
+
14
+ @Component({
15
+ selector: 'modelselector',
16
+ template: `<modelplayer
17
+ [model]="modelItem()"
18
+ [command]="command()"
19
+ [viewList]="viewList()"
20
+ [lookupValue]="lookupValue()"
21
+ [dialogValue]="dialogValue()"
22
+ [scale]="scale()"
23
+ (commandsChanged)="onCommandsChanged($event)"></modelplayer>`,
24
+ changeDetection: ChangeDetectionStrategy.OnPush,
25
+ imports: [ModelPlayerComponent],
26
+ })
27
+ export class ModelSelectorComponent {
28
+ currentModel = input<ItemInterface>();
29
+ currentCommand = input<ItemCommandInterface>();
30
+ viewList = input<boolean>();
31
+ lookupValue = input<any>();
32
+ dialogValue = input<any>();
33
+ scale = input<number>();
34
+
35
+ commandsChanged = output<ItemCommandInterface[]>();
36
+
37
+ modelItem = signal<ModelItem | null>(null);
38
+ command = signal<ItemCommandInterface | null>(null);
39
+
40
+ constructor() {
41
+ effect(() => {
42
+ const m = this.currentModel();
43
+ if (m) {
44
+ this.modelItem.set(new ModelItem(ModelItemComponent, m));
45
+ }
46
+ });
47
+ effect(() => {
48
+ const c = this.currentCommand();
49
+ if (c !== undefined) {
50
+ this.command.set(c);
51
+ }
52
+ });
53
+ }
54
+
55
+ /** Forwards toolbar command state changes to the parent via the commandsChanged output. */
56
+ onCommandsChanged(commands: ItemCommandInterface[]) {
57
+ this.commandsChanged.emit(commands);
58
+ }
59
+ }
@@ -0,0 +1,13 @@
1
+ <full-calendar class="calendar" [options]="calendarOptions"></full-calendar>
2
+ <schedulerdialog
3
+ [hidden]="!showdialog"
4
+ [(show)]="showdialog"
5
+ [(text)]="textdialog"
6
+ [(title)]="titledialog"
7
+ (schedulerDialogResult)="dialogResult($event)"
8
+ [(showconfirm)]="showconfirm"
9
+ [(width)]="dialogWidth"
10
+ [(height)]="dialogHeight"
11
+ [(top)]="dialogTop"
12
+ [(left)]="dialogLeft">
13
+ </schedulerdialog>
@@ -0,0 +1,6 @@
1
+
2
+ .calendar {
3
+ width: 100%;
4
+ height: 100%;
5
+ padding: 0.8rem;
6
+ }
@@ -0,0 +1,296 @@
1
+ import {
2
+ AfterViewInit,
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ OnDestroy,
6
+ inject,
7
+ DestroyRef,
8
+ } from '@angular/core';
9
+ import {
10
+ CalendarOptions,
11
+ DateSelectArg,
12
+ EventClickArg,
13
+ EventApi,
14
+ EventAddArg,
15
+ EventRemoveArg,
16
+ EventInput,
17
+ } from '@fullcalendar/core';
18
+ import itLocale from '@fullcalendar/core/locales/it';
19
+ import enLocale from '@fullcalendar/core/locales/en-gb';
20
+ import { GlobalService, Languages } from '../services/global.service';
21
+ import { AppMessageService } from '../services/message.service';
22
+ import { SchedulerService } from './services/scheduler.service';
23
+ import {
24
+ DialogFieldInterface,
25
+ DialogType,
26
+ TransportInterface,
27
+ } from '../interfaces/item.interface';
28
+ import { SchedulerInterface } from '../interfaces/item.interface';
29
+ import { v4 as uuidv4 } from 'uuid';
30
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
31
+
32
+ import dayGridPlugin from '@fullcalendar/daygrid';
33
+ import timeGridPlugin from '@fullcalendar/timegrid';
34
+ import listPlugin from '@fullcalendar/list';
35
+
36
+ import interactionPlugin from '@fullcalendar/interaction';
37
+ import stc from 'string-to-color';
38
+ import { FullCalendarModule } from '@fullcalendar/angular';
39
+ import { SchedulerDialogComponent } from './schedulerdialog.component';
40
+
41
+ @Component({
42
+ selector: 'scheduler',
43
+ templateUrl: './scheduler.component.html',
44
+ styleUrls: ['./scheduler.component.scss'],
45
+ changeDetection: ChangeDetectionStrategy.OnPush,
46
+ imports: [FullCalendarModule, SchedulerDialogComponent],
47
+ })
48
+ export class SchedulerComponent implements AfterViewInit, OnDestroy {
49
+ gsv = inject(GlobalService);
50
+ msg = inject(AppMessageService);
51
+ scr = inject(SchedulerService);
52
+
53
+ public scheduler!: SchedulerInterface;
54
+
55
+ // SchedulerDialog
56
+ public showdialog = false;
57
+ public titledialog = '';
58
+ public textdialog = '';
59
+ public showconfirm = false;
60
+ public dialogHeight = 0;
61
+ public dialogWidth = 0;
62
+ public dialogTop = 0;
63
+ public dialogLeft = 0;
64
+ public dialogValue!: any;
65
+ public dialogType: DialogType = 0;
66
+ private destroyRef = inject(DestroyRef);
67
+
68
+ calendarOptions: CalendarOptions = {
69
+ headerToolbar: {
70
+ left: 'prev,next today',
71
+ center: 'title',
72
+ right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek',
73
+ },
74
+ plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
75
+
76
+ initialView: 'dayGridMonth',
77
+ weekends: true,
78
+ editable: true,
79
+ selectable: true,
80
+ selectMirror: true,
81
+ dayMaxEvents: true,
82
+ select: this.handleDateSelect.bind(this),
83
+ eventClick: this.handleEventClick.bind(this),
84
+ eventsSet: this.handleEvents.bind(this),
85
+ eventAdd: this.handleDateAdd.bind(this),
86
+ eventChange: this.handleDateChange.bind(this),
87
+ eventRemove: this.handleDateRemove.bind(this),
88
+ datesSet: this.handleDateChange.bind(this),
89
+ timeZone: 'Europe/Rome',
90
+ };
91
+ constructor() {
92
+ this.calendarOptions.locales = [this.gsv.getLng() === Languages.IT ? itLocale : enLocale];
93
+ }
94
+
95
+ /** Fetches calendar events for the given date range and updates the calendarEvents signal. */
96
+ public loadEvents(start: Date, end: Date) {
97
+ this.currentEvents = [];
98
+
99
+ this.scheduler = this.gsv.getSchedulerInterface();
100
+
101
+ this.scheduler.year = this.gsv.getYear();
102
+ this.scheduler.start = start;
103
+ this.scheduler.end = end;
104
+
105
+ this.scr
106
+ .getSchedulerDataRange(this.scheduler)
107
+ .pipe(takeUntilDestroyed(this.destroyRef))
108
+ .subscribe({
109
+ next: async (data: TransportInterface) => {
110
+ let events: Array<EventInput> = new Array<EventInput>();
111
+ (data.dataFile as any[]).forEach((element: any) => {
112
+ events.push({
113
+ id: element.id,
114
+ title: element.description,
115
+ start: element.startdate,
116
+ end: element.enddate,
117
+ allDay: element.allday,
118
+ extendedProps: { assigned: element.assigned },
119
+ backgroundColor: stc(element.description.split('-')[0]),
120
+ });
121
+ });
122
+ this.calendarOptions.events = events;
123
+ },
124
+ error: () => {},
125
+ });
126
+ }
127
+ /** Lifecycle: no-op — subscriptions managed by takeUntilDestroyed. */
128
+ public ngOnDestroy(): void {
129
+ // subscriptions are managed by takeUntilDestroyed
130
+ }
131
+
132
+ /** Lifecycle: subscribes to the dialog-field channel to open the event dialog. */
133
+ public ngAfterViewInit() {
134
+ this.gsv
135
+ .getDialogField()
136
+ .pipe(takeUntilDestroyed(this.destroyRef))
137
+ .subscribe(dialog => {
138
+ this.setDialog(dialog);
139
+ });
140
+ }
141
+
142
+ currentEvents: EventApi[] = [];
143
+
144
+ /** Broadcasts the current dialog state (show/hide, position, tag) to GlobalService. */
145
+ private sendDialog() {
146
+ this.gsv.setDialogField({
147
+ showdialog: this.showdialog,
148
+ titledialog: this.titledialog,
149
+ textdialog: this.textdialog,
150
+ showconfirm: this.showconfirm,
151
+ dialogHeight: this.dialogHeight,
152
+ dialogWidth: this.dialogWidth,
153
+ dialogTop: this.dialogTop,
154
+ dialogLeft: this.dialogLeft,
155
+ });
156
+ }
157
+
158
+ /** Applies an incoming dialog state (called by the parent shell on a dialog-field event). */
159
+ public setDialog(dialog: DialogFieldInterface) {
160
+ this.showdialog = dialog.showdialog;
161
+ this.titledialog = dialog.titledialog;
162
+ this.textdialog = dialog.textdialog;
163
+ this.showconfirm = dialog.showconfirm;
164
+ this.dialogHeight = dialog.dialogHeight;
165
+ this.dialogWidth = dialog.dialogWidth;
166
+ this.dialogTop = dialog.dialogTop;
167
+ this.dialogLeft = dialog.dialogLeft;
168
+ }
169
+
170
+ /**
171
+ * Handles the dialog close result: on confirm, creates a new event via postData, or
172
+ * deletes an existing event via deleteItem, then reloads the visible date range.
173
+ */
174
+ dialogResult(rsp: any) {
175
+ this.showdialog = false;
176
+ this.dialogValue = rsp;
177
+ this.titledialog = '';
178
+ this.textdialog = '';
179
+ this.showconfirm = false;
180
+ this.dialogHeight = 300;
181
+ this.dialogWidth = 400;
182
+ this.dialogTop = 200;
183
+ this.dialogLeft = 200;
184
+
185
+ if (rsp.value) {
186
+ if (rsp.tag.view === undefined) {
187
+ this.scheduler.id = rsp.tag.id;
188
+ this.scheduler.year = this.gsv.getYear();
189
+ this.scheduler.start = rsp.tag.start;
190
+ this.scheduler.end = rsp.tag.end;
191
+ this.scheduler.assigned = rsp.props[1];
192
+ this.scheduler.description = rsp.props[0];
193
+ this.scheduler.allday = rsp.tag.allDay;
194
+ this.scr.deleteItem(this.scheduler).subscribe({
195
+ next: (data: boolean) => {
196
+ if (data === true) {
197
+ rsp.tag.remove();
198
+ const calendarApi = rsp.tag._context.viewApi.calendar;
199
+ calendarApi.unselect();
200
+ calendarApi.addEvent({
201
+ id: rsp.tag.id,
202
+ title: rsp.props[0],
203
+ start: rsp.tag.startStr,
204
+ end: rsp.tag.endStr,
205
+ allDay: rsp.tag.allDay,
206
+ assigned: rsp.props[1],
207
+ backgroundColor: stc(rsp.props[0].split('-')[0]),
208
+ });
209
+ }
210
+ },
211
+ error: () => {},
212
+ });
213
+ } else {
214
+ const calendarApi = rsp.tag.view.calendar;
215
+ calendarApi.unselect();
216
+ calendarApi.addEvent({
217
+ id: uuidv4(),
218
+ title: rsp.props[0],
219
+ start: rsp.tag.startStr,
220
+ end: rsp.tag.endStr,
221
+ allDay: rsp.tag.allDay,
222
+ assigned: rsp.props[1],
223
+ backgroundColor: stc(rsp.props[0].split('-')[0]),
224
+ });
225
+ }
226
+ } else if (rsp.tag.view === undefined && rsp.delete) {
227
+ rsp.tag.remove();
228
+ }
229
+ }
230
+
231
+ /** Toggles the weekend-days visibility on the FullCalendar instance. */
232
+ handleWeekendsToggle() {
233
+ const { calendarOptions } = this;
234
+ calendarOptions.weekends = !calendarOptions.weekends;
235
+ }
236
+
237
+ /** Called by FullCalendar after an external event is dropped; logs the new event data. */
238
+ handleDateAdd(eventAdd: EventAddArg) {
239
+ this.scheduler.id = eventAdd.event.id;
240
+ this.scheduler.year = this.gsv.getYear();
241
+ this.scheduler.start = eventAdd.event.start;
242
+ this.scheduler.end = eventAdd.event.end;
243
+ this.scheduler.assigned = eventAdd.event.extendedProps.assigned;
244
+ this.scheduler.description = eventAdd.event.title;
245
+ this.scheduler.allday = eventAdd.event.allDay;
246
+ this.scr.postData(this.scheduler).subscribe({
247
+ next: () => {},
248
+ error: () => {},
249
+ });
250
+ }
251
+
252
+ /** Called by FullCalendar after an event is dragged/resized; reloads events for the new range. */
253
+ handleDateChange(eventChange: any) {
254
+ this.loadEvents(eventChange.start, eventChange.end);
255
+ }
256
+
257
+ /** Called by FullCalendar after an event is removed; logs the removed event data. */
258
+ handleDateRemove(eventRemove: EventRemoveArg) {
259
+ this.scheduler.id = eventRemove.event.id;
260
+ this.scheduler.year = this.gsv.getYear();
261
+ this.scr.deleteItem(this.scheduler).subscribe({
262
+ next: () => {},
263
+ error: () => {},
264
+ });
265
+ }
266
+
267
+ /** Called by FullCalendar on date/range selection; opens the dialog to create a new event. */
268
+ handleDateSelect(selectInfo: DateSelectArg) {
269
+ this.gsv.setDialog({ target: '', state: true, tag: selectInfo });
270
+ this.openDialog();
271
+ }
272
+
273
+ /** Called by FullCalendar when an existing event is clicked; opens the dialog to edit/delete. */
274
+ handleEventClick(clickInfo: EventClickArg) {
275
+ this.gsv.setDialog(null);
276
+ this.gsv.setDialog({ target: '', state: true, tag: clickInfo.event });
277
+ this.openDialog();
278
+ }
279
+
280
+ private openDialog() {
281
+ this.textdialog = '';
282
+ this.titledialog = this.msg.get('app.notify');
283
+ this.dialogHeight = 300;
284
+ this.dialogWidth = 400;
285
+ this.dialogTop = screen.height / 2 - this.dialogHeight / 2;
286
+ this.dialogLeft = screen.width / 2 - this.dialogWidth / 2;
287
+ this.showconfirm = true;
288
+ this.showdialog = true;
289
+ this.sendDialog();
290
+ }
291
+
292
+ /** FullCalendar callback: keeps the currentEvents array in sync for template rendering. */
293
+ handleEvents(events: EventApi[]) {
294
+ this.currentEvents = events;
295
+ }
296
+ }
@@ -0,0 +1,15 @@
1
+ import { Routes } from '@angular/router';
2
+ import { SchedulerComponent } from './scheduler.component';
3
+ import { authGuard } from '../auth/services/auth.service';
4
+
5
+ export const SCHEDULER_ROUTES: Routes = [
6
+ {
7
+ path: '',
8
+ component: SchedulerComponent,
9
+ canActivate: [authGuard],
10
+ children: [
11
+ { path: 'scheduler', component: SchedulerComponent },
12
+ { path: '**', redirectTo: '/scheduler', pathMatch: 'full' },
13
+ ],
14
+ },
15
+ ];
@@ -0,0 +1,72 @@
1
+ <div
2
+ class="modal fade"
3
+ bsModal
4
+ #modal="bs-modal"
5
+ [ngStyle]="contextStyle()"
6
+ ngxModalDraggable>
7
+ <div class="modal-header">
8
+ <h6 class="modal-title">{{ title() }}</h6>
9
+ <button
10
+ type="button"
11
+ class="btn-close"
12
+ data-dismiss="modal"
13
+ aria-label="Close"
14
+ (click)="closeDetail(false)"></button>
15
+ </div>
16
+ <div class="modal-body-60 bg-light p-2">
17
+ <form #form [formGroup]="profileform">
18
+ <div class="container">
19
+ <div class="row mt-2">
20
+ <label for="assigned" class="col-sm-3">{{
21
+ msg?.get('app.assigned')
22
+ }}</label>
23
+ <div class="col-sm-9">
24
+ <select
25
+ nvg
26
+ id="assigned"
27
+ tabindex="0"
28
+ class="field"
29
+ name="assigned"
30
+ [(ngModel)]="selected"
31
+ formControlName="assigned">
32
+ @for (c of assigneds; track c) {
33
+ <option value="{{ c.id }}">
34
+ {{ c.name }}
35
+ </option>
36
+ }
37
+ </select>
38
+ </div>
39
+ </div>
40
+ <div class="row mt-2">
41
+ <label for="description" class="col-sm-3">{{
42
+ msg?.get('app.description')
43
+ }}</label>
44
+ <div class="col-sm-9">
45
+ <input
46
+ nvg
47
+ autocomplete="off"
48
+ tabindex="1"
49
+ id="description"
50
+ [attr.data-state]="0"
51
+ class="field"
52
+ type="text"
53
+ formControlName="description" />
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </form>
58
+ </div>
59
+ <div class="modal-footer">
60
+ <button class="btn mx-2" (click)="closeAndRemove()">
61
+ {{ closeButtonText }}
62
+ </button>
63
+ <button
64
+ class="btn mx-2"
65
+ (click)="closeDetail(true)"
66
+ [hidden]="!showconfirm()"
67
+ type="submit"
68
+ [disabled]="!profileform.valid">
69
+ {{ msg?.get('app.confirm') }}
70
+ </button>
71
+ </div>
72
+ </div>