cloud-ide-academics 0.0.1 → 0.0.2

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 (20) hide show
  1. package/fesm2022/cloud-ide-academics-class-program-term-create.component-D3PfbSMN.mjs +578 -0
  2. package/fesm2022/cloud-ide-academics-class-program-term-create.component-D3PfbSMN.mjs.map +1 -0
  3. package/fesm2022/cloud-ide-academics-class-program-term-list.component-Cpbyavgd.mjs +404 -0
  4. package/fesm2022/cloud-ide-academics-class-program-term-list.component-Cpbyavgd.mjs.map +1 -0
  5. package/fesm2022/cloud-ide-academics-class-program-term.service-BW4PJQEM.mjs +111 -0
  6. package/fesm2022/cloud-ide-academics-class-program-term.service-BW4PJQEM.mjs.map +1 -0
  7. package/fesm2022/cloud-ide-academics-cloud-ide-academics-BP1hZ-yx.mjs +2802 -0
  8. package/fesm2022/cloud-ide-academics-cloud-ide-academics-BP1hZ-yx.mjs.map +1 -0
  9. package/fesm2022/cloud-ide-academics-program-class-create.component-Ds8vN9sL.mjs +391 -0
  10. package/fesm2022/cloud-ide-academics-program-class-create.component-Ds8vN9sL.mjs.map +1 -0
  11. package/fesm2022/cloud-ide-academics-program-class-list.component-C6VyX4hH.mjs +433 -0
  12. package/fesm2022/cloud-ide-academics-program-class-list.component-C6VyX4hH.mjs.map +1 -0
  13. package/fesm2022/cloud-ide-academics-program-term-section-create.component-Dg9Pjwj5.mjs +211 -0
  14. package/fesm2022/cloud-ide-academics-program-term-section-create.component-Dg9Pjwj5.mjs.map +1 -0
  15. package/fesm2022/cloud-ide-academics-program-term-section-list.component-xVeeeGDV.mjs +478 -0
  16. package/fesm2022/cloud-ide-academics-program-term-section-list.component-xVeeeGDV.mjs.map +1 -0
  17. package/fesm2022/cloud-ide-academics.mjs +1 -1535
  18. package/fesm2022/cloud-ide-academics.mjs.map +1 -1
  19. package/index.d.ts +239 -2
  20. package/package.json +1 -1
@@ -0,0 +1,2802 @@
1
+ import { authGuard } from 'cloud-ide-auth';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, Injectable, DestroyRef, signal, Component, viewChild, computed } from '@angular/core';
4
+ import * as i1$1 from '@angular/common';
5
+ import { CommonModule, Location } from '@angular/common';
6
+ import * as i1 from '@angular/forms';
7
+ import { FormBuilder, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
8
+ import { Router, ActivatedRoute } from '@angular/router';
9
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
10
+ import { of, forkJoin } from 'rxjs';
11
+ import { switchMap, catchError, map } from 'rxjs/operators';
12
+ import { CideInputComponent, CideTextareaComponent, CideEleButtonComponent, CideEleTabComponent, CideIconComponent, CideSelectComponent, ConfirmationService, NotificationService, CideEleDataGridComponent, CideEleDropdownComponent } from 'cloud-ide-element';
13
+ import { HttpClient } from '@angular/common/http';
14
+ import { generateStringFromObject, cidePath, hostManagerRoutesUrl, academicsRoutesUrl, generateObjectFromString } from 'cloud-ide-lms-model';
15
+ import { ENTITY_SERVICE_TOKEN } from 'cloud-ide-shared';
16
+ import { AppStateHelperService } from 'cloud-ide-layout';
17
+
18
+ const academicsRoutes = [
19
+ // Academic Year Management Routes
20
+ {
21
+ path: 'academic_year',
22
+ loadComponent: () => Promise.resolve().then(function () { return academicYearList_component; }).then(c => c.AcademicYearListComponent),
23
+ title: 'Academic Year Management',
24
+ canActivate: [authGuard],
25
+ data: {
26
+ reuseTab: true,
27
+ sypg_page_code: "academic_year_list"
28
+ }
29
+ },
30
+ {
31
+ path: 'academic_year/create',
32
+ loadComponent: () => Promise.resolve().then(function () { return academicYearCreate_component; }).then(c => c.AcademicYearCreateComponent),
33
+ title: 'Create Academic Year',
34
+ canActivate: [authGuard],
35
+ data: {
36
+ reuseTab: true,
37
+ sypg_page_code: "academic_year_list"
38
+ }
39
+ },
40
+ {
41
+ path: 'academic_year/edit/:query',
42
+ loadComponent: () => Promise.resolve().then(function () { return academicYearCreate_component; }).then(c => c.AcademicYearCreateComponent),
43
+ title: 'Edit Academic Year',
44
+ canActivate: [authGuard],
45
+ data: {
46
+ reuseTab: true,
47
+ sypg_page_code: "academic_year_list"
48
+ }
49
+ },
50
+ {
51
+ path: 'academic_year/view/:query',
52
+ loadComponent: () => Promise.resolve().then(function () { return academicYearCreate_component; }).then(c => c.AcademicYearCreateComponent),
53
+ title: 'View Academic Year',
54
+ canActivate: [authGuard],
55
+ data: {
56
+ reuseTab: true,
57
+ sypg_page_code: "academic_year_list"
58
+ }
59
+ },
60
+ {
61
+ path: 'program-class-management',
62
+ loadComponent: () => import('./cloud-ide-academics-program-class-list.component-C6VyX4hH.mjs').then(c => c.ProgramClassListComponent),
63
+ title: 'Program Class Management',
64
+ canActivate: [authGuard],
65
+ data: {
66
+ reuseTab: false,
67
+ sypg_page_code: "program_class"
68
+ }
69
+ },
70
+ {
71
+ path: 'program-class-management/create',
72
+ loadComponent: () => import('./cloud-ide-academics-program-class-create.component-Ds8vN9sL.mjs').then(c => c.ProgramClassCreateComponent),
73
+ title: 'Create Program Class',
74
+ canActivate: [authGuard],
75
+ data: {
76
+ reuseTab: false,
77
+ sypg_page_code: "program_class"
78
+ }
79
+ },
80
+ {
81
+ path: 'program-class-management/edit/:query',
82
+ loadComponent: () => import('./cloud-ide-academics-program-class-create.component-Ds8vN9sL.mjs').then(c => c.ProgramClassCreateComponent),
83
+ title: 'Edit Program Class',
84
+ canActivate: [authGuard],
85
+ data: {
86
+ reuseTab: false,
87
+ sypg_page_code: "program_class"
88
+ }
89
+ },
90
+ {
91
+ path: 'program-class-management/view/:query',
92
+ loadComponent: () => import('./cloud-ide-academics-program-class-create.component-Ds8vN9sL.mjs').then(c => c.ProgramClassCreateComponent),
93
+ title: 'View Program Class',
94
+ canActivate: [authGuard],
95
+ data: {
96
+ reuseTab: false,
97
+ sypg_page_code: "program_class"
98
+ }
99
+ },
100
+ {
101
+ path: 'program-term-management/create',
102
+ loadComponent: () => import('./cloud-ide-academics-class-program-term-create.component-D3PfbSMN.mjs').then(c => c.ClassProgramTermCreateComponent),
103
+ title: 'Create Class Program Term',
104
+ canActivate: [authGuard],
105
+ data: {
106
+ reuseTab: true,
107
+ sypg_page_code: "class_program_term_list"
108
+ }
109
+ },
110
+ {
111
+ path: 'program-term-management/edit/:query',
112
+ loadComponent: () => import('./cloud-ide-academics-class-program-term-create.component-D3PfbSMN.mjs').then(c => c.ClassProgramTermCreateComponent),
113
+ title: 'Edit Class Program Term',
114
+ canActivate: [authGuard],
115
+ data: {
116
+ reuseTab: true,
117
+ sypg_page_code: "class_program_term_list"
118
+ }
119
+ },
120
+ {
121
+ path: 'program-term-management/view/:query',
122
+ loadComponent: () => import('./cloud-ide-academics-class-program-term-create.component-D3PfbSMN.mjs').then(c => c.ClassProgramTermCreateComponent),
123
+ title: 'View Class Program Term',
124
+ canActivate: [authGuard],
125
+ data: {
126
+ reuseTab: true,
127
+ sypg_page_code: "class_program_term_list"
128
+ }
129
+ },
130
+ {
131
+ path: 'program-term-management/:query',
132
+ loadComponent: () => import('./cloud-ide-academics-class-program-term-list.component-Cpbyavgd.mjs').then(c => c.ClassProgramTermListComponent),
133
+ title: 'Class Program Term Management',
134
+ canActivate: [authGuard],
135
+ data: {
136
+ reuseTab: true,
137
+ sypg_page_code: "class_program_term_list"
138
+ }
139
+ },
140
+ {
141
+ path: 'class-program-term/:query',
142
+ loadComponent: () => import('./cloud-ide-academics-program-term-section-list.component-xVeeeGDV.mjs').then(c => c.ProgramTermSectionListComponent),
143
+ title: 'Program Term Section Management',
144
+ canActivate: [authGuard],
145
+ data: {
146
+ reuseTab: true,
147
+ sypg_page_code: "program_term_section_list"
148
+ }
149
+ },
150
+ {
151
+ path: 'class-program-term/create',
152
+ loadComponent: () => import('./cloud-ide-academics-program-term-section-create.component-Dg9Pjwj5.mjs').then(c => c.ProgramTermSectionCreateComponent),
153
+ title: 'Create Program Term Section',
154
+ canActivate: [authGuard],
155
+ data: {
156
+ reuseTab: true,
157
+ sypg_page_code: "program_term_section_list"
158
+ }
159
+ },
160
+ {
161
+ path: 'class-program-term/edit/:query',
162
+ loadComponent: () => import('./cloud-ide-academics-program-term-section-create.component-Dg9Pjwj5.mjs').then(c => c.ProgramTermSectionCreateComponent),
163
+ title: 'Edit Program Term Section',
164
+ canActivate: [authGuard],
165
+ data: {
166
+ reuseTab: true,
167
+ sypg_page_code: "program_term_section_list"
168
+ }
169
+ },
170
+ {
171
+ path: 'class-program-term/view/:query',
172
+ loadComponent: () => import('./cloud-ide-academics-program-term-section-create.component-Dg9Pjwj5.mjs').then(c => c.ProgramTermSectionCreateComponent),
173
+ title: 'View Program Term Section',
174
+ canActivate: [authGuard],
175
+ data: {
176
+ reuseTab: true,
177
+ sypg_page_code: "program_term_section_list"
178
+ }
179
+ },
180
+ // Class Program Branch Management Routes
181
+ {
182
+ path: 'program_specialization/:query',
183
+ loadComponent: () => Promise.resolve().then(function () { return classProgramBranchList_component; }).then(c => c.CideLytClassProgramBranchListComponent),
184
+ title: 'Class Program Branch Management',
185
+ canActivate: [authGuard],
186
+ data: {
187
+ reuseTab: true,
188
+ sypg_page_code: "class_program_branch"
189
+ }
190
+ },
191
+ {
192
+ path: 'program_specialization',
193
+ loadComponent: () => Promise.resolve().then(function () { return classProgramBranchList_component; }).then(c => c.CideLytClassProgramBranchListComponent),
194
+ title: 'Class Program Branch Management',
195
+ canActivate: [authGuard],
196
+ data: {
197
+ reuseTab: true,
198
+ sypg_page_code: "class_program_branch"
199
+ }
200
+ },
201
+ {
202
+ path: 'program_specialization/create/:query?',
203
+ loadComponent: () => Promise.resolve().then(function () { return classProgramBranchForm_component; }).then(c => c.CideLytClassProgramBranchFormComponent),
204
+ title: 'Create Class Program Branch',
205
+ canActivate: [authGuard],
206
+ data: {
207
+ reuseTab: true,
208
+ sypg_page_code: "class_program_branch"
209
+ }
210
+ },
211
+ {
212
+ path: 'program_specialization/edit/:query',
213
+ loadComponent: () => Promise.resolve().then(function () { return classProgramBranchForm_component; }).then(c => c.CideLytClassProgramBranchFormComponent),
214
+ title: 'Edit Class Program Branch',
215
+ canActivate: [authGuard],
216
+ data: {
217
+ reuseTab: true,
218
+ sypg_page_code: "class_program_branch"
219
+ }
220
+ },
221
+ {
222
+ path: 'program_specialization/view/:query',
223
+ loadComponent: () => Promise.resolve().then(function () { return classProgramBranchForm_component; }).then(c => c.CideLytClassProgramBranchFormComponent),
224
+ title: 'View Class Program Branch',
225
+ canActivate: [authGuard],
226
+ data: {
227
+ reuseTab: true,
228
+ sypg_page_code: "class_program_branch"
229
+ }
230
+ }
231
+ ];
232
+
233
+ class CideLytAcademicYearService {
234
+ http = inject(HttpClient);
235
+ /**
236
+ * Get list of academic years
237
+ * @param payload - Query parameters for filtering/pagination
238
+ * @returns Observable of academic year list response
239
+ */
240
+ getAcademicYearList(payload) {
241
+ console.log("payload", payload);
242
+ const query = generateStringFromObject(payload);
243
+ const url = cidePath.join([
244
+ hostManagerRoutesUrl.cideSuiteHost,
245
+ academicsRoutesUrl.module,
246
+ academicsRoutesUrl.academicYear,
247
+ query
248
+ ]);
249
+ return this.http.get(url);
250
+ }
251
+ /**
252
+ * Get academic year by ID
253
+ * @param payload - Academic year ID payload
254
+ * @returns Observable of academic year data
255
+ */
256
+ getAcademicYearById(payload) {
257
+ const query = generateStringFromObject(payload);
258
+ const url = cidePath.join([
259
+ hostManagerRoutesUrl.cideSuiteHost,
260
+ academicsRoutesUrl.module,
261
+ academicsRoutesUrl.academicYear,
262
+ 'byId',
263
+ query
264
+ ]);
265
+ return this.http.get(url);
266
+ }
267
+ /**
268
+ * Create or update academic year
269
+ * @param data - Academic year data to save
270
+ * @returns Observable of the save response
271
+ */
272
+ saveUpdateAcademicYear(data) {
273
+ const url = cidePath.join([
274
+ hostManagerRoutesUrl.cideSuiteHost,
275
+ academicsRoutesUrl.module,
276
+ academicsRoutesUrl.academicYear
277
+ ]);
278
+ return this.http.post(url, data);
279
+ }
280
+ /**
281
+ * Create or update academic year with mappings
282
+ * @param data - Academic year data with mappings
283
+ * @returns Observable of the save response
284
+ */
285
+ saveUpdateAcademicYearWithMappings(data) {
286
+ // Extract mappings from the data
287
+ const mappings = data.acayr_academic_year_mappings || [];
288
+ const academicYearData = { ...data };
289
+ delete academicYearData.acayr_academic_year_mappings;
290
+ // First save/update the academic year
291
+ return this.saveUpdateAcademicYear(academicYearData).pipe(switchMap((academicYearResponse) => {
292
+ if (!academicYearResponse.success || !academicYearResponse.data) {
293
+ return of(academicYearResponse);
294
+ }
295
+ const academicYearId = academicYearResponse.data._id;
296
+ // If no mappings, return the academic year response
297
+ if (mappings.length === 0) {
298
+ return of(academicYearResponse);
299
+ }
300
+ // Process mappings
301
+ const mappingObservables = mappings.map((mapping) => {
302
+ const mappingPayload = {
303
+ _id: mapping._id && !mapping._id.startsWith('temp_') ? mapping._id : undefined,
304
+ acayrmp_academic_year_id_acayr: academicYearId,
305
+ acayrmp_entity_id_syen: mapping.acayrmp_entity_id_syen,
306
+ acayrmp_islocked: mapping.acayrmp_islocked || false,
307
+ acayrmp_iscurrent: mapping.acayrmp_iscurrent || false
308
+ };
309
+ const mappingUrl = cidePath.join([
310
+ hostManagerRoutesUrl.cideSuiteHost,
311
+ academicsRoutesUrl.module,
312
+ academicsRoutesUrl.academicYearMapping
313
+ ]);
314
+ return this.http.post(mappingUrl, mappingPayload).pipe(catchError((error) => {
315
+ console.error('Error saving mapping:', error);
316
+ return of({ success: false, error });
317
+ }));
318
+ });
319
+ // Execute all mapping operations
320
+ return forkJoin(mappingObservables).pipe(map((mappingResponses) => {
321
+ // Check if all mappings were successful
322
+ const allMappingsSuccessful = mappingResponses.every((response) => response.success);
323
+ if (allMappingsSuccessful) {
324
+ return {
325
+ ...academicYearResponse,
326
+ message: 'Academic year and mappings saved successfully'
327
+ };
328
+ }
329
+ else {
330
+ return {
331
+ ...academicYearResponse,
332
+ message: 'Academic year saved but some mappings failed',
333
+ mappingErrors: mappingResponses.filter((response) => !response.success)
334
+ };
335
+ }
336
+ }));
337
+ }), catchError((error) => {
338
+ console.error('Error in saveUpdateAcademicYearWithMappings:', error);
339
+ return of({
340
+ success: false,
341
+ code: 500,
342
+ message: 'Error saving academic year with mappings',
343
+ error
344
+ });
345
+ }));
346
+ }
347
+ /**
348
+ * Delete academic year
349
+ * @param payload - Academic year ID payload
350
+ * @returns Observable of the delete response
351
+ */
352
+ deleteAcademicYear(payload) {
353
+ const query = generateStringFromObject(payload);
354
+ const url = cidePath.join([
355
+ hostManagerRoutesUrl.cideSuiteHost,
356
+ academicsRoutesUrl.module,
357
+ academicsRoutesUrl.academicYear,
358
+ 'delete',
359
+ query
360
+ ]);
361
+ return this.http.delete(url);
362
+ }
363
+ /**
364
+ * Toggle academic year status
365
+ * @param payload - Academic year ID payload
366
+ * @returns Observable of the toggle response
367
+ */
368
+ toggleAcademicYearStatus(payload) {
369
+ const url = cidePath.join([
370
+ hostManagerRoutesUrl.cideSuiteHost,
371
+ academicsRoutesUrl.module,
372
+ academicsRoutesUrl.academicYear,
373
+ 'toggle-status'
374
+ ]);
375
+ console.log('🔄 Making PATCH request to toggle academic year status:', { url, payload });
376
+ return this.http.patch(url, payload);
377
+ }
378
+ /**
379
+ * Delete academic year mapping
380
+ * @param payload - Academic year mapping ID payload
381
+ * @returns Observable of the delete response
382
+ */
383
+ deleteAcademicYearMapping(payload) {
384
+ const url = cidePath.join([
385
+ hostManagerRoutesUrl.cideSuiteHost,
386
+ academicsRoutesUrl.module,
387
+ academicsRoutesUrl.academicYearMapping
388
+ ]);
389
+ return this.http.delete(url, { body: payload });
390
+ }
391
+ /**
392
+ * Toggle academic year mapping status
393
+ * @param payload - Academic year mapping ID payload
394
+ * @returns Observable of the toggle response
395
+ */
396
+ toggleAcademicYearMappingStatus(payload) {
397
+ const url = cidePath.join([
398
+ hostManagerRoutesUrl.cideSuiteHost,
399
+ academicsRoutesUrl.module,
400
+ academicsRoutesUrl.academicYearMapping,
401
+ 'toggle-status'
402
+ ]);
403
+ console.log('🔄 Making PATCH request to toggle academic year mapping status:', { url, payload });
404
+ return this.http.patch(url, payload);
405
+ }
406
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytAcademicYearService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
407
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytAcademicYearService, providedIn: 'root' });
408
+ }
409
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytAcademicYearService, decorators: [{
410
+ type: Injectable,
411
+ args: [{
412
+ providedIn: 'root'
413
+ }]
414
+ }] });
415
+
416
+ class CideLytAcademicYearMappingService {
417
+ http = inject(HttpClient);
418
+ /**
419
+ * Get list of academic year mappings
420
+ * @param payload - Query parameters for filtering/pagination
421
+ * @returns Observable of academic year mapping list response
422
+ */
423
+ getAcademicYearMappingList(payload) {
424
+ const query = generateStringFromObject(payload);
425
+ const url = cidePath.join([
426
+ hostManagerRoutesUrl.cideSuiteHost,
427
+ academicsRoutesUrl.module,
428
+ academicsRoutesUrl.academicYearMapping,
429
+ query
430
+ ]);
431
+ return this.http.get(url);
432
+ }
433
+ /**
434
+ * Get academic year mapping by ID
435
+ * @param payload - Academic year mapping ID payload
436
+ * @returns Observable of academic year mapping data
437
+ */
438
+ getAcademicYearMappingById(payload) {
439
+ const query = generateStringFromObject(payload);
440
+ const url = cidePath.join([
441
+ hostManagerRoutesUrl.cideSuiteHost,
442
+ academicsRoutesUrl.module,
443
+ academicsRoutesUrl.academicYearMapping,
444
+ 'byId',
445
+ query
446
+ ]);
447
+ return this.http.get(url);
448
+ }
449
+ /**
450
+ * Create or update academic year mapping
451
+ * @param data - Academic year mapping data to save
452
+ * @returns Observable of the save response
453
+ */
454
+ saveUpdateAcademicYearMapping(data) {
455
+ const url = cidePath.join([
456
+ hostManagerRoutesUrl.cideSuiteHost,
457
+ academicsRoutesUrl.module,
458
+ academicsRoutesUrl.academicYearMapping
459
+ ]);
460
+ return this.http.post(url, data);
461
+ }
462
+ /**
463
+ * Delete academic year mapping
464
+ * @param payload - Academic year mapping ID payload
465
+ * @returns Observable of the delete response
466
+ */
467
+ deleteAcademicYearMapping(payload) {
468
+ const query = generateStringFromObject(payload);
469
+ const url = cidePath.join([
470
+ hostManagerRoutesUrl.cideSuiteHost,
471
+ academicsRoutesUrl.module,
472
+ academicsRoutesUrl.academicYearMapping,
473
+ 'delete',
474
+ query
475
+ ]);
476
+ return this.http.delete(url);
477
+ }
478
+ /**
479
+ * Toggle academic year mapping status
480
+ * @param payload - Academic year mapping ID payload
481
+ * @returns Observable of the toggle response
482
+ */
483
+ toggleAcademicYearMappingStatus(payload) {
484
+ const url = cidePath.join([
485
+ hostManagerRoutesUrl.cideSuiteHost,
486
+ academicsRoutesUrl.module,
487
+ academicsRoutesUrl.academicYearMapping,
488
+ 'toggle-status'
489
+ ]);
490
+ return this.http.post(url, payload);
491
+ }
492
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytAcademicYearMappingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
493
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytAcademicYearMappingService, providedIn: 'root' });
494
+ }
495
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytAcademicYearMappingService, decorators: [{
496
+ type: Injectable,
497
+ args: [{
498
+ providedIn: 'root'
499
+ }]
500
+ }] });
501
+
502
+ class AcademicYearCreateComponent {
503
+ // Modern Angular 20+ dependency injection
504
+ destroyRef = inject(DestroyRef);
505
+ fb = inject(FormBuilder);
506
+ academicYearService = inject(CideLytAcademicYearService);
507
+ academicYearMappingService = inject(CideLytAcademicYearMappingService);
508
+ entityService = inject(ENTITY_SERVICE_TOKEN);
509
+ router = inject(Router);
510
+ route = inject(ActivatedRoute);
511
+ // Form and state management with proper typing
512
+ academicYearForm;
513
+ activeTab = signal('basic', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
514
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
515
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
516
+ // Academic year information from route
517
+ academicYearId = signal('', ...(ngDevMode ? [{ debugName: "academicYearId" }] : []));
518
+ isEditMode = signal(false, ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
519
+ originalMappings = signal([], ...(ngDevMode ? [{ debugName: "originalMappings" }] : [])); // Track original mappings for deletion
520
+ // Entity options for dropdown
521
+ entityOptions = signal([], ...(ngDevMode ? [{ debugName: "entityOptions" }] : []));
522
+ constructor() {
523
+ this.academicYearForm = this.fb.group({
524
+ // Basic Academic Year Information
525
+ acayr_code: ['', [Validators.required]],
526
+ acayr_name: ['', [Validators.required]],
527
+ acayr_description: [''],
528
+ acayr_from_date: ['', [Validators.required]],
529
+ acayr_to_date: ['', [Validators.required]],
530
+ acayr_isactive: [true],
531
+ acayr_iscurrent: [false],
532
+ acayr_islocked: [false],
533
+ // Academic Year Mapping Information
534
+ acayr_academic_year_mappings: this.fb.array([])
535
+ });
536
+ }
537
+ ngOnInit() {
538
+ this.initializeComponent();
539
+ }
540
+ /**
541
+ * Initialize component
542
+ */
543
+ initializeComponent() {
544
+ // Get academic year information from route (for edit mode)
545
+ this.route.params.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(params => {
546
+ const queryParams = params['query'];
547
+ console.log(queryParams, 'queryParams');
548
+ if (queryParams) {
549
+ // Query parameters passed (following page-controls pattern)
550
+ const queryData = generateObjectFromString(queryParams);
551
+ if (queryData?.acayr_id) {
552
+ this.academicYearId.set(queryData.acayr_id);
553
+ this.isEditMode.set(true);
554
+ this.loadAcademicYearData(queryData.acayr_id);
555
+ }
556
+ }
557
+ else {
558
+ // Create mode
559
+ this.isEditMode.set(false);
560
+ }
561
+ // Always load dropdown options
562
+ this.loadDropdownOptions();
563
+ });
564
+ }
565
+ /**
566
+ * Load dropdown options
567
+ */
568
+ loadDropdownOptions() {
569
+ console.log('🏢 Loading dropdown options');
570
+ // Load entity options
571
+ this.entityService.getEntityList({}).subscribe({
572
+ next: (response) => {
573
+ if (response?.success) {
574
+ console.log(`🏢 entities:`, response.data);
575
+ this.entityOptions.set(response.data || []);
576
+ }
577
+ },
578
+ error: (error) => console.error('Error loading entities:', error)
579
+ });
580
+ }
581
+ /**
582
+ * Load academic year data for edit mode
583
+ */
584
+ loadAcademicYearData(academicYearId) {
585
+ this.loading.set(true);
586
+ this.error.set(null);
587
+ const payload = {
588
+ acayr_id: academicYearId
589
+ };
590
+ // Load academic year data
591
+ this.academicYearService.getAcademicYearById(payload).subscribe({
592
+ next: (response) => {
593
+ if (response?.success && response.data) {
594
+ console.log('📚 Academic year data loaded:', response.data);
595
+ this.populateFormWithAcademicYearData(response.data);
596
+ // Load existing mappings for this academic year
597
+ this.loadAcademicYearMappings(academicYearId);
598
+ }
599
+ else {
600
+ console.error('❌ Failed to load academic year data');
601
+ this.error.set('Failed to load academic year data');
602
+ this.loading.set(false);
603
+ }
604
+ },
605
+ error: (error) => {
606
+ console.error('❌ Error loading academic year data:', error);
607
+ this.error.set('Error loading academic year data');
608
+ this.loading.set(false);
609
+ }
610
+ });
611
+ }
612
+ /**
613
+ * Load academic year mappings for edit mode
614
+ */
615
+ loadAcademicYearMappings(academicYearId) {
616
+ const mappingPayload = {
617
+ acayrmp_academic_year_id_acayr: academicYearId
618
+ };
619
+ this.academicYearMappingService.getAcademicYearMappingList(mappingPayload).subscribe({
620
+ next: (response) => {
621
+ if (response?.success && response.data) {
622
+ console.log('🔗 Academic year mappings loaded:', response.data);
623
+ this.populateFormWithMappingsData(response.data);
624
+ }
625
+ else {
626
+ console.warn('⚠️ No mappings found for this academic year');
627
+ }
628
+ this.loading.set(false);
629
+ },
630
+ error: (error) => {
631
+ console.error('❌ Error loading academic year mappings:', error);
632
+ this.loading.set(false);
633
+ }
634
+ });
635
+ }
636
+ /**
637
+ * Populate form with academic year data
638
+ */
639
+ populateFormWithAcademicYearData(data) {
640
+ if (data) {
641
+ this.academicYearForm.patchValue({
642
+ acayr_code: data.acayr_code || '',
643
+ acayr_name: data.acayr_name || '',
644
+ acayr_description: data.acayr_description || '',
645
+ acayr_from_date: data.acayr_from_date ? new Date(data.acayr_from_date).toISOString().split('T')[0] : '',
646
+ acayr_to_date: data.acayr_to_date ? new Date(data.acayr_to_date).toISOString().split('T')[0] : '',
647
+ acayr_isactive: data.acayr_isactive ?? true,
648
+ acayr_iscurrent: data.acayr_iscurrent ?? false,
649
+ acayr_islocked: data.acayr_islocked ?? false
650
+ });
651
+ }
652
+ }
653
+ /**
654
+ * Populate form with mappings data
655
+ */
656
+ populateFormWithMappingsData(mappings) {
657
+ if (mappings && Array.isArray(mappings)) {
658
+ // Store original mappings for deletion tracking
659
+ this.originalMappings.set([...mappings]);
660
+ // Clear existing mappings
661
+ while (this.academicYearMappingsArray.length !== 0) {
662
+ this.academicYearMappingsArray.removeAt(0);
663
+ }
664
+ // Add existing mappings
665
+ mappings.forEach((mapping) => {
666
+ const mappingGroup = this.fb.group({
667
+ _id: [mapping._id || ''],
668
+ acayrmp_academic_year_id_acayr: [mapping.acayrmp_academic_year_id_acayr || this.academicYearId() || '', [Validators.required]],
669
+ acayrmp_entity_id_syen: [mapping.acayrmp_entity_id_syen || '', [Validators.required]],
670
+ acayrmp_islocked: [mapping.acayrmp_islocked ?? false],
671
+ acayrmp_iscurrent: [mapping.acayrmp_iscurrent ?? false]
672
+ });
673
+ this.academicYearMappingsArray.push(mappingGroup);
674
+ });
675
+ }
676
+ }
677
+ /**
678
+ * Tab configuration
679
+ */
680
+ academicYearTabs() {
681
+ return [
682
+ { id: 'basic', label: 'Academic Year Details', icon: 'school' },
683
+ { id: 'mapping', label: 'Mapping Configuration', icon: 'link' }
684
+ ];
685
+ }
686
+ onTabChange(tab) {
687
+ this.activeTab.set(tab.id);
688
+ }
689
+ onSubmit() {
690
+ // Clear any previous errors
691
+ this.error.set(null);
692
+ if (this.academicYearForm.valid && this.validateMappings()) {
693
+ this.loading.set(true);
694
+ const formData = this.academicYearForm.value;
695
+ // Prepare payload with mappings
696
+ const payload = {
697
+ ...formData,
698
+ _id: this.isEditMode() ? this.academicYearId() : undefined,
699
+ acayr_academic_year_mappings: this.getAcademicYearMappingsValue()
700
+ };
701
+ console.log('📤 Submitting academic year with mappings:', payload);
702
+ // First delete removed mappings, then save/update academic year
703
+ this.deleteRemovedMappings().pipe(switchMap(() => {
704
+ // After deleting removed mappings, save/update the academic year
705
+ return this.academicYearService.saveUpdateAcademicYearWithMappings(payload);
706
+ })).subscribe({
707
+ next: (response) => {
708
+ if (response?.success) {
709
+ console.log('✅ Academic year and mappings saved successfully:', response.data);
710
+ // Check if there were any mapping errors
711
+ if (response.mappingErrors && response.mappingErrors.length > 0) {
712
+ console.warn('⚠️ Some mappings failed:', response.mappingErrors);
713
+ this.error.set('Academic year saved but some mappings failed. Please check the mappings.');
714
+ }
715
+ else {
716
+ this.goBackToAcademicYearList();
717
+ }
718
+ }
719
+ else {
720
+ console.error('❌ Failed to save academic year');
721
+ this.error.set(response?.message || 'Failed to save academic year');
722
+ }
723
+ this.loading.set(false);
724
+ },
725
+ error: (error) => {
726
+ console.error('❌ Error saving academic year:', error);
727
+ this.error.set('Error saving academic year');
728
+ this.loading.set(false);
729
+ }
730
+ });
731
+ }
732
+ else {
733
+ console.warn('Form is invalid');
734
+ this.markFormGroupTouched();
735
+ }
736
+ }
737
+ /**
738
+ * Mark all form controls as touched to trigger validation display
739
+ */
740
+ markFormGroupTouched() {
741
+ Object.keys(this.academicYearForm.controls).forEach(key => {
742
+ const control = this.academicYearForm.get(key);
743
+ control?.markAsTouched();
744
+ });
745
+ }
746
+ resetForm() {
747
+ this.academicYearForm.reset({
748
+ acayr_isactive: true,
749
+ acayr_iscurrent: false,
750
+ acayr_islocked: false
751
+ });
752
+ // Clear the mappings array
753
+ while (this.academicYearMappingsArray.length !== 0) {
754
+ this.academicYearMappingsArray.removeAt(0);
755
+ }
756
+ // Reset academic year ID
757
+ this.academicYearId.set('');
758
+ this.isEditMode.set(false);
759
+ this.originalMappings.set([]);
760
+ // Reset entity options to show all entities again
761
+ this.updateEntityOptionsForMappings();
762
+ }
763
+ /**
764
+ * Go back to academic year list
765
+ */
766
+ goBackToAcademicYearList() {
767
+ this.router.navigate(['/control-panel/academic-year']);
768
+ }
769
+ /**
770
+ * Cancel form and optionally navigate back
771
+ */
772
+ cancelForm() {
773
+ if (this.isEditMode()) {
774
+ this.goBackToAcademicYearList();
775
+ }
776
+ else {
777
+ this.resetForm();
778
+ }
779
+ }
780
+ /**
781
+ * Get page title based on mode
782
+ */
783
+ getPageTitle() {
784
+ return this.isEditMode() ? 'Edit Academic Year' : 'Create New Academic Year';
785
+ }
786
+ /**
787
+ * Getter methods for form arrays
788
+ */
789
+ get academicYearMappingsArray() {
790
+ return this.academicYearForm.get('acayr_academic_year_mappings');
791
+ }
792
+ /**
793
+ * Add new academic year mapping
794
+ */
795
+ addAcademicYearMapping() {
796
+ // Check if there are any available entities to map
797
+ const availableEntities = this.getAvailableEntityCount(this.academicYearMappingsArray.length);
798
+ if (availableEntities === 0) {
799
+ console.warn('No available entities to map');
800
+ return;
801
+ }
802
+ // Generate a temporary ID for new mappings
803
+ const tempId = 'temp_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
804
+ const academicYearMapping = this.fb.group({
805
+ _id: [tempId],
806
+ acayrmp_academic_year_id_acayr: [this.academicYearId() || '', [Validators.required]],
807
+ acayrmp_entity_id_syen: ['', [Validators.required]],
808
+ acayrmp_islocked: [false],
809
+ acayrmp_iscurrent: [false]
810
+ });
811
+ this.academicYearMappingsArray.push(academicYearMapping);
812
+ }
813
+ /**
814
+ * Update academic year ID in all existing mappings when academic year ID changes
815
+ */
816
+ updateMappingsAcademicYearId(newAcademicYearId) {
817
+ const mappingsArray = this.academicYearMappingsArray;
818
+ mappingsArray.controls.forEach((control) => {
819
+ if (control.get('acayrmp_academic_year_id_acayr')) {
820
+ control.get('acayrmp_academic_year_id_acayr').setValue(newAcademicYearId);
821
+ }
822
+ });
823
+ }
824
+ /**
825
+ * Get form array value for validation or submission
826
+ */
827
+ getAcademicYearMappingsValue() {
828
+ return this.academicYearMappingsArray.value;
829
+ }
830
+ /**
831
+ * Check if mappings array has any invalid controls
832
+ */
833
+ isMappingsArrayValid() {
834
+ return this.academicYearMappingsArray.valid;
835
+ }
836
+ /**
837
+ * Set academic year ID for all existing mappings
838
+ * This is useful when the academic year ID is generated after creation
839
+ */
840
+ setAcademicYearIdForMappings(academicYearId) {
841
+ this.academicYearId.set(academicYearId);
842
+ this.updateMappingsAcademicYearId(academicYearId);
843
+ }
844
+ /**
845
+ * Validate that all mappings have required fields
846
+ */
847
+ validateMappings() {
848
+ const mappings = this.academicYearMappingsArray.controls;
849
+ // Check if there are any mappings
850
+ if (mappings.length === 0) {
851
+ return true; // No mappings is valid
852
+ }
853
+ // Validate each mapping
854
+ for (let i = 0; i < mappings.length; i++) {
855
+ const mapping = mappings[i];
856
+ // Check required fields
857
+ if (!mapping.get('acayrmp_entity_id_syen')?.value) {
858
+ console.warn(`Mapping ${i + 1} is missing entity selection`);
859
+ this.error.set(`Mapping ${i + 1} requires an entity selection`);
860
+ return false;
861
+ }
862
+ // Check for duplicate entity selections
863
+ const currentEntityId = mapping.get('acayrmp_entity_id_syen')?.value;
864
+ const duplicateIndex = this.findDuplicateEntitySelection(currentEntityId, i);
865
+ if (duplicateIndex !== -1) {
866
+ console.warn(`Mapping ${i + 1} has duplicate entity selection with mapping ${duplicateIndex + 1}`);
867
+ this.error.set(`Mapping ${i + 1} has duplicate entity selection with mapping ${duplicateIndex + 1}`);
868
+ return false;
869
+ }
870
+ }
871
+ return true;
872
+ }
873
+ /**
874
+ * Find duplicate entity selection in mappings
875
+ */
876
+ findDuplicateEntitySelection(entityId, currentIndex) {
877
+ const mappings = this.academicYearMappingsArray.controls;
878
+ for (let i = 0; i < mappings.length; i++) {
879
+ if (i !== currentIndex) {
880
+ const mapping = mappings[i];
881
+ if (mapping.get('acayrmp_entity_id_syen')?.value === entityId) {
882
+ return i;
883
+ }
884
+ }
885
+ }
886
+ return -1;
887
+ }
888
+ /**
889
+ * Remove academic year mapping
890
+ */
891
+ removeAcademicYearMapping(index) {
892
+ this.academicYearMappingsArray.removeAt(index);
893
+ // Update entity options after removal to re-enable previously selected entities
894
+ this.updateEntityOptionsForMappings();
895
+ }
896
+ /**
897
+ * Handle entity selection change for a specific mapping
898
+ */
899
+ onMappingEntityChange(event, mappingIndex) {
900
+ const selectedEntityId = event?.value || event;
901
+ if (selectedEntityId) {
902
+ console.log(`🏢 Entity selected for mapping ${mappingIndex}:`, selectedEntityId);
903
+ // Trigger change detection to update other mappings' entity options
904
+ this.updateEntityOptionsForMappings();
905
+ }
906
+ }
907
+ /**
908
+ * Get filtered entity options excluding already selected entities in other mappings
909
+ * @param currentMappingIndex The index of the current mapping being edited
910
+ * @returns Entity options excluding already selected entities
911
+ */
912
+ getFilteredEntityOptions(currentMappingIndex) {
913
+ const allEntities = this.entityOptions();
914
+ if (!allEntities || allEntities.length === 0) {
915
+ return [];
916
+ }
917
+ // Get all currently selected entity IDs from other mappings (excluding current mapping)
918
+ const selectedEntityIds = this.getSelectedEntityIds(currentMappingIndex);
919
+ console.log(`🔍 Filtering entities for mapping ${currentMappingIndex}:`, {
920
+ totalEntities: allEntities.length,
921
+ selectedEntityIds,
922
+ availableEntities: allEntities.length - selectedEntityIds.length
923
+ });
924
+ // Return only entities that are not already selected in other mappings
925
+ return allEntities.filter((entity) => {
926
+ const entityId = entity._id;
927
+ const isAlreadySelected = selectedEntityIds.includes(entityId);
928
+ if (isAlreadySelected) {
929
+ console.log(`🚫 Entity "${entity.syen_name}" (${entityId}) is already selected in another mapping - excluding from options`);
930
+ }
931
+ return !isAlreadySelected;
932
+ });
933
+ }
934
+ /**
935
+ * Get all currently selected entity IDs from other mappings
936
+ */
937
+ getSelectedEntityIds(excludeMappingIndex) {
938
+ const mappingsArray = this.academicYearMappingsArray;
939
+ const selectedIds = [];
940
+ mappingsArray.controls.forEach((control, index) => {
941
+ if (index !== excludeMappingIndex) {
942
+ const entityId = control.get('acayrmp_entity_id_syen')?.value;
943
+ if (entityId) {
944
+ selectedIds.push(entityId);
945
+ }
946
+ }
947
+ });
948
+ return selectedIds;
949
+ }
950
+ /**
951
+ * Update entity options for all mappings to prevent duplicates
952
+ */
953
+ updateEntityOptionsForMappings() {
954
+ // This method triggers change detection to update the UI
955
+ // The actual filtering is done in getEntityOptionsForMapping method
956
+ console.log('🔄 Updating entity options for all mappings');
957
+ }
958
+ /**
959
+ * Check if an entity is disabled for a specific mapping
960
+ */
961
+ isEntityDisabled(entityId, mappingIndex) {
962
+ const selectedEntityIds = this.getSelectedEntityIds(mappingIndex);
963
+ return selectedEntityIds.includes(entityId);
964
+ }
965
+ /**
966
+ * Get the count of available entities for a specific mapping
967
+ */
968
+ getAvailableEntityCount(mappingIndex) {
969
+ const availableEntities = this.getFilteredEntityOptions(mappingIndex);
970
+ return availableEntities.length;
971
+ }
972
+ /**
973
+ * Get the count of total entities
974
+ */
975
+ getTotalEntityCount() {
976
+ return this.entityOptions().length;
977
+ }
978
+ /**
979
+ * Check if all entities are already selected in other mappings
980
+ * @param currentMappingIndex The index of the current mapping being edited
981
+ * @returns True if all entities are already selected
982
+ */
983
+ isAllEntitiesSelected(currentMappingIndex) {
984
+ const allEntities = this.entityOptions();
985
+ const currentMappings = this.academicYearMappingsArray.value;
986
+ // Get all selected entity IDs from other mappings (excluding current mapping)
987
+ const selectedEntityIds = currentMappings
988
+ .map((mapping, index) => {
989
+ if (index !== currentMappingIndex && mapping.acayrmp_entity_id_syen) {
990
+ return mapping.acayrmp_entity_id_syen;
991
+ }
992
+ return null;
993
+ })
994
+ .filter((id) => id !== null && id !== '');
995
+ // Check if all entities are selected
996
+ return allEntities.length > 0 && selectedEntityIds.length >= allEntities.length;
997
+ }
998
+ /**
999
+ * Check if all entities are already mapped (for disabling Add Entity Mapping button)
1000
+ * @returns True if all entities are already mapped
1001
+ */
1002
+ isAllEntitiesMapped() {
1003
+ const allEntities = this.entityOptions();
1004
+ const currentMappings = this.academicYearMappingsArray.value;
1005
+ // Get all selected entity IDs
1006
+ const selectedEntityIds = currentMappings
1007
+ .map((mapping) => {
1008
+ if (mapping.acayrmp_entity_id_syen) {
1009
+ return mapping.acayrmp_entity_id_syen;
1010
+ }
1011
+ return null;
1012
+ })
1013
+ .filter((id) => id !== null && id !== '');
1014
+ // Check if all entities are selected
1015
+ return allEntities.length > 0 && selectedEntityIds.length >= allEntities.length;
1016
+ }
1017
+ /**
1018
+ * Cleanup when component is destroyed
1019
+ * This ensures that when the component is destroyed (e.g., tab closed),
1020
+ * all state is properly reset to prevent old data from persisting
1021
+ */
1022
+ ngOnDestroy() {
1023
+ console.log('🧹 AcademicYearCreateComponent: Cleaning up component state');
1024
+ // Reset all signals to their initial state
1025
+ this.activeTab.set('basic');
1026
+ this.loading.set(false);
1027
+ this.error.set(null);
1028
+ this.academicYearId.set('');
1029
+ this.isEditMode.set(false);
1030
+ this.originalMappings.set([]);
1031
+ this.entityOptions.set([]);
1032
+ // Reset form to initial state
1033
+ this.resetForm();
1034
+ console.log('🧹 AcademicYearCreateComponent: Component state cleaned up');
1035
+ }
1036
+ /**
1037
+ * Delete removed academic year mappings
1038
+ */
1039
+ deleteRemovedMappings() {
1040
+ const originalMappings = this.originalMappings();
1041
+ const currentMappings = this.getAcademicYearMappingsValue();
1042
+ // Find mappings that were removed (exist in original but not in current)
1043
+ const removedMappings = originalMappings.filter(originalMapping => {
1044
+ return !currentMappings.some(currentMapping => currentMapping._id === originalMapping._id && originalMapping._id);
1045
+ });
1046
+ console.log('🗑️ Mappings to delete:', removedMappings);
1047
+ if (removedMappings.length === 0) {
1048
+ return of([]);
1049
+ }
1050
+ // Create delete observables for each removed mapping
1051
+ const deleteObservables = removedMappings.map(mapping => {
1052
+ return this.academicYearService.deleteAcademicYearMapping({
1053
+ acayrmp_id: mapping._id || ''
1054
+ }).pipe(catchError(error => {
1055
+ console.error('❌ Error deleting mapping:', error);
1056
+ return of({ success: false, error, mappingId: mapping._id });
1057
+ }));
1058
+ });
1059
+ return forkJoin(deleteObservables);
1060
+ }
1061
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: AcademicYearCreateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1062
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: AcademicYearCreateComponent, isStandalone: true, selector: "cide-core-academic-year-create", ngImport: i0, template: "<!-- \r\n ACADEMIC YEAR MASTER FORM\r\n \r\n Enterprise-Level Styling with Tailwind CSS\r\n Features: Responsive grids, proper typography, enhanced user experience\r\n-->\r\n\r\n<div class=\"tw-w-full tw-h-full\">\r\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"academicYearForm\" [class.tw-opacity-60]=\"loading()\"\r\n (ngSubmit)=\"onSubmit()\">\r\n\r\n <!-- Simple Header Section -->\r\n <div class=\"tw-table-row tw-w-full tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n \r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">school</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">\r\n {{ isEditMode() ? 'Edit Academic Year' : 'Create Academic Year' }}\r\n </h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <!-- Back button or other actions can be added here if needed -->\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Tab Navigation -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-2 tw-py-0\">\r\n <cide-ele-tab [tabs]=\"academicYearTabs()\" [activeTabId]=\"activeTab()\" size=\"md\" variant=\"default\"\r\n (tabChange)=\"onTabChange($event)\">\r\n </cide-ele-tab>\r\n </div>\r\n </div>\r\n\r\n <!-- Tab Content -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-6\">\r\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\r\n @switch (activeTab()) {\r\n\r\n @case ('basic') {\r\n <!-- Basic Academic Year Information -->\r\n <div class=\"tw-space-y-6\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\r\n <cide-ele-input label=\"Academic Year Code *\" formControlName=\"acayr_code\"\r\n placeholder=\"e.g., AY2024-25\" size=\"md\" leadingIcon=\"code\">\r\n </cide-ele-input>\r\n\r\n <cide-ele-input label=\"Academic Year Name *\" formControlName=\"acayr_name\"\r\n placeholder=\"e.g., Academic Year 2024-2025\" size=\"md\" leadingIcon=\"school\">\r\n </cide-ele-input>\r\n </div>\r\n\r\n <div>\r\n <cide-ele-textarea label=\"Description\" formControlName=\"acayr_description\"\r\n placeholder=\"Enter detailed description of the academic year...\"\r\n rows=\"3\" size=\"md\">\r\n </cide-ele-textarea>\r\n </div>\r\n\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\r\n <cide-ele-input label=\"From Date *\" formControlName=\"acayr_from_date\" type=\"date\" size=\"md\"\r\n leadingIcon=\"calendar_today\" id=\"acayr_from_date\">\r\n </cide-ele-input>\r\n\r\n <cide-ele-input label=\"To Date *\" formControlName=\"acayr_to_date\" type=\"date\" size=\"md\"\r\n leadingIcon=\"calendar_today\" id=\"acayr_to_date\">\r\n </cide-ele-input>\r\n </div>\r\n\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-6\">\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input formControlName=\"acayr_isactive\" type=\"checkbox\" size=\"md\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Active</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Enable/disable this academic year</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input formControlName=\"acayr_iscurrent\" type=\"checkbox\" size=\"md\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Current</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Mark as current academic year</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input formControlName=\"acayr_islocked\" type=\"checkbox\" size=\"md\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Locked</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Prevent modifications</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @case ('mapping') {\r\n <!-- Academic Year Mapping Configuration -->\r\n <div class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-indigo-50 tw-border tw-border-blue-200 tw-rounded-xl tw-p-6\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-6\">\r\n <div class=\"tw-flex tw-items-center tw-gap-3\">\r\n <div class=\"tw-bg-blue-100 tw-p-2 tw-rounded-lg\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-6 tw-h-6\">link</cide-ele-icon>\r\n </div>\r\n <div>\r\n <h6 class=\"tw-text-lg tw-font-semibold tw-text-blue-900 tw-m-0\">Academic Year Mapping</h6>\r\n <p class=\"tw-text-sm tw-text-blue-600 tw-m-0\">Configure entity mappings for this academic year</p>\r\n </div>\r\n </div>\r\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"md\" leftIcon=\"add\"\r\n (click)=\"addAcademicYearMapping()\"\r\n class=\"tw-shadow-md hover:tw-shadow-lg tw-transition-shadow\">\r\n Add New Mapping\r\n </button>\r\n </div>\r\n \r\n @if (academicYearMappingsArray.length === 0) {\r\n <div class=\"tw-text-center tw-py-12 tw-text-gray-500\">\r\n <div class=\"tw-bg-white tw-p-4 tw-rounded-full tw-w-16 tw-h-16 tw-mx-auto tw-mb-4 tw-flex tw-items-center tw-justify-center\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400\">link</cide-ele-icon>\r\n </div>\r\n <h6 class=\"tw-text-base tw-font-medium tw-text-gray-600 tw-mb-2\">No Mappings Yet</h6>\r\n <p class=\"tw-text-sm tw-text-gray-500\">Click \"Add New Mapping\" to start configuring entity relationships for this academic year.</p>\r\n </div>\r\n } @else {\r\n <div class=\"tw-space-y-4\" formArrayName=\"acayr_academic_year_mappings\">\r\n @for (mapping of academicYearMappingsArray.controls; track $index) {\r\n <div class=\"tw-bg-white tw-rounded-xl tw-border tw-border-gray-200 tw-shadow-sm hover:tw-shadow-md tw-transition-shadow tw-p-6\">\r\n <div class=\"tw-flex tw-items-start tw-justify-between tw-mb-4\">\r\n <div class=\"tw-flex tw-items-center tw-gap-2\">\r\n <div class=\"tw-bg-blue-100 tw-p-2 tw-rounded-lg\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">settings</cide-ele-icon>\r\n </div>\r\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">Mapping #{{ $index + 1 }}</h6>\r\n </div>\r\n <button cideEleButton type=\"button\" variant=\"danger\" size=\"sm\" leftIcon=\"delete\"\r\n (click)=\"removeAcademicYearMapping($index)\"\r\n class=\"tw-opacity-80 hover:tw-opacity-100 tw-transition-opacity\">\r\n Remove\r\n </button>\r\n </div>\r\n \r\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-4\" [formGroupName]=\"$index\">\r\n <!-- Hidden Academic Year ID field (internal use only) -->\r\n <input type=\"hidden\" formControlName=\"acayrmp_academic_year_id_acayr\">\r\n \r\n <!-- Entity Selection -->\r\n <div class=\"tw-space-y-2\">\r\n <label class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Select Entity *</label>\r\n <cide-ele-select \r\n [options]=\"entityOptions()\"\r\n formControlName=\"acayrmp_entity_id_syen\"\r\n placeholder=\"Choose entity for this mapping\" \r\n size=\"md\"\r\n valueKey=\"_id\"\r\n labelKey=\"syen_name\"\r\n class=\"tw-min-w-full\"\r\n (change)=\"onMappingEntityChange($event, $index)\">\r\n </cide-ele-select>\r\n </div>\r\n \r\n <!-- Status Controls -->\r\n <div class=\"tw-space-y-2\">\r\n <div class=\"tw-grid tw-grid-cols-1 tw-gap-3\">\r\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input \r\n formControlName=\"acayrmp_islocked\" \r\n type=\"checkbox\" \r\n size=\"sm\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Locked</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Prevent modifications</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input \r\n formControlName=\"acayrmp_iscurrent\" \r\n type=\"checkbox\" \r\n size=\"sm\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Current</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Mark as current mapping</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Mapping Validation Messages -->\r\n @if (academicYearMappingsArray.length > 0 && !isMappingsArrayValid()) {\r\n <div class=\"tw-mt-4 tw-p-4 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded-lg\">\r\n <div class=\"tw-flex tw-items-center tw-gap-2\">\r\n <cide-ele-icon variant=\"warning\" size=\"sm\">warning</cide-ele-icon>\r\n <span class=\"tw-text-sm tw-font-medium tw-text-yellow-800\">\r\n Please ensure all mappings have required fields filled in.\r\n </span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Error Display -->\r\n @if (error()) {\r\n <div class=\"tw-mt-6 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-lg\">\r\n <div class=\"tw-flex tw-items-center tw-gap-2\">\r\n <cide-ele-icon variant=\"red\" size=\"sm\">error</cide-ele-icon>\r\n <span class=\"tw-text-sm tw-font-medium tw-text-red-800\">{{ error() }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Form Actions -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-2 tw-bg-gray-50 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-flex tw-justify-end tw-gap-4\">\r\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"resetForm()\" leftIcon=\"refresh\"\r\n [disabled]=\"loading()\">\r\n Reset Form\r\n </button>\r\n\r\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"cancelForm()\" leftIcon=\"close\"\r\n [disabled]=\"loading()\">\r\n Cancel\r\n </button>\r\n\r\n <button cideEleButton type=\"submit\" variant=\"primary\" [disabled]=\"loading() || academicYearForm.invalid\"\r\n [loading]=\"loading()\" leftIcon=\"save\">\r\n {{ isEditMode() ? 'Update Academic Year' : 'Create Academic Year' }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n </div>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideTextareaComponent, selector: "cide-ele-textarea", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "minlength", "maxlength", "rows", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton]", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleTabComponent, selector: "cide-ele-tab", inputs: ["tabs", "activeTabId", "size", "variant", "fullWidth", "disabled"], outputs: ["tabChange"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey"], outputs: ["ngModelChange", "change", "searchChange"] }] });
1063
+ }
1064
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: AcademicYearCreateComponent, decorators: [{
1065
+ type: Component,
1066
+ args: [{ selector: 'cide-core-academic-year-create', standalone: true, imports: [
1067
+ CommonModule,
1068
+ ReactiveFormsModule,
1069
+ CideInputComponent,
1070
+ CideTextareaComponent,
1071
+ CideEleButtonComponent,
1072
+ CideEleTabComponent,
1073
+ CideIconComponent,
1074
+ CideSelectComponent
1075
+ ], template: "<!-- \r\n ACADEMIC YEAR MASTER FORM\r\n \r\n Enterprise-Level Styling with Tailwind CSS\r\n Features: Responsive grids, proper typography, enhanced user experience\r\n-->\r\n\r\n<div class=\"tw-w-full tw-h-full\">\r\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"academicYearForm\" [class.tw-opacity-60]=\"loading()\"\r\n (ngSubmit)=\"onSubmit()\">\r\n\r\n <!-- Simple Header Section -->\r\n <div class=\"tw-table-row tw-w-full tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n \r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">school</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">\r\n {{ isEditMode() ? 'Edit Academic Year' : 'Create Academic Year' }}\r\n </h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <!-- Back button or other actions can be added here if needed -->\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Tab Navigation -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-2 tw-py-0\">\r\n <cide-ele-tab [tabs]=\"academicYearTabs()\" [activeTabId]=\"activeTab()\" size=\"md\" variant=\"default\"\r\n (tabChange)=\"onTabChange($event)\">\r\n </cide-ele-tab>\r\n </div>\r\n </div>\r\n\r\n <!-- Tab Content -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-6\">\r\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\r\n @switch (activeTab()) {\r\n\r\n @case ('basic') {\r\n <!-- Basic Academic Year Information -->\r\n <div class=\"tw-space-y-6\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\r\n <cide-ele-input label=\"Academic Year Code *\" formControlName=\"acayr_code\"\r\n placeholder=\"e.g., AY2024-25\" size=\"md\" leadingIcon=\"code\">\r\n </cide-ele-input>\r\n\r\n <cide-ele-input label=\"Academic Year Name *\" formControlName=\"acayr_name\"\r\n placeholder=\"e.g., Academic Year 2024-2025\" size=\"md\" leadingIcon=\"school\">\r\n </cide-ele-input>\r\n </div>\r\n\r\n <div>\r\n <cide-ele-textarea label=\"Description\" formControlName=\"acayr_description\"\r\n placeholder=\"Enter detailed description of the academic year...\"\r\n rows=\"3\" size=\"md\">\r\n </cide-ele-textarea>\r\n </div>\r\n\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\r\n <cide-ele-input label=\"From Date *\" formControlName=\"acayr_from_date\" type=\"date\" size=\"md\"\r\n leadingIcon=\"calendar_today\" id=\"acayr_from_date\">\r\n </cide-ele-input>\r\n\r\n <cide-ele-input label=\"To Date *\" formControlName=\"acayr_to_date\" type=\"date\" size=\"md\"\r\n leadingIcon=\"calendar_today\" id=\"acayr_to_date\">\r\n </cide-ele-input>\r\n </div>\r\n\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-6\">\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input formControlName=\"acayr_isactive\" type=\"checkbox\" size=\"md\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Active</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Enable/disable this academic year</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input formControlName=\"acayr_iscurrent\" type=\"checkbox\" size=\"md\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Current</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Mark as current academic year</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input formControlName=\"acayr_islocked\" type=\"checkbox\" size=\"md\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Locked</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Prevent modifications</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @case ('mapping') {\r\n <!-- Academic Year Mapping Configuration -->\r\n <div class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-indigo-50 tw-border tw-border-blue-200 tw-rounded-xl tw-p-6\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-6\">\r\n <div class=\"tw-flex tw-items-center tw-gap-3\">\r\n <div class=\"tw-bg-blue-100 tw-p-2 tw-rounded-lg\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-6 tw-h-6\">link</cide-ele-icon>\r\n </div>\r\n <div>\r\n <h6 class=\"tw-text-lg tw-font-semibold tw-text-blue-900 tw-m-0\">Academic Year Mapping</h6>\r\n <p class=\"tw-text-sm tw-text-blue-600 tw-m-0\">Configure entity mappings for this academic year</p>\r\n </div>\r\n </div>\r\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"md\" leftIcon=\"add\"\r\n (click)=\"addAcademicYearMapping()\"\r\n class=\"tw-shadow-md hover:tw-shadow-lg tw-transition-shadow\">\r\n Add New Mapping\r\n </button>\r\n </div>\r\n \r\n @if (academicYearMappingsArray.length === 0) {\r\n <div class=\"tw-text-center tw-py-12 tw-text-gray-500\">\r\n <div class=\"tw-bg-white tw-p-4 tw-rounded-full tw-w-16 tw-h-16 tw-mx-auto tw-mb-4 tw-flex tw-items-center tw-justify-center\">\r\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-text-gray-400\">link</cide-ele-icon>\r\n </div>\r\n <h6 class=\"tw-text-base tw-font-medium tw-text-gray-600 tw-mb-2\">No Mappings Yet</h6>\r\n <p class=\"tw-text-sm tw-text-gray-500\">Click \"Add New Mapping\" to start configuring entity relationships for this academic year.</p>\r\n </div>\r\n } @else {\r\n <div class=\"tw-space-y-4\" formArrayName=\"acayr_academic_year_mappings\">\r\n @for (mapping of academicYearMappingsArray.controls; track $index) {\r\n <div class=\"tw-bg-white tw-rounded-xl tw-border tw-border-gray-200 tw-shadow-sm hover:tw-shadow-md tw-transition-shadow tw-p-6\">\r\n <div class=\"tw-flex tw-items-start tw-justify-between tw-mb-4\">\r\n <div class=\"tw-flex tw-items-center tw-gap-2\">\r\n <div class=\"tw-bg-blue-100 tw-p-2 tw-rounded-lg\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">settings</cide-ele-icon>\r\n </div>\r\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">Mapping #{{ $index + 1 }}</h6>\r\n </div>\r\n <button cideEleButton type=\"button\" variant=\"danger\" size=\"sm\" leftIcon=\"delete\"\r\n (click)=\"removeAcademicYearMapping($index)\"\r\n class=\"tw-opacity-80 hover:tw-opacity-100 tw-transition-opacity\">\r\n Remove\r\n </button>\r\n </div>\r\n \r\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-4\" [formGroupName]=\"$index\">\r\n <!-- Hidden Academic Year ID field (internal use only) -->\r\n <input type=\"hidden\" formControlName=\"acayrmp_academic_year_id_acayr\">\r\n \r\n <!-- Entity Selection -->\r\n <div class=\"tw-space-y-2\">\r\n <label class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Select Entity *</label>\r\n <cide-ele-select \r\n [options]=\"entityOptions()\"\r\n formControlName=\"acayrmp_entity_id_syen\"\r\n placeholder=\"Choose entity for this mapping\" \r\n size=\"md\"\r\n valueKey=\"_id\"\r\n labelKey=\"syen_name\"\r\n class=\"tw-min-w-full\"\r\n (change)=\"onMappingEntityChange($event, $index)\">\r\n </cide-ele-select>\r\n </div>\r\n \r\n <!-- Status Controls -->\r\n <div class=\"tw-space-y-2\">\r\n <div class=\"tw-grid tw-grid-cols-1 tw-gap-3\">\r\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input \r\n formControlName=\"acayrmp_islocked\" \r\n type=\"checkbox\" \r\n size=\"sm\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Locked</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Prevent modifications</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-3 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200\">\r\n <cide-ele-input \r\n formControlName=\"acayrmp_iscurrent\" \r\n type=\"checkbox\" \r\n size=\"sm\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Current</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Mark as current mapping</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Mapping Validation Messages -->\r\n @if (academicYearMappingsArray.length > 0 && !isMappingsArrayValid()) {\r\n <div class=\"tw-mt-4 tw-p-4 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded-lg\">\r\n <div class=\"tw-flex tw-items-center tw-gap-2\">\r\n <cide-ele-icon variant=\"warning\" size=\"sm\">warning</cide-ele-icon>\r\n <span class=\"tw-text-sm tw-font-medium tw-text-yellow-800\">\r\n Please ensure all mappings have required fields filled in.\r\n </span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Error Display -->\r\n @if (error()) {\r\n <div class=\"tw-mt-6 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-lg\">\r\n <div class=\"tw-flex tw-items-center tw-gap-2\">\r\n <cide-ele-icon variant=\"red\" size=\"sm\">error</cide-ele-icon>\r\n <span class=\"tw-text-sm tw-font-medium tw-text-red-800\">{{ error() }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Form Actions -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-2 tw-bg-gray-50 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-flex tw-justify-end tw-gap-4\">\r\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"resetForm()\" leftIcon=\"refresh\"\r\n [disabled]=\"loading()\">\r\n Reset Form\r\n </button>\r\n\r\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"cancelForm()\" leftIcon=\"close\"\r\n [disabled]=\"loading()\">\r\n Cancel\r\n </button>\r\n\r\n <button cideEleButton type=\"submit\" variant=\"primary\" [disabled]=\"loading() || academicYearForm.invalid\"\r\n [loading]=\"loading()\" leftIcon=\"save\">\r\n {{ isEditMode() ? 'Update Academic Year' : 'Create Academic Year' }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n </div>" }]
1076
+ }], ctorParameters: () => [] });
1077
+
1078
+ var academicYearCreate_component = /*#__PURE__*/Object.freeze({
1079
+ __proto__: null,
1080
+ AcademicYearCreateComponent: AcademicYearCreateComponent
1081
+ });
1082
+
1083
+ class AcademicYearListComponent {
1084
+ // Modern Angular 20+ dependency injection using inject()
1085
+ destroyRef = inject(DestroyRef);
1086
+ academicYearService = inject(CideLytAcademicYearService);
1087
+ router = inject(Router);
1088
+ appState = inject(AppStateHelperService);
1089
+ confirmationService = inject(ConfirmationService);
1090
+ notificationService = inject(NotificationService);
1091
+ // Modern ViewChild signals for template renderers (Angular 20 approach)
1092
+ academicYearDetailsRendererTemplate = viewChild.required('academicYearDetailsRendererTemplate');
1093
+ dateRangeRendererTemplate = viewChild.required('dateRangeRendererTemplate');
1094
+ statusRendererTemplate = viewChild.required('statusRendererTemplate');
1095
+ actionsDropdownRendererTemplate = viewChild.required('actionsDropdownRendererTemplate');
1096
+ // Modern Angular 20+ state management using signals with proper typing
1097
+ academicYears = signal([], ...(ngDevMode ? [{ debugName: "academicYears" }] : []));
1098
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1099
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
1100
+ // Server-side pagination state using signals
1101
+ currentPage = signal(1, ...(ngDevMode ? [{ debugName: "currentPage" }] : []));
1102
+ pageSize = signal(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
1103
+ totalItems = signal(0, ...(ngDevMode ? [{ debugName: "totalItems" }] : []));
1104
+ totalPages = signal(0, ...(ngDevMode ? [{ debugName: "totalPages" }] : []));
1105
+ // Server-side search state using signals
1106
+ searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
1107
+ // Server-side sorting state using signals
1108
+ sortColumn = signal('acayr_name', ...(ngDevMode ? [{ debugName: "sortColumn" }] : []));
1109
+ sortDirection = signal('asc', ...(ngDevMode ? [{ debugName: "sortDirection" }] : []));
1110
+ // Server-side filtering state using signals
1111
+ selectedStatusFilter = signal('', ...(ngDevMode ? [{ debugName: "selectedStatusFilter" }] : []));
1112
+ // Filter options using computed signal for better performance
1113
+ statusFilterOptions = computed(() => [
1114
+ { value: '', label: 'All Status' },
1115
+ { value: 'active', label: 'Active Years' },
1116
+ { value: 'inactive', label: 'Inactive Years' },
1117
+ { value: 'current', label: 'Current Year' },
1118
+ { value: 'locked', label: 'Locked Years' }
1119
+ ], ...(ngDevMode ? [{ debugName: "statusFilterOptions" }] : []));
1120
+ // Modern Angular 20+ grid configuration using computed signal with proper typing
1121
+ gridConfig = computed(() => ({
1122
+ id: 'academic-year-list-grid',
1123
+ columns: [
1124
+ {
1125
+ key: 'acayr_code',
1126
+ header: 'Academic Year Code',
1127
+ type: 'text',
1128
+ width: '140px',
1129
+ truncate: true,
1130
+ align: 'left',
1131
+ sortable: true
1132
+ },
1133
+ {
1134
+ key: 'details',
1135
+ header: 'Academic Year Details',
1136
+ type: 'custom',
1137
+ width: 'auto',
1138
+ truncate: true,
1139
+ align: 'left',
1140
+ renderer: 'academicYearDetailsRenderer',
1141
+ sortable: true
1142
+ },
1143
+ {
1144
+ key: 'date_range',
1145
+ header: 'Date Range',
1146
+ type: 'custom',
1147
+ width: '200px',
1148
+ truncate: false,
1149
+ align: 'left',
1150
+ renderer: 'dateRangeRenderer',
1151
+ sortable: true
1152
+ },
1153
+ {
1154
+ key: 'acayr_isactive',
1155
+ header: 'Status',
1156
+ type: 'custom',
1157
+ width: '140px',
1158
+ truncate: false,
1159
+ align: 'center',
1160
+ renderer: 'statusRenderer'
1161
+ },
1162
+ {
1163
+ key: 'actions',
1164
+ header: 'Actions',
1165
+ type: 'custom',
1166
+ width: '80px',
1167
+ truncate: false,
1168
+ align: 'center',
1169
+ renderer: 'actionsDropdownRenderer'
1170
+ }
1171
+ ],
1172
+ data: this.academicYears(),
1173
+ trackBy: '_id',
1174
+ pagination: {
1175
+ enabled: true,
1176
+ pageSize: this.pageSize(),
1177
+ pageSizeOptions: [10, 25, 50, 100],
1178
+ showQuickJump: true,
1179
+ showPageInfo: true,
1180
+ showRefresh: true
1181
+ },
1182
+ search: {
1183
+ enabled: true,
1184
+ placeholder: 'Search by code, name, or description...',
1185
+ searchableColumns: ['acayr_code', 'acayr_name', 'acayr_description'],
1186
+ debounceMs: 300,
1187
+ showClearButton: true
1188
+ },
1189
+ loading: {
1190
+ useDefer: true,
1191
+ skeletonRows: 5,
1192
+ showOverlay: this.loading()
1193
+ },
1194
+ scroll: {
1195
+ enabled: true,
1196
+ maxHeight: '',
1197
+ minHeight: '',
1198
+ stickyHeader: true,
1199
+ virtualScroll: false,
1200
+ rowHeight: 50
1201
+ },
1202
+ export: {
1203
+ enabled: true,
1204
+ formats: ['csv', 'excel', 'pdf'],
1205
+ filename: 'academic-years',
1206
+ includeHeaders: true
1207
+ },
1208
+ responsive: true,
1209
+ striped: false,
1210
+ bordered: true,
1211
+ compact: false,
1212
+ tableClass: 'tw-table-fixed tw-w-full tw-rounded-none'
1213
+ }), ...(ngDevMode ? [{ debugName: "gridConfig" }] : []));
1214
+ ngOnInit() {
1215
+ console.log('🎓 Academic Year List Component initialized');
1216
+ this.loadAcademicYears();
1217
+ }
1218
+ ngOnDestroy() {
1219
+ // Cleanup if needed
1220
+ }
1221
+ /**
1222
+ * Load academic years from API
1223
+ */
1224
+ loadAcademicYears() {
1225
+ this.loading.set(true);
1226
+ this.error.set(null);
1227
+ const payload = {
1228
+ pageIndex: this.currentPage(),
1229
+ pageSize: this.pageSize(),
1230
+ query: this.searchQuery() || "",
1231
+ sort: {
1232
+ key: this.sortColumn(),
1233
+ order: this.sortDirection()
1234
+ }
1235
+ };
1236
+ this.academicYearService.getAcademicYearList(payload)
1237
+ .pipe(takeUntilDestroyed(this.destroyRef))
1238
+ .subscribe({
1239
+ next: (response) => {
1240
+ if (response?.success && response.data) {
1241
+ console.log('📚 Academic years loaded:', response.data);
1242
+ console.log('📊 Pagination info:', {
1243
+ total: response.total,
1244
+ pageIndex: response.pageIndex,
1245
+ pageSize: response.pageSize
1246
+ });
1247
+ this.academicYears.set(response.data);
1248
+ this.totalItems.set(response.total || 0);
1249
+ this.totalPages.set(Math.ceil((response.total || 0) / this.pageSize()));
1250
+ // Show success notification if data was loaded successfully
1251
+ if (response.data.length > 0) {
1252
+ this.notificationService.success(`Loaded ${response.data.length} academic year(s) successfully.`);
1253
+ }
1254
+ }
1255
+ else {
1256
+ console.warn('⚠️ No academic year data received');
1257
+ this.academicYears.set([]);
1258
+ this.totalItems.set(0);
1259
+ this.totalPages.set(0);
1260
+ this.notificationService.warning('No academic years found.');
1261
+ }
1262
+ this.loading.set(false);
1263
+ },
1264
+ error: (error) => {
1265
+ console.error('❌ Error loading academic years:', error);
1266
+ this.error.set('Failed to load academic years. Please try again.');
1267
+ this.academicYears.set([]);
1268
+ this.totalItems.set(0);
1269
+ this.totalPages.set(0);
1270
+ this.notificationService.error('Failed to load academic years. Please try again.');
1271
+ this.loading.set(false);
1272
+ }
1273
+ });
1274
+ }
1275
+ // Computed template renderers for grid
1276
+ templateRenderers = computed(() => ({
1277
+ academicYearDetailsRenderer: this.academicYearDetailsRendererTemplate(),
1278
+ dateRangeRenderer: this.dateRangeRendererTemplate(),
1279
+ statusRenderer: this.statusRendererTemplate(),
1280
+ actionsDropdownRenderer: this.actionsDropdownRendererTemplate()
1281
+ }), ...(ngDevMode ? [{ debugName: "templateRenderers" }] : []));
1282
+ /**
1283
+ * Handle grid events
1284
+ */
1285
+ onGridEvent(event) {
1286
+ switch (event.type) {
1287
+ case 'pageChange':
1288
+ if (event.data && typeof event.data === 'object' && 'pageIndex' in event.data && 'pageSize' in event.data) {
1289
+ this.currentPage.set(event.data['pageIndex']);
1290
+ this.pageSize.set(event.data['pageSize']);
1291
+ this.loadAcademicYears();
1292
+ }
1293
+ break;
1294
+ case 'search':
1295
+ this.searchQuery.set(event.data);
1296
+ this.currentPage.set(1);
1297
+ this.loadAcademicYears();
1298
+ break;
1299
+ case 'refresh':
1300
+ this.loadAcademicYears();
1301
+ break;
1302
+ case 'action':
1303
+ // Handle action events if needed
1304
+ console.log('Action event:', event);
1305
+ break;
1306
+ case 'rowClick':
1307
+ // Handle row click events if needed
1308
+ console.log('Row click event:', event);
1309
+ break;
1310
+ case 'sort':
1311
+ if (event.data && typeof event.data === 'object' && 'column' in event.data && 'direction' in event.data) {
1312
+ this.sortColumn.set(event.data['column']);
1313
+ this.sortDirection.set(event.data['direction']);
1314
+ this.currentPage.set(1); // Reset to first page when sorting
1315
+ this.loadAcademicYears();
1316
+ }
1317
+ break;
1318
+ case 'export':
1319
+ if (event.data && typeof event.data === 'string') {
1320
+ this.handleExport(event.data);
1321
+ }
1322
+ break;
1323
+ default:
1324
+ console.log('🔄 Unhandled grid event:', event.type);
1325
+ }
1326
+ }
1327
+ // Filter handlers
1328
+ onStatusFilterChange() {
1329
+ console.log('🔍 Status filter changed:', this.selectedStatusFilter());
1330
+ this.currentPage.set(1); // Reset to first page when filtering
1331
+ this.loadAcademicYears();
1332
+ }
1333
+ clearFilters() {
1334
+ console.log('🧹 Clearing filters');
1335
+ this.selectedStatusFilter.set('');
1336
+ this.searchQuery.set('');
1337
+ this.currentPage.set(1);
1338
+ this.loadAcademicYears();
1339
+ }
1340
+ // Academic Year actions with proper typing
1341
+ createAcademicYear() {
1342
+ console.log('➕ Navigating to create academic year');
1343
+ this.notificationService.info('Opening form to create a new academic year.');
1344
+ this.router.navigate(['/control-panel/academic_year/create']);
1345
+ }
1346
+ viewAcademicYear(academicYear) {
1347
+ console.log('👁️ Viewing academic year:', academicYear);
1348
+ this.notificationService.info(`Opening academic year "${academicYear.acayr_name}" for viewing.`);
1349
+ const queryParams = generateStringFromObject({ acayr_id: academicYear._id });
1350
+ this.router.navigate(['/control-panel/academic_year/view', queryParams]);
1351
+ }
1352
+ editAcademicYear(academicYear) {
1353
+ console.log('✏️ Editing academic year:', academicYear);
1354
+ // Check if the academic year is locked
1355
+ if (academicYear.acayr_islocked) {
1356
+ this.notificationService.error(`Cannot edit "${academicYear.acayr_name}" - This academic year is locked and cannot be modified. Please contact an administrator to unlock it first.`);
1357
+ return;
1358
+ }
1359
+ this.notificationService.info(`Opening academic year "${academicYear.acayr_name}" for editing.`);
1360
+ const queryParams = generateStringFromObject({ acayr_id: academicYear._id });
1361
+ this.router.navigate(['/control-panel/academic_year/edit', queryParams]);
1362
+ }
1363
+ /**
1364
+ * Get dropdown configuration
1365
+ */
1366
+ getDropdownConfig() {
1367
+ return {
1368
+ triggerIcon: 'more_vert',
1369
+ triggerSize: 'sm',
1370
+ // menuPosition: 'right' as const,
1371
+ // forcePosition: 'bottom' as const,
1372
+ // offsetX: 0,
1373
+ // offsetY: 1,
1374
+ // usePortal: true,
1375
+ // showArrow: false
1376
+ };
1377
+ }
1378
+ /**
1379
+ * Get action dropdown items
1380
+ */
1381
+ getActionDropdownItems(academicYear) {
1382
+ console.log('🔽 Generating dropdown items for:', academicYear.acayr_name);
1383
+ console.log('🔽 Academic year data:', {
1384
+ isCurrent: academicYear.acayr_iscurrent,
1385
+ isLocked: academicYear.acayr_islocked,
1386
+ isActive: academicYear.acayr_isactive
1387
+ });
1388
+ const items = [
1389
+ {
1390
+ id: 'view',
1391
+ label: 'View Details',
1392
+ icon: 'visibility',
1393
+ iconColor: 'tw-text-gray-400',
1394
+ textColor: 'tw-text-gray-700',
1395
+ hoverBgColor: 'hover:tw-bg-gray-100'
1396
+ },
1397
+ {
1398
+ id: 'edit',
1399
+ label: 'Edit',
1400
+ icon: 'edit',
1401
+ iconColor: academicYear?.acayr_islocked ? 'tw-text-gray-300' : 'tw-text-blue-400',
1402
+ textColor: academicYear?.acayr_islocked ? 'tw-text-gray-400' : 'tw-text-blue-600',
1403
+ hoverBgColor: academicYear?.acayr_islocked ? 'hover:tw-bg-gray-50' : 'hover:tw-bg-blue-50'
1404
+ },
1405
+ {
1406
+ id: 'toggle-status',
1407
+ label: academicYear.acayr_isactive ? 'Deactivate' : 'Activate',
1408
+ icon: academicYear.acayr_isactive ? 'toggle_off' : 'toggle_on',
1409
+ iconColor: academicYear?.acayr_islocked ? 'tw-text-gray-300' : 'tw-text-gray-400',
1410
+ textColor: academicYear?.acayr_islocked ? 'tw-text-gray-400' : 'tw-text-gray-700',
1411
+ hoverBgColor: academicYear?.acayr_islocked ? 'hover:tw-bg-gray-50' : 'hover:tw-bg-gray-100'
1412
+ }
1413
+ ];
1414
+ return items;
1415
+ }
1416
+ /**
1417
+ * Handle dropdown item click
1418
+ */
1419
+ onDropdownItemClick(item, academicYear) {
1420
+ console.log('🖱️ Dropdown item clicked:', item.id, 'for academic year:', academicYear.acayr_name);
1421
+ // Check if item is disabled
1422
+ if (item.disabled) {
1423
+ console.log('⚠️ Item is disabled, ignoring click');
1424
+ return;
1425
+ }
1426
+ switch (item.id) {
1427
+ case 'view':
1428
+ this.viewAcademicYear(academicYear);
1429
+ break;
1430
+ case 'edit':
1431
+ this.editAcademicYear(academicYear);
1432
+ break;
1433
+ case 'toggle-status':
1434
+ this.toggleAcademicYearStatus(academicYear);
1435
+ break;
1436
+ default:
1437
+ console.log('❓ Unknown dropdown item clicked:', item.id);
1438
+ }
1439
+ }
1440
+ /**
1441
+ * Toggle academic year status (active/inactive)
1442
+ */
1443
+ toggleAcademicYearStatus(academicYear) {
1444
+ console.log('🔄 Toggling academic year status:', academicYear);
1445
+ // Check if the academic year is locked
1446
+ if (academicYear.acayr_islocked) {
1447
+ this.notificationService.error(`Cannot ${academicYear.acayr_isactive ? 'deactivate' : 'activate'} "${academicYear.acayr_name}" - This academic year is locked and its status cannot be changed. Please contact an administrator to unlock it first.`);
1448
+ return;
1449
+ }
1450
+ const action = academicYear.acayr_isactive ? 'deactivate' : 'activate';
1451
+ const actionText = academicYear.acayr_isactive ? 'Deactivate' : 'Activate';
1452
+ // Show confirmation dialog
1453
+ console.log('🔔 Showing confirmation dialog for toggle status');
1454
+ this.confirmationService.ask({
1455
+ title: `${actionText} Academic Year`,
1456
+ message: `Are you sure you want to ${action} the academic year "${academicYear.acayr_name}"?${!academicYear.acayr_isactive ? '\n\nThis will also deactivate all associated mappings.' : ''}`,
1457
+ confirmText: actionText,
1458
+ cancelText: 'Cancel',
1459
+ type: academicYear.acayr_isactive ? 'warning' : 'info'
1460
+ }).then((confirmed) => {
1461
+ console.log('🔔 Confirmation dialog result:', confirmed);
1462
+ if (confirmed) {
1463
+ this.loading.set(true);
1464
+ // First toggle the academic year status
1465
+ console.log('🔄 Calling toggleAcademicYearStatus with ID:', academicYear._id);
1466
+ this.academicYearService.toggleAcademicYearStatus({ acayr_id: academicYear._id }).subscribe({
1467
+ next: (response) => {
1468
+ console.log('🔄 Toggle academic year status response:', response);
1469
+ if (response?.success) {
1470
+ console.log('✅ Academic year status toggled successfully');
1471
+ // If deactivating, also toggle status of all academic year mappings
1472
+ if (!academicYear.acayr_isactive) { // If we're deactivating (was active, now inactive)
1473
+ this.toggleAcademicYearMappingsStatus(academicYear._id || '', false);
1474
+ }
1475
+ else {
1476
+ // If activating, just reload the list
1477
+ this.notificationService.success(`Academic year "${academicYear.acayr_name}" has been activated successfully.`);
1478
+ this.loadAcademicYears();
1479
+ }
1480
+ }
1481
+ else {
1482
+ console.error('❌ Failed to toggle academic year status');
1483
+ this.notificationService.error(response?.message || 'Failed to toggle academic year status');
1484
+ this.loading.set(false);
1485
+ }
1486
+ },
1487
+ error: (error) => {
1488
+ console.error('❌ Error toggling academic year status:', error);
1489
+ console.error('❌ Error details:', {
1490
+ status: error.status,
1491
+ message: error.message,
1492
+ error: error.error
1493
+ });
1494
+ this.notificationService.error('Failed to toggle academic year status. Please try again.');
1495
+ this.loading.set(false);
1496
+ }
1497
+ });
1498
+ }
1499
+ });
1500
+ }
1501
+ /**
1502
+ * Toggle status of all academic year mappings for a specific academic year
1503
+ */
1504
+ toggleAcademicYearMappingsStatus(academicYearId, isActive) {
1505
+ console.log(`🔄 Toggling mappings status for academic year ${academicYearId} to ${isActive ? 'active' : 'inactive'}`);
1506
+ // Get all mappings for this academic year and toggle their status
1507
+ // For now, we'll reload the academic year data to get the mappings
1508
+ // In a real implementation, you might want to get mappings separately
1509
+ this.academicYearService.getAcademicYearById({ acayr_id: academicYearId }).subscribe({
1510
+ next: (response) => {
1511
+ if (response?.success && response.data && response.data.acayr_academic_year_mappings) {
1512
+ const mappings = response.data.acayr_academic_year_mappings;
1513
+ console.log('📋 Found mappings to toggle:', mappings);
1514
+ // Toggle each mapping's status
1515
+ const toggleObservables = mappings.map((mapping) => {
1516
+ return this.academicYearService.toggleAcademicYearMappingStatus({
1517
+ acayrmp_id: mapping._id
1518
+ }).pipe(catchError(error => {
1519
+ console.error('❌ Error toggling mapping status:', error);
1520
+ return of({ success: false, error, mappingId: mapping._id });
1521
+ }));
1522
+ });
1523
+ if (toggleObservables.length > 0) {
1524
+ forkJoin(toggleObservables).subscribe((results) => {
1525
+ console.log('✅ All mapping statuses toggled:', results);
1526
+ const resultsArray = results;
1527
+ const failedCount = resultsArray.filter((result) => !result.success).length;
1528
+ if (failedCount === 0) {
1529
+ this.notificationService.success(`Academic year and all ${resultsArray.length} associated mappings have been deactivated successfully.`);
1530
+ }
1531
+ else {
1532
+ this.notificationService.warning(`Academic year deactivated, but ${failedCount} out of ${resultsArray.length} mappings failed to update.`);
1533
+ }
1534
+ this.loadAcademicYears(); // Reload the list
1535
+ }, (error) => {
1536
+ console.error('❌ Error toggling mapping statuses:', error);
1537
+ this.notificationService.error('Academic year deactivated, but failed to update some mappings.');
1538
+ this.loadAcademicYears(); // Still reload the list
1539
+ });
1540
+ }
1541
+ else {
1542
+ this.notificationService.success('Academic year has been deactivated successfully.');
1543
+ this.loadAcademicYears(); // No mappings to toggle, just reload
1544
+ }
1545
+ }
1546
+ else {
1547
+ this.notificationService.success('Academic year has been deactivated successfully.');
1548
+ this.loadAcademicYears(); // No mappings found, just reload
1549
+ }
1550
+ },
1551
+ error: (error) => {
1552
+ console.error('❌ Error getting academic year mappings:', error);
1553
+ this.notificationService.error('Academic year deactivated, but failed to update mappings.');
1554
+ this.loadAcademicYears(); // Still reload the list
1555
+ }
1556
+ });
1557
+ }
1558
+ // Export handler
1559
+ handleExport(format) {
1560
+ console.log(`📤 Exporting academic years as ${format}`);
1561
+ const data = this.academicYears().map(item => ({
1562
+ 'Academic Year Code': item.acayr_code,
1563
+ 'Academic Year Name': item.acayr_name,
1564
+ 'Description': item.acayr_description,
1565
+ 'From Date': this.formatDate(item?.acayr_from_date || ""),
1566
+ 'To Date': this.formatDate(item?.acayr_to_date || ""),
1567
+ 'Duration': this.getDuration(item?.acayr_from_date || "", item?.acayr_to_date || ""),
1568
+ 'Status': this.getStatusText(item),
1569
+ 'Is Current': item.acayr_iscurrent ? 'Yes' : 'No',
1570
+ 'Is Active': item.acayr_isactive ? 'Yes' : 'No',
1571
+ 'Is Locked': item.acayr_islocked ? 'Yes' : 'No'
1572
+ }));
1573
+ // Create filename with timestamp
1574
+ const timestamp = new Date().toISOString().split('T')[0];
1575
+ const filename = `academic-years-${timestamp}`;
1576
+ switch (format.toLowerCase()) {
1577
+ case 'csv':
1578
+ this.exportToCSV(data, filename);
1579
+ break;
1580
+ case 'excel':
1581
+ this.exportToExcel(data, filename);
1582
+ break;
1583
+ case 'pdf':
1584
+ this.exportToPDF(data, filename);
1585
+ break;
1586
+ default:
1587
+ console.warn(`Unsupported export format: ${format}`);
1588
+ }
1589
+ }
1590
+ exportToCSV(data, filename) {
1591
+ const headers = Object.keys(data[0] || {});
1592
+ const csvContent = [
1593
+ headers.join(','),
1594
+ ...data.map(row => headers.map(header => `"${row[header] || ''}"`).join(','))
1595
+ ].join('\n');
1596
+ this.downloadFile(csvContent, `${filename}.csv`, 'text/csv');
1597
+ }
1598
+ exportToExcel(data, filename) {
1599
+ // For Excel export, you might want to use a library like xlsx
1600
+ // For now, we'll export as CSV with .xlsx extension
1601
+ this.exportToCSV(data, filename);
1602
+ }
1603
+ exportToPDF(data, filename) {
1604
+ // For PDF export, you might want to use a library like jsPDF
1605
+ // For now, we'll export as CSV
1606
+ this.exportToCSV(data, filename);
1607
+ }
1608
+ downloadFile(content, filename, mimeType) {
1609
+ const blob = new Blob([content], { type: mimeType });
1610
+ const url = window.URL.createObjectURL(blob);
1611
+ const link = document.createElement('a');
1612
+ link.href = url;
1613
+ link.download = filename;
1614
+ document.body.appendChild(link);
1615
+ link.click();
1616
+ document.body.removeChild(link);
1617
+ window.URL.revokeObjectURL(url);
1618
+ }
1619
+ // Utility methods with proper typing
1620
+ formatDate(date) {
1621
+ if (!date)
1622
+ return '-';
1623
+ return new Date(date).toLocaleDateString('en-US', {
1624
+ year: 'numeric',
1625
+ month: 'short',
1626
+ day: 'numeric'
1627
+ });
1628
+ }
1629
+ getDuration(fromDate, toDate) {
1630
+ if (!fromDate || !toDate)
1631
+ return '';
1632
+ const from = new Date(fromDate);
1633
+ const to = new Date(toDate);
1634
+ const diffTime = Math.abs(to.getTime() - from.getTime());
1635
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
1636
+ const months = Math.floor(diffDays / 30);
1637
+ const years = Math.floor(months / 12);
1638
+ if (years > 0) {
1639
+ return `${years} year${years > 1 ? 's' : ''}`;
1640
+ }
1641
+ else if (months > 0) {
1642
+ return `${months} month${months > 1 ? 's' : ''}`;
1643
+ }
1644
+ else {
1645
+ return `${diffDays} day${diffDays > 1 ? 's' : ''}`;
1646
+ }
1647
+ }
1648
+ getStatusBadgeClass(academicYear) {
1649
+ if (academicYear.acayr_iscurrent)
1650
+ return 'tw-bg-green-100 tw-text-green-800';
1651
+ if (academicYear.acayr_islocked)
1652
+ return 'tw-bg-red-100 tw-text-red-800';
1653
+ if (academicYear.acayr_isactive)
1654
+ return 'tw-bg-blue-100 tw-text-blue-800';
1655
+ return 'tw-bg-gray-100 tw-text-gray-800';
1656
+ }
1657
+ getActiveStatusBadgeClass(academicYear) {
1658
+ if (academicYear.acayr_isactive) {
1659
+ return 'tw-bg-green-100 tw-text-green-800';
1660
+ }
1661
+ else {
1662
+ return 'tw-bg-orange-100 tw-text-orange-800';
1663
+ }
1664
+ }
1665
+ getStatusText(academicYear) {
1666
+ if (academicYear.acayr_iscurrent)
1667
+ return 'Current';
1668
+ if (academicYear.acayr_islocked)
1669
+ return 'Locked';
1670
+ if (academicYear.acayr_isactive)
1671
+ return 'Active';
1672
+ return 'Inactive';
1673
+ }
1674
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: AcademicYearListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1675
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: AcademicYearListComponent, isStandalone: true, selector: "cide-core-academic-year-list", viewQueries: [{ propertyName: "academicYearDetailsRendererTemplate", first: true, predicate: ["academicYearDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "dateRangeRendererTemplate", first: true, predicate: ["dateRangeRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "statusRendererTemplate", first: true, predicate: ["statusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Academic Year Container -->\r\n<div class=\"tw-table tw-w-full tw-h-full\">\r\n\r\n <!-- Header Section with Filters -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n\r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">school</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Academic Year Management</h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"createAcademicYear()\">\r\n Create Academic Year\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Area -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-h-full tw-relative\">\r\n\r\n <!-- Data Grid Component -->\r\n <div class=\"tw-h-full tw-overflow-auto\">\r\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n</div>\r\n\r\n<!-- Template Renderers -->\r\n<ng-template #academicYearDetailsRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-w-full\">\r\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.acayr_name || 'N/A' }}</div>\r\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">{{ row.acayr_description || 'No description' }}</div>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #dateRangeRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-text-sm\">\r\n <span class=\"tw-text-gray-900 tw-font-medium\">{{ formatDate(row.acayr_from_date) }}</span>\r\n <span class=\"tw-text-gray-500\">to {{ formatDate(row.acayr_to_date) }}</span>\r\n <span class=\"tw-text-xs tw-text-gray-400\">{{ getDuration(row.acayr_from_date, row.acayr_to_date) }}</span>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #statusRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-gap-1 tw-items-center\">\r\n <!-- Current Year Badge (Priority) -->\r\n @if (row.acayr_iscurrent) {\r\n <span\r\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-yellow-100 tw-text-yellow-800 tw-text-center\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">star</cide-ele-icon>\r\n Current Year\r\n </span>\r\n }\r\n \r\n <!-- Active/Inactive Status Badge -->\r\n <span class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\r\n [ngClass]=\"getActiveStatusBadgeClass(row)\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\r\n {{ row.acayr_isactive ? 'check_circle' : 'cancel' }}\r\n </cide-ele-icon>\r\n {{ row.acayr_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n \r\n <!-- Locked Status Badge (Additional info) -->\r\n @if (row.acayr_islocked) {\r\n <span\r\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-800 tw-text-center\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">lock</cide-ele-icon>\r\n Locked\r\n </span>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown \r\n [items]=\"getActionDropdownItems(row)\"\r\n [config]=\"{ triggerIcon: 'more_vert', triggerSize: 'sm' }\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template>", styles: [".academic-year-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton]", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }] });
1676
+ }
1677
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: AcademicYearListComponent, decorators: [{
1678
+ type: Component,
1679
+ args: [{ selector: 'cide-core-academic-year-list', standalone: true, imports: [
1680
+ CommonModule,
1681
+ FormsModule,
1682
+ CideIconComponent,
1683
+ CideEleButtonComponent,
1684
+ CideEleDataGridComponent,
1685
+ CideEleDropdownComponent
1686
+ ], template: "<!-- Academic Year Container -->\r\n<div class=\"tw-table tw-w-full tw-h-full\">\r\n\r\n <!-- Header Section with Filters -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n\r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">school</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Academic Year Management</h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"createAcademicYear()\">\r\n Create Academic Year\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Area -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-h-full tw-relative\">\r\n\r\n <!-- Data Grid Component -->\r\n <div class=\"tw-h-full tw-overflow-auto\">\r\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers()\"\r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n\r\n</div>\r\n\r\n<!-- Template Renderers -->\r\n<ng-template #academicYearDetailsRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-w-full\">\r\n <div class=\"tw-font-medium tw-text-gray-900\">{{ row.acayr_name || 'N/A' }}</div>\r\n <div class=\"tw-text-sm tw-text-gray-500 tw-truncate\">{{ row.acayr_description || 'No description' }}</div>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #dateRangeRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-text-sm\">\r\n <span class=\"tw-text-gray-900 tw-font-medium\">{{ formatDate(row.acayr_from_date) }}</span>\r\n <span class=\"tw-text-gray-500\">to {{ formatDate(row.acayr_to_date) }}</span>\r\n <span class=\"tw-text-xs tw-text-gray-400\">{{ getDuration(row.acayr_from_date, row.acayr_to_date) }}</span>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #statusRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-flex-col tw-gap-1 tw-items-center\">\r\n <!-- Current Year Badge (Priority) -->\r\n @if (row.acayr_iscurrent) {\r\n <span\r\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-yellow-100 tw-text-yellow-800 tw-text-center\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">star</cide-ele-icon>\r\n Current Year\r\n </span>\r\n }\r\n \r\n <!-- Active/Inactive Status Badge -->\r\n <span class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-text-center\"\r\n [ngClass]=\"getActiveStatusBadgeClass(row)\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">\r\n {{ row.acayr_isactive ? 'check_circle' : 'cancel' }}\r\n </cide-ele-icon>\r\n {{ row.acayr_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n \r\n <!-- Locked Status Badge (Additional info) -->\r\n @if (row.acayr_islocked) {\r\n <span\r\n class=\"tw-inline-flex tw-items-center tw-justify-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-800 tw-text-center\">\r\n <cide-ele-icon size=\"2xs\" class=\"tw-mr-1\">lock</cide-ele-icon>\r\n Locked\r\n </span>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown \r\n [items]=\"getActionDropdownItems(row)\"\r\n [config]=\"{ triggerIcon: 'more_vert', triggerSize: 'sm' }\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template>", styles: [".academic-year-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"] }]
1687
+ }] });
1688
+
1689
+ var academicYearList_component = /*#__PURE__*/Object.freeze({
1690
+ __proto__: null,
1691
+ AcademicYearListComponent: AcademicYearListComponent
1692
+ });
1693
+
1694
+ // Academic Year Management Components
1695
+
1696
+ class CideLytClassProgramBranchService {
1697
+ http = inject(HttpClient);
1698
+ /**
1699
+ * Get list of class program branches
1700
+ * @param payload - Query parameters for filtering/pagination
1701
+ * @returns Observable of class program branch list response
1702
+ */
1703
+ getClassProgramBranchList(payload) {
1704
+ console.log("Class Program Branch List Payload:", payload);
1705
+ const query = generateStringFromObject(payload);
1706
+ const url = cidePath.join([
1707
+ hostManagerRoutesUrl.cideSuiteHost,
1708
+ academicsRoutesUrl.module,
1709
+ academicsRoutesUrl.classProgramBranch,
1710
+ query
1711
+ ]);
1712
+ return this.http.get(url);
1713
+ }
1714
+ /**
1715
+ * Get class program branch by ID
1716
+ * @param payload - Class program branch ID payload
1717
+ * @returns Observable of class program branch data
1718
+ */
1719
+ getClassProgramBranchById(payload) {
1720
+ const query = generateStringFromObject(payload);
1721
+ const url = cidePath.join([
1722
+ hostManagerRoutesUrl.cideSuiteHost,
1723
+ academicsRoutesUrl.module,
1724
+ academicsRoutesUrl.classProgramBranch,
1725
+ 'byId',
1726
+ query
1727
+ ]);
1728
+ return this.http.get(url);
1729
+ }
1730
+ /**
1731
+ * Create or update class program branch
1732
+ * @param data - Class program branch data to save
1733
+ * @returns Observable of the save response
1734
+ */
1735
+ saveClassProgramBranch(data) {
1736
+ const url = cidePath.join([
1737
+ hostManagerRoutesUrl.cideSuiteHost,
1738
+ academicsRoutesUrl.module,
1739
+ academicsRoutesUrl.classProgramBranch
1740
+ ]);
1741
+ return this.http.post(url, data);
1742
+ }
1743
+ /**
1744
+ * Delete class program branch
1745
+ * @param payload - Class program branch delete payload
1746
+ * @returns Observable of the delete response
1747
+ */
1748
+ deleteClassProgramBranch(payload) {
1749
+ const query = generateStringFromObject(payload);
1750
+ const url = cidePath.join([
1751
+ hostManagerRoutesUrl.cideSuiteHost,
1752
+ academicsRoutesUrl.module,
1753
+ academicsRoutesUrl.classProgramBranch,
1754
+ query
1755
+ ]);
1756
+ return this.http.delete(url);
1757
+ }
1758
+ /**
1759
+ * Toggle class program branch status (active/inactive)
1760
+ * @param payload - Class program branch toggle status payload
1761
+ * @returns Observable of the toggle status response
1762
+ */
1763
+ toggleClassProgramBranchStatus(payload) {
1764
+ const query = generateStringFromObject(payload);
1765
+ const url = cidePath.join([
1766
+ hostManagerRoutesUrl.cideSuiteHost,
1767
+ academicsRoutesUrl.module,
1768
+ academicsRoutesUrl.classProgramBranch,
1769
+ 'toggleStatus',
1770
+ query
1771
+ ]);
1772
+ return this.http.put(url, {});
1773
+ }
1774
+ /**
1775
+ * Toggle class program branch lock
1776
+ * @param payload - Class program branch toggle lock payload
1777
+ * @returns Observable of the toggle lock response
1778
+ */
1779
+ toggleClassProgramBranchLock(payload) {
1780
+ const query = generateStringFromObject(payload);
1781
+ const url = cidePath.join([
1782
+ hostManagerRoutesUrl.cideSuiteHost,
1783
+ academicsRoutesUrl.module,
1784
+ academicsRoutesUrl.classProgramBranch,
1785
+ 'toggleLock',
1786
+ query
1787
+ ]);
1788
+ return this.http.put(url, {});
1789
+ }
1790
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytClassProgramBranchService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1791
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytClassProgramBranchService, providedIn: 'root' });
1792
+ }
1793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytClassProgramBranchService, decorators: [{
1794
+ type: Injectable,
1795
+ args: [{
1796
+ providedIn: 'root'
1797
+ }]
1798
+ }] });
1799
+
1800
+ class CideLytClassProgramBranchListComponent {
1801
+ // Dependency injection
1802
+ destroyRef = inject(DestroyRef);
1803
+ router = inject(Router);
1804
+ route = inject(ActivatedRoute);
1805
+ appState = inject(AppStateHelperService);
1806
+ notificationService = inject(NotificationService);
1807
+ confirmationService = inject(ConfirmationService);
1808
+ classProgramBranchService = inject(CideLytClassProgramBranchService);
1809
+ // State management
1810
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1811
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
1812
+ branches = signal([], ...(ngDevMode ? [{ debugName: "branches" }] : []));
1813
+ totalCount = signal(0, ...(ngDevMode ? [{ debugName: "totalCount" }] : []));
1814
+ programId = signal(null, ...(ngDevMode ? [{ debugName: "programId" }] : []));
1815
+ // Template renderers
1816
+ dragHandleRendererTemplate = viewChild('dragHandleRendererTemplate', ...(ngDevMode ? [{ debugName: "dragHandleRendererTemplate" }] : []));
1817
+ classProgramRendererTemplate = viewChild('classProgramRendererTemplate', ...(ngDevMode ? [{ debugName: "classProgramRendererTemplate" }] : []));
1818
+ actionsDropdownRendererTemplate = viewChild('actionsDropdownRendererTemplate', ...(ngDevMode ? [{ debugName: "actionsDropdownRendererTemplate" }] : []));
1819
+ // Grid configuration
1820
+ gridConfig = signal({
1821
+ id: 'class-program-branch-list-grid',
1822
+ title: '',
1823
+ subtitle: '',
1824
+ columns: [
1825
+ {
1826
+ key: 'drag',
1827
+ header: '',
1828
+ type: 'custom',
1829
+ width: '40px',
1830
+ truncate: false,
1831
+ align: 'center',
1832
+ renderer: 'dragHandleRenderer'
1833
+ },
1834
+ {
1835
+ key: 'acabrn_name',
1836
+ header: 'Branch Name',
1837
+ type: 'text',
1838
+ width: '200px',
1839
+ truncate: true,
1840
+ align: 'left'
1841
+ },
1842
+ {
1843
+ key: 'acabrn_code',
1844
+ header: 'Code',
1845
+ type: 'text',
1846
+ width: '150px',
1847
+ truncate: true,
1848
+ align: 'left'
1849
+ },
1850
+ {
1851
+ key: 'acabrn_class_program_id_acacpm',
1852
+ header: 'Class Program',
1853
+ type: 'custom',
1854
+ width: '200px',
1855
+ truncate: true,
1856
+ align: 'left',
1857
+ renderer: 'classProgramRenderer'
1858
+ },
1859
+ {
1860
+ key: 'acabrn_isactive',
1861
+ header: 'Status',
1862
+ type: 'status',
1863
+ width: '100px',
1864
+ truncate: false,
1865
+ align: 'center',
1866
+ statusConfig: {
1867
+ activeValue: true,
1868
+ activeLabel: 'Active',
1869
+ inactiveLabel: 'Inactive',
1870
+ activeClass: 'tw-bg-green-100 tw-text-green-800',
1871
+ inactiveClass: 'tw-bg-red-100 tw-text-red-800'
1872
+ }
1873
+ },
1874
+ {
1875
+ key: 'acabrn_islocked',
1876
+ header: 'Locked',
1877
+ type: 'status',
1878
+ width: '100px',
1879
+ truncate: false,
1880
+ align: 'center',
1881
+ statusConfig: {
1882
+ activeValue: true,
1883
+ activeLabel: 'Locked',
1884
+ inactiveLabel: 'Unlocked',
1885
+ activeClass: 'tw-bg-yellow-100 tw-text-yellow-800',
1886
+ inactiveClass: 'tw-bg-gray-100 tw-text-gray-800'
1887
+ }
1888
+ },
1889
+ {
1890
+ key: 'actions',
1891
+ header: '',
1892
+ type: 'custom',
1893
+ width: '80px',
1894
+ truncate: false,
1895
+ align: 'center',
1896
+ renderer: 'actionsDropdownRenderer'
1897
+ }
1898
+ ],
1899
+ data: [],
1900
+ trackBy: '_id',
1901
+ pagination: {
1902
+ enabled: true,
1903
+ pageSize: 10,
1904
+ pageSizeOptions: [10, 25, 50, 100],
1905
+ showQuickJump: true,
1906
+ showPageInfo: true,
1907
+ showRefresh: true
1908
+ },
1909
+ search: {
1910
+ enabled: true,
1911
+ placeholder: 'Search branches...',
1912
+ searchableColumns: ['acabrn_name', 'acabrn_code'],
1913
+ debounceMs: 300
1914
+ },
1915
+ loading: {
1916
+ useDefer: true,
1917
+ skeletonRows: 5,
1918
+ showOverlay: false
1919
+ },
1920
+ scroll: {
1921
+ enabled: true,
1922
+ maxHeight: '600px',
1923
+ minHeight: '400px',
1924
+ stickyHeader: true,
1925
+ virtualScroll: false,
1926
+ rowHeight: 50
1927
+ },
1928
+ responsive: true,
1929
+ striped: true,
1930
+ bordered: true,
1931
+ compact: false,
1932
+ tableClass: 'tw-table-fixed tw-w-full tw-rounded-lg',
1933
+ dragDrop: {
1934
+ enabled: true
1935
+ },
1936
+ onRefresh: 'onRefresh',
1937
+ onPageChange: 'onPageChange',
1938
+ onSearch: 'onSearch',
1939
+ onRowReorder: 'onRowReorder'
1940
+ }, ...(ngDevMode ? [{ debugName: "gridConfig" }] : []));
1941
+ // Computed template renderers
1942
+ templateRenderers = computed(() => {
1943
+ const renderers = {};
1944
+ if (this.dragHandleRendererTemplate()) {
1945
+ renderers['dragHandleRenderer'] = this.dragHandleRendererTemplate();
1946
+ }
1947
+ if (this.classProgramRendererTemplate()) {
1948
+ renderers['classProgramRenderer'] = this.classProgramRendererTemplate();
1949
+ }
1950
+ if (this.actionsDropdownRendererTemplate()) {
1951
+ renderers['actionsDropdownRenderer'] = this.actionsDropdownRendererTemplate();
1952
+ }
1953
+ return renderers;
1954
+ }, ...(ngDevMode ? [{ debugName: "templateRenderers" }] : []));
1955
+ ngOnInit() {
1956
+ console.log('🏢 Class Program Branch List Component initialized');
1957
+ this.checkRouteParams();
1958
+ // Load branches will be called when programId is set in checkRouteParams
1959
+ }
1960
+ /**
1961
+ * Check route parameters for program ID
1962
+ */
1963
+ checkRouteParams() {
1964
+ this.route.params.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(params => {
1965
+ const queryParams = params['query'];
1966
+ console.log('🏢 Route params:', params, 'queryParams:', queryParams);
1967
+ if (queryParams) {
1968
+ // Query parameters passed (following page-controls pattern)
1969
+ const queryData = generateObjectFromString(queryParams);
1970
+ console.log('🏢 Program Class ID from route:', queryData);
1971
+ if (queryData?.programId) {
1972
+ this.programId.set(queryData.programId);
1973
+ console.log('🏢 Will filter branches by acabrn_class_program_id_acacpm:', queryData.programId);
1974
+ this.loadBranches();
1975
+ }
1976
+ }
1977
+ else {
1978
+ // Check for direct query parameters (fallback)
1979
+ const queryParams = this.route.snapshot.queryParams;
1980
+ const programId = queryParams['programId'] || queryParams['acabrn_class_program_id_acacpm'];
1981
+ if (programId) {
1982
+ this.programId.set(programId);
1983
+ console.log('🏢 Program Class ID from query params:', programId);
1984
+ console.log('🏢 Will filter branches by acabrn_class_program_id_acacpm:', programId);
1985
+ this.loadBranches();
1986
+ }
1987
+ else {
1988
+ // Load all branches if no program ID is provided
1989
+ console.log('🏢 No program class ID provided, loading all branches');
1990
+ this.loadBranches();
1991
+ }
1992
+ }
1993
+ });
1994
+ }
1995
+ /**
1996
+ * Load branches from API
1997
+ */
1998
+ loadBranches() {
1999
+ this.loading.set(true);
2000
+ this.error.set(null);
2001
+ const payload = {
2002
+ pagination: true,
2003
+ pageIndex: 0,
2004
+ pageSize: 10,
2005
+ acabrn_class_program_id_acacpm: this.programId()
2006
+ };
2007
+ // Add program class ID filter if available
2008
+ const currentProgramId = this.programId();
2009
+ if (currentProgramId) {
2010
+ // Filter branches by program class ID using acabrn_class_program_id_acacpm field
2011
+ console.log('🏢 Filtering branches by acabrn_class_program_id_acacpm:', currentProgramId);
2012
+ }
2013
+ else {
2014
+ console.log('🏢 No program class ID filter applied, loading all branches');
2015
+ }
2016
+ this.classProgramBranchService.getClassProgramBranchList(payload)
2017
+ .pipe(takeUntilDestroyed(this.destroyRef))
2018
+ .subscribe({
2019
+ next: (response) => {
2020
+ console.log('✅ Branches loaded:', response);
2021
+ if (response?.success && response.data) {
2022
+ this.branches.set(response.data);
2023
+ this.totalCount.set(response.total || 0);
2024
+ this.updateGridData();
2025
+ }
2026
+ else {
2027
+ this.error.set('Failed to load branches');
2028
+ this.notificationService.error('Failed to load branches');
2029
+ }
2030
+ this.loading.set(false);
2031
+ },
2032
+ error: (error) => {
2033
+ console.error('❌ Error loading branches:', error);
2034
+ this.error.set('Failed to load branches');
2035
+ this.loading.set(false);
2036
+ this.notificationService.error('Failed to load branches');
2037
+ }
2038
+ });
2039
+ }
2040
+ /**
2041
+ * Update grid data
2042
+ */
2043
+ updateGridData() {
2044
+ this.gridConfig.update(config => ({
2045
+ ...config,
2046
+ data: this.branches()
2047
+ }));
2048
+ }
2049
+ /**
2050
+ * Handle grid events
2051
+ */
2052
+ onGridEvent(event) {
2053
+ console.log('Grid Event:', event);
2054
+ switch (event.type) {
2055
+ case 'refresh':
2056
+ this.onRefresh();
2057
+ break;
2058
+ case 'pageChange':
2059
+ this.onPageChange(event.data);
2060
+ break;
2061
+ case 'search':
2062
+ this.onSearch(event.data);
2063
+ break;
2064
+ case 'rowReorder':
2065
+ this.onRowReorder(event.data);
2066
+ break;
2067
+ }
2068
+ }
2069
+ /**
2070
+ * Handle refresh
2071
+ */
2072
+ onRefresh() {
2073
+ this.loadBranches();
2074
+ }
2075
+ /**
2076
+ * Handle page change
2077
+ */
2078
+ onPageChange(event) {
2079
+ console.log('Page change:', event);
2080
+ // Implement pagination logic here
2081
+ }
2082
+ /**
2083
+ * Handle search
2084
+ */
2085
+ onSearch(event) {
2086
+ console.log('Search:', event);
2087
+ // Implement search logic here
2088
+ }
2089
+ /**
2090
+ * Handle row reorder (drag and drop)
2091
+ */
2092
+ onRowReorder(event) {
2093
+ console.log('Row reorder:', event);
2094
+ if (event && event.newOrder) {
2095
+ // Update the sequence order based on the new drag and drop order
2096
+ this.updateSequenceOrder(event.newOrder);
2097
+ }
2098
+ }
2099
+ /**
2100
+ * Update sequence order for branches
2101
+ */
2102
+ updateSequenceOrder(branches) {
2103
+ // Update sequence numbers based on new order
2104
+ const updatedBranches = branches.map((branch, index) => ({
2105
+ ...branch,
2106
+ acabrn_sequence: index + 1
2107
+ }));
2108
+ // Update local state
2109
+ this.branches.set(updatedBranches);
2110
+ this.updateGridData();
2111
+ // TODO: Implement API call to update sequence order on server
2112
+ // This would typically be a bulk update API call
2113
+ console.log('Updated sequence order:', updatedBranches.map(b => ({ id: b._id, sequence: b.acabrn_sequence })));
2114
+ this.notificationService.success('Sequence order updated successfully');
2115
+ }
2116
+ /**
2117
+ * Navigate to create branch
2118
+ */
2119
+ onCreateBranch() {
2120
+ const currentProgramId = this.programId();
2121
+ if (currentProgramId) {
2122
+ // Use generateStringFromObject to pass programId as route parameter
2123
+ const queryParams = generateStringFromObject({ programId: currentProgramId });
2124
+ this.router.navigate(['/control-panel/program_specialization/create', queryParams]);
2125
+ }
2126
+ else {
2127
+ // No program ID, navigate to create without parameters
2128
+ this.router.navigate(['/control-panel/program_specialization/create']);
2129
+ }
2130
+ }
2131
+ /**
2132
+ * Navigate to view branch
2133
+ */
2134
+ onViewBranch(branch) {
2135
+ if (branch._id) {
2136
+ const currentProgramId = this.programId();
2137
+ const queryParams = generateStringFromObject({ acabrn_id: branch._id });
2138
+ // Add programId as query parameter if available
2139
+ const navigationExtras = {};
2140
+ if (currentProgramId) {
2141
+ navigationExtras.queryParams = { programId: currentProgramId };
2142
+ }
2143
+ this.router.navigate(['/control-panel/program_specialization/view', queryParams], navigationExtras);
2144
+ }
2145
+ }
2146
+ /**
2147
+ * Navigate to edit branch
2148
+ */
2149
+ onEditBranch(branch) {
2150
+ if (branch._id) {
2151
+ const currentProgramId = this.programId();
2152
+ const queryParams = generateStringFromObject({ acabrn_id: branch._id });
2153
+ this.router.navigate(['/control-panel/program_specialization/edit', queryParams]);
2154
+ }
2155
+ }
2156
+ /**
2157
+ * Navigate to manage term for branch
2158
+ */
2159
+ onManageTerm(branch) {
2160
+ if (branch._id) {
2161
+ const currentProgramId = this.programId();
2162
+ const queryParams = generateStringFromObject({
2163
+ acabrn_id: branch._id,
2164
+ acacpm_id: currentProgramId
2165
+ });
2166
+ // Navigate to term management page
2167
+ this.router.navigate(['/control-panel/program-term-management', queryParams]);
2168
+ }
2169
+ }
2170
+ /**
2171
+ * Get dropdown items for branch actions
2172
+ */
2173
+ getBranchActionDropdownItems(branch) {
2174
+ return [
2175
+ {
2176
+ id: 'view',
2177
+ label: 'View',
2178
+ icon: 'visibility'
2179
+ },
2180
+ {
2181
+ id: 'edit',
2182
+ label: 'Edit',
2183
+ icon: 'edit'
2184
+ },
2185
+ {
2186
+ id: 'manage-term',
2187
+ label: 'Manage Term',
2188
+ icon: 'school'
2189
+ },
2190
+ {
2191
+ id: 'toggle-status',
2192
+ label: branch.acabrn_isactive ? 'Deactivate' : 'Activate',
2193
+ icon: branch.acabrn_isactive ? 'block' : 'check_circle'
2194
+ },
2195
+ {
2196
+ id: 'toggle-lock',
2197
+ label: branch.acabrn_islocked ? 'Unlock' : 'Lock',
2198
+ icon: branch.acabrn_islocked ? 'lock_open' : 'lock'
2199
+ },
2200
+ {
2201
+ id: 'delete',
2202
+ label: 'Delete',
2203
+ icon: 'delete',
2204
+ }
2205
+ ];
2206
+ }
2207
+ /**
2208
+ * Handle dropdown item click
2209
+ */
2210
+ onDropdownItemClick(item, branch) {
2211
+ switch (item.id) {
2212
+ case 'view':
2213
+ this.onViewBranch(branch);
2214
+ break;
2215
+ case 'edit':
2216
+ this.onEditBranch(branch);
2217
+ break;
2218
+ case 'manage-term':
2219
+ this.onManageTerm(branch);
2220
+ break;
2221
+ case 'toggle-status':
2222
+ this.toggleBranchStatus(branch);
2223
+ break;
2224
+ case 'toggle-lock':
2225
+ this.toggleBranchLock(branch);
2226
+ break;
2227
+ case 'delete':
2228
+ this.deleteBranch(branch);
2229
+ break;
2230
+ }
2231
+ }
2232
+ /**
2233
+ * Toggle branch status
2234
+ */
2235
+ toggleBranchStatus(branch) {
2236
+ if (!branch._id)
2237
+ return;
2238
+ const action = branch.acabrn_isactive ? 'deactivate' : 'activate';
2239
+ this.confirmationService.ask({
2240
+ title: `${action.charAt(0).toUpperCase() + action.slice(1)} Branch`,
2241
+ message: `Are you sure you want to ${action} this branch?`,
2242
+ confirmText: action.charAt(0).toUpperCase() + action.slice(1),
2243
+ cancelText: 'Cancel',
2244
+ type: 'warning'
2245
+ }).then((confirmed) => {
2246
+ if (confirmed) {
2247
+ const payload = {
2248
+ acabrn_id: branch._id
2249
+ };
2250
+ this.classProgramBranchService.toggleClassProgramBranchStatus(payload)
2251
+ .pipe(takeUntilDestroyed(this.destroyRef))
2252
+ .subscribe({
2253
+ next: (response) => {
2254
+ if (response?.success) {
2255
+ this.notificationService.success(`Branch ${action}d successfully`);
2256
+ this.loadBranches();
2257
+ }
2258
+ else {
2259
+ this.notificationService.error(`Failed to ${action} branch`);
2260
+ }
2261
+ },
2262
+ error: (error) => {
2263
+ console.error('❌ Error toggling branch status:', error);
2264
+ this.notificationService.error(`Failed to ${action} branch`);
2265
+ }
2266
+ });
2267
+ }
2268
+ });
2269
+ }
2270
+ /**
2271
+ * Toggle branch lock
2272
+ */
2273
+ toggleBranchLock(branch) {
2274
+ if (!branch._id)
2275
+ return;
2276
+ const action = branch.acabrn_islocked ? 'unlock' : 'lock';
2277
+ this.confirmationService.ask({
2278
+ title: `${action.charAt(0).toUpperCase() + action.slice(1)} Branch`,
2279
+ message: `Are you sure you want to ${action} this branch?`,
2280
+ confirmText: action.charAt(0).toUpperCase() + action.slice(1),
2281
+ cancelText: 'Cancel',
2282
+ type: 'warning'
2283
+ }).then((confirmed) => {
2284
+ if (confirmed) {
2285
+ const payload = {
2286
+ acabrn_id: branch._id
2287
+ };
2288
+ this.classProgramBranchService.toggleClassProgramBranchLock(payload)
2289
+ .pipe(takeUntilDestroyed(this.destroyRef))
2290
+ .subscribe({
2291
+ next: (response) => {
2292
+ if (response?.success) {
2293
+ this.notificationService.success(`Branch ${action}ed successfully`);
2294
+ this.loadBranches();
2295
+ }
2296
+ else {
2297
+ this.notificationService.error(`Failed to ${action} branch`);
2298
+ }
2299
+ },
2300
+ error: (error) => {
2301
+ console.error('❌ Error toggling branch lock:', error);
2302
+ this.notificationService.error(`Failed to ${action} branch`);
2303
+ }
2304
+ });
2305
+ }
2306
+ });
2307
+ }
2308
+ /**
2309
+ * Delete branch
2310
+ */
2311
+ deleteBranch(branch) {
2312
+ if (!branch._id)
2313
+ return;
2314
+ this.confirmationService.ask({
2315
+ title: 'Delete Branch',
2316
+ message: `Are you sure you want to delete "${branch.acabrn_name}"? This action cannot be undone.`,
2317
+ confirmText: 'Delete',
2318
+ cancelText: 'Cancel',
2319
+ type: 'danger'
2320
+ }).then((confirmed) => {
2321
+ if (confirmed) {
2322
+ const payload = {
2323
+ acabrn_id: branch._id
2324
+ };
2325
+ this.classProgramBranchService.deleteClassProgramBranch(payload)
2326
+ .pipe(takeUntilDestroyed(this.destroyRef))
2327
+ .subscribe({
2328
+ next: (response) => {
2329
+ if (response?.success) {
2330
+ this.notificationService.success('Branch deleted successfully');
2331
+ this.loadBranches();
2332
+ }
2333
+ else {
2334
+ this.notificationService.error('Failed to delete branch');
2335
+ }
2336
+ },
2337
+ error: (error) => {
2338
+ console.error('❌ Error deleting branch:', error);
2339
+ this.notificationService.error('Failed to delete branch');
2340
+ }
2341
+ });
2342
+ }
2343
+ });
2344
+ }
2345
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytClassProgramBranchListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2346
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.1.7", type: CideLytClassProgramBranchListComponent, isStandalone: true, selector: "cide-academics-class-program-branch-list", viewQueries: [{ propertyName: "dragHandleRendererTemplate", first: true, predicate: ["dragHandleRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "classProgramRendererTemplate", first: true, predicate: ["classProgramRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Class Program Branch Container -->\r\n<div class=\"tw-table tw-w-full tw-h-full\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">account_tree</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Class Program Branch Management</h5>\r\n </div>\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"onCreateBranch()\">\r\n Create Branch\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Data Grid Section -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-p-0\">\r\n <cide-ele-data-grid\r\n [config]=\"gridConfig()\"\r\n [templateRenderers]=\"templateRenderers()\"\r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Template Renderers -->\r\n<ng-template #dragHandleRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-justify-center tw-cursor-move drag-handle\" title=\"Drag to reorder\">\r\n <cide-ele-icon name=\"drag_indicator\" class=\"tw-w-4 tw-h-4 tw-text-gray-400 hover:tw-text-gray-600\"></cide-ele-icon>\r\n </div>\r\n</ng-template>\r\n\r\n\r\n<ng-template #classProgramRendererTemplate let-row=\"row\">\r\n <div class=\"tw-text-sm tw-text-gray-900\">\r\n {{ row.acabrn_class_program_id_acacpm?.acacpm_alise_title || 'N/A' }}\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\">\r\n <div class=\"tw-relative tw-inline-block\">\r\n <cide-ele-dropdown \r\n [items]=\"getBranchActionDropdownItems(row)\" \r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n </div>\r\n</ng-template>\r\n\r\n", styles: [".drag-handle{cursor:move}.drag-handle:hover{background-color:#0000000d;border-radius:4px}.tw-table tbody tr{cursor:pointer}.tw-table tbody tr:hover{background-color:#00000005}.tw-table tbody tr.selected{background-color:#3b82f61a}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton]", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }] });
2347
+ }
2348
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytClassProgramBranchListComponent, decorators: [{
2349
+ type: Component,
2350
+ args: [{ selector: 'cide-academics-class-program-branch-list', standalone: true, imports: [
2351
+ CommonModule,
2352
+ CideEleDataGridComponent,
2353
+ CideIconComponent,
2354
+ CideEleButtonComponent,
2355
+ CideEleDropdownComponent
2356
+ ], template: "<!-- Class Program Branch Container -->\r\n<div class=\"tw-table tw-w-full tw-h-full\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">account_tree</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Class Program Branch Management</h5>\r\n </div>\r\n <div\r\n class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <button cideEleButton variant=\"primary\" size=\"sm\" leftIcon=\"add\" (click)=\"onCreateBranch()\">\r\n Create Branch\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Data Grid Section -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-p-0\">\r\n <cide-ele-data-grid\r\n [config]=\"gridConfig()\"\r\n [templateRenderers]=\"templateRenderers()\"\r\n (gridEvent)=\"onGridEvent($event)\">\r\n </cide-ele-data-grid>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Template Renderers -->\r\n<ng-template #dragHandleRendererTemplate let-row=\"row\">\r\n <div class=\"tw-flex tw-justify-center tw-cursor-move drag-handle\" title=\"Drag to reorder\">\r\n <cide-ele-icon name=\"drag_indicator\" class=\"tw-w-4 tw-h-4 tw-text-gray-400 hover:tw-text-gray-600\"></cide-ele-icon>\r\n </div>\r\n</ng-template>\r\n\r\n\r\n<ng-template #classProgramRendererTemplate let-row=\"row\">\r\n <div class=\"tw-text-sm tw-text-gray-900\">\r\n {{ row.acabrn_class_program_id_acacpm?.acacpm_alise_title || 'N/A' }}\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\">\r\n <div class=\"tw-relative tw-inline-block\">\r\n <cide-ele-dropdown \r\n [items]=\"getBranchActionDropdownItems(row)\" \r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n </div>\r\n</ng-template>\r\n\r\n", styles: [".drag-handle{cursor:move}.drag-handle:hover{background-color:#0000000d;border-radius:4px}.tw-table tbody tr{cursor:pointer}.tw-table tbody tr:hover{background-color:#00000005}.tw-table tbody tr.selected{background-color:#3b82f61a}\n"] }]
2357
+ }] });
2358
+
2359
+ var classProgramBranchList_component = /*#__PURE__*/Object.freeze({
2360
+ __proto__: null,
2361
+ CideLytClassProgramBranchListComponent: CideLytClassProgramBranchListComponent
2362
+ });
2363
+
2364
+ class CideLytProgramClassService {
2365
+ http = inject(HttpClient);
2366
+ /**
2367
+ * Get list of program classes
2368
+ * @param payload - Query parameters for filtering/pagination
2369
+ * @returns Observable of program class list response
2370
+ */
2371
+ getProgramClassList(payload) {
2372
+ console.log("Program Class List Payload:", payload);
2373
+ const query = generateStringFromObject(payload);
2374
+ const url = cidePath.join([
2375
+ hostManagerRoutesUrl.cideSuiteHost,
2376
+ academicsRoutesUrl.module,
2377
+ academicsRoutesUrl.classProgramMaster,
2378
+ query
2379
+ ]);
2380
+ return this.http.get(url);
2381
+ }
2382
+ /**
2383
+ * Get program class by ID
2384
+ * @param payload - Program class ID payload
2385
+ * @returns Observable of program class data
2386
+ */
2387
+ getProgramClassById(payload) {
2388
+ const query = generateStringFromObject(payload);
2389
+ const url = cidePath.join([
2390
+ hostManagerRoutesUrl.cideSuiteHost,
2391
+ academicsRoutesUrl.module,
2392
+ academicsRoutesUrl.classProgramMaster,
2393
+ 'byId',
2394
+ query
2395
+ ]);
2396
+ return this.http.get(url);
2397
+ }
2398
+ /**
2399
+ * Create or update program class
2400
+ * @param data - Program class data to save
2401
+ * @returns Observable of the save response
2402
+ */
2403
+ saveProgramClass(data) {
2404
+ const url = cidePath.join([
2405
+ hostManagerRoutesUrl.cideSuiteHost,
2406
+ academicsRoutesUrl.module,
2407
+ academicsRoutesUrl.classProgramMaster
2408
+ ]);
2409
+ return this.http.post(url, data);
2410
+ }
2411
+ /**
2412
+ * Delete program class
2413
+ * @param payload - Program class delete payload
2414
+ * @returns Observable of the delete response
2415
+ */
2416
+ deleteProgramClass(payload) {
2417
+ const query = generateStringFromObject(payload);
2418
+ const url = cidePath.join([
2419
+ hostManagerRoutesUrl.cideSuiteHost,
2420
+ academicsRoutesUrl.module,
2421
+ academicsRoutesUrl.classProgramMaster,
2422
+ query
2423
+ ]);
2424
+ return this.http.delete(url);
2425
+ }
2426
+ /**
2427
+ * Toggle program class status (active/inactive)
2428
+ * @param payload - Program class toggle status payload
2429
+ * @returns Observable of the toggle status response
2430
+ */
2431
+ toggleProgramClassStatus(payload) {
2432
+ const query = generateStringFromObject(payload);
2433
+ const url = cidePath.join([
2434
+ hostManagerRoutesUrl.cideSuiteHost,
2435
+ academicsRoutesUrl.module,
2436
+ academicsRoutesUrl.classProgramMaster,
2437
+ 'toggleStatus',
2438
+ query
2439
+ ]);
2440
+ return this.http.put(url, {});
2441
+ }
2442
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytProgramClassService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2443
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytProgramClassService, providedIn: 'root' });
2444
+ }
2445
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytProgramClassService, decorators: [{
2446
+ type: Injectable,
2447
+ args: [{
2448
+ providedIn: 'root'
2449
+ }]
2450
+ }] });
2451
+
2452
+ class CideLytClassProgramBranchFormComponent {
2453
+ // Dependency injection
2454
+ destroyRef = inject(DestroyRef);
2455
+ fb = inject(FormBuilder);
2456
+ router = inject(Router);
2457
+ route = inject(ActivatedRoute);
2458
+ location = inject(Location);
2459
+ appState = inject(AppStateHelperService);
2460
+ notificationService = inject(NotificationService);
2461
+ confirmationService = inject(ConfirmationService);
2462
+ classProgramBranchService = inject(CideLytClassProgramBranchService);
2463
+ programClassService = inject(CideLytProgramClassService);
2464
+ // Form and state management
2465
+ branchForm;
2466
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
2467
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
2468
+ isEditMode = signal(false, ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
2469
+ isViewMode = signal(false, ...(ngDevMode ? [{ debugName: "isViewMode" }] : []));
2470
+ branchId = signal(null, ...(ngDevMode ? [{ debugName: "branchId" }] : []));
2471
+ // Data signals
2472
+ programClasses = signal([], ...(ngDevMode ? [{ debugName: "programClasses" }] : []));
2473
+ constructor() {
2474
+ this.branchForm = this.fb.group({
2475
+ acabrn_name: ['', [Validators.required, Validators.minLength(2)]],
2476
+ acabrn_code: ['', [Validators.required, Validators.minLength(2)]],
2477
+ acabrn_sequence: [0, [Validators.required, Validators.min(0)]],
2478
+ acabrn_class_program_id_acacpm: ['', [Validators.required]],
2479
+ acabrn_isactive: [true],
2480
+ acabrn_islocked: [false]
2481
+ });
2482
+ }
2483
+ ngOnInit() {
2484
+ console.log('🏢 Class Program Branch Form Component initialized');
2485
+ this.initializeComponent();
2486
+ }
2487
+ ngOnDestroy() {
2488
+ console.log('🏢 Class Program Branch Form Component destroyed');
2489
+ }
2490
+ /**
2491
+ * Initialize component
2492
+ */
2493
+ initializeComponent() {
2494
+ this.loadMasterData();
2495
+ this.checkRouteParams();
2496
+ }
2497
+ /**
2498
+ * Check route parameters to determine mode
2499
+ */
2500
+ checkRouteParams() {
2501
+ const url = this.router.url;
2502
+ const queryParams = this.route.snapshot.queryParams;
2503
+ const routeParams = this.route.snapshot.params;
2504
+ // Check for program ID from route parameters or query parameters
2505
+ // Also check route parameters for programId (for create operations)
2506
+ let programId = {};
2507
+ if (routeParams['query']) {
2508
+ const params = generateObjectFromString(routeParams['query']);
2509
+ console.log('🏢 Params:generateObjectFromString', params);
2510
+ programId = params?.programId;
2511
+ }
2512
+ if (programId) {
2513
+ console.log('🏢 Program ID from route:', programId);
2514
+ // Pre-select the program in the form
2515
+ this.branchForm.patchValue({
2516
+ acabrn_class_program_id_acacpm: programId
2517
+ });
2518
+ }
2519
+ if (url.includes('/view/')) {
2520
+ this.isViewMode.set(true);
2521
+ this.loadBranchForView(queryParams);
2522
+ }
2523
+ else if (url.includes('/edit/')) {
2524
+ this.isEditMode.set(true);
2525
+ this.loadBranchForEdit(queryParams);
2526
+ }
2527
+ else {
2528
+ // Create mode
2529
+ this.isEditMode.set(false);
2530
+ this.isViewMode.set(false);
2531
+ }
2532
+ }
2533
+ /**
2534
+ * Load master data
2535
+ */
2536
+ loadMasterData() {
2537
+ console.log('🔄 Loading master data for Class Program Branch Form...');
2538
+ // Load program classes
2539
+ this.loadProgramClasses();
2540
+ }
2541
+ /**
2542
+ * Load program classes
2543
+ */
2544
+ loadProgramClasses() {
2545
+ this.programClassService.getProgramClassList({ pagination: false })
2546
+ .pipe(takeUntilDestroyed(this.destroyRef))
2547
+ .subscribe({
2548
+ next: (response) => {
2549
+ console.log('✅ Program classes loaded:', response);
2550
+ if (response?.success && response.data) {
2551
+ this.programClasses.set(response.data);
2552
+ }
2553
+ else {
2554
+ console.warn('⚠️ No program class data received');
2555
+ this.programClasses.set([]);
2556
+ }
2557
+ },
2558
+ error: (error) => {
2559
+ console.error('❌ Error loading program classes:', error);
2560
+ this.programClasses.set([]);
2561
+ }
2562
+ });
2563
+ }
2564
+ /**
2565
+ * Load branch for viewing
2566
+ */
2567
+ loadBranchForView(queryParams) {
2568
+ const routeParams = this.route.snapshot.params;
2569
+ // Check query parameters first
2570
+ let params = generateObjectFromString(routeParams['query']);
2571
+ console.log('🏢 Params:generateObjectFromString', params);
2572
+ if (params?.acabrn_id) {
2573
+ console.log('🏢 Branch ID for view:', params.acabrn_id);
2574
+ this.branchId.set(params.acabrn_id);
2575
+ this.loadBranchData(params.acabrn_id, true);
2576
+ }
2577
+ else {
2578
+ console.error('❌ No branch ID found in route parameters');
2579
+ this.error.set('Branch ID not found in route parameters');
2580
+ }
2581
+ }
2582
+ /**
2583
+ * Load branch for editing
2584
+ */
2585
+ loadBranchForEdit(queryParams) {
2586
+ const routeParams = this.route.snapshot.params;
2587
+ // Check query parameters first
2588
+ let params = generateObjectFromString(routeParams['query']);
2589
+ console.log('🏢 Params:generateObjectFromString', params);
2590
+ if (params?.acabrn_id) {
2591
+ console.log('🏢 Branch ID for edit:', params.acabrn_id);
2592
+ this.branchId.set(params.acabrn_id);
2593
+ this.loadBranchData(params.acabrn_id, false);
2594
+ }
2595
+ else {
2596
+ console.error('❌ No branch ID found in route parameters');
2597
+ this.error.set('Branch ID not found in route parameters');
2598
+ }
2599
+ }
2600
+ /**
2601
+ * Load branch data
2602
+ */
2603
+ loadBranchData(branchId, isViewMode) {
2604
+ this.loading.set(true);
2605
+ this.error.set(null);
2606
+ const payload = {
2607
+ acabrn_id: branchId
2608
+ };
2609
+ this.classProgramBranchService.getClassProgramBranchById(payload)
2610
+ .pipe(takeUntilDestroyed(this.destroyRef))
2611
+ .subscribe({
2612
+ next: (response) => {
2613
+ if (response?.success && response.data) {
2614
+ const branchData = response.data;
2615
+ // Populate form with branch data
2616
+ this.branchForm.patchValue({
2617
+ acabrn_name: branchData.acabrn_name,
2618
+ acabrn_code: branchData.acabrn_code,
2619
+ acabrn_sequence: branchData.acabrn_sequence,
2620
+ acabrn_class_program_id_acacpm: branchData.acabrn_class_program_id_acacpm?._id,
2621
+ acabrn_isactive: (branchData).acabrn_isactive,
2622
+ acabrn_islocked: branchData.acabrn_islocked
2623
+ });
2624
+ // Disable form if in view mode
2625
+ if (isViewMode) {
2626
+ this.branchForm.disable();
2627
+ }
2628
+ this.notificationService.success('Branch data loaded successfully.');
2629
+ }
2630
+ else {
2631
+ this.error.set('Failed to load branch data.');
2632
+ this.notificationService.error('Failed to load branch data.');
2633
+ }
2634
+ this.loading.set(false);
2635
+ },
2636
+ error: (error) => {
2637
+ console.error('❌ Error loading branch data:', error);
2638
+ this.error.set('Failed to load branch data. Please try again.');
2639
+ this.loading.set(false);
2640
+ this.notificationService.error('Failed to load branch data. Please try again.');
2641
+ }
2642
+ });
2643
+ }
2644
+ /**
2645
+ * Get form title
2646
+ */
2647
+ get formTitle() {
2648
+ if (this.isViewMode())
2649
+ return 'View Program Specialization';
2650
+ if (this.isEditMode())
2651
+ return 'Edit Program Specialization';
2652
+ return 'Create Program Specialization';
2653
+ }
2654
+ /**
2655
+ * Get submit button text
2656
+ */
2657
+ get submitButtonText() {
2658
+ if (this.isViewMode())
2659
+ return 'Close';
2660
+ if (this.isEditMode())
2661
+ return 'Update Branch';
2662
+ return 'Create Branch';
2663
+ }
2664
+ /**
2665
+ * Handle form submission
2666
+ */
2667
+ onSubmit() {
2668
+ if (this.isViewMode()) {
2669
+ this.location.back();
2670
+ return;
2671
+ }
2672
+ if (this.branchForm.invalid) {
2673
+ this.notificationService.error('Please fill in all required fields correctly.');
2674
+ return;
2675
+ }
2676
+ const formData = this.branchForm.value;
2677
+ const payload = {
2678
+ _id: this.branchId() || undefined,
2679
+ acabrn_name: formData.acabrn_name,
2680
+ acabrn_code: formData.acabrn_code,
2681
+ acabrn_sequence: formData.acabrn_sequence,
2682
+ acabrn_class_program_id_acacpm: formData.acabrn_class_program_id_acacpm,
2683
+ acabrn_isactive: formData.acabrn_isactive,
2684
+ acabrn_islocked: formData.acabrn_islocked
2685
+ };
2686
+ this.saveBranch(payload);
2687
+ }
2688
+ /**
2689
+ * Save branch
2690
+ */
2691
+ saveBranch(payload) {
2692
+ this.loading.set(true);
2693
+ this.classProgramBranchService.saveClassProgramBranch(payload)
2694
+ .pipe(takeUntilDestroyed(this.destroyRef))
2695
+ .subscribe({
2696
+ next: (response) => {
2697
+ if (response?.success) {
2698
+ const action = this.isEditMode() ? 'updated' : 'created';
2699
+ this.notificationService.success(`Branch has been ${action} successfully.`);
2700
+ this.location.back();
2701
+ }
2702
+ else {
2703
+ this.notificationService.error(response?.message || 'Failed to save branch.');
2704
+ }
2705
+ this.loading.set(false);
2706
+ },
2707
+ error: (error) => {
2708
+ console.error('❌ Error saving branch:', error);
2709
+ this.notificationService.error('Failed to save branch. Please try again.');
2710
+ this.loading.set(false);
2711
+ }
2712
+ });
2713
+ }
2714
+ /**
2715
+ * Handle cancel
2716
+ */
2717
+ onCancel() {
2718
+ if (this.branchForm.dirty && !this.isViewMode()) {
2719
+ this.confirmationService.ask({
2720
+ title: 'Discard Changes',
2721
+ message: 'You have unsaved changes. Are you sure you want to discard them?',
2722
+ confirmText: 'Discard',
2723
+ cancelText: 'Keep Editing',
2724
+ type: 'warning'
2725
+ }).then((confirmed) => {
2726
+ if (confirmed) {
2727
+ this.location.back();
2728
+ }
2729
+ });
2730
+ }
2731
+ else {
2732
+ this.location.back();
2733
+ }
2734
+ }
2735
+ /**
2736
+ * Reset form to initial state
2737
+ */
2738
+ resetForm() {
2739
+ this.branchForm.reset();
2740
+ this.branchForm.patchValue({
2741
+ acabrn_isactive: true,
2742
+ acabrn_islocked: false,
2743
+ acabrn_sequence: 0
2744
+ });
2745
+ this.notificationService.info('Form has been reset to initial values.');
2746
+ }
2747
+ /**
2748
+ * Toggle active status on card click
2749
+ */
2750
+ onActiveCardClick() {
2751
+ if (this.isViewMode())
2752
+ return;
2753
+ const currentValue = this.branchForm.get('acabrn_isactive')?.value;
2754
+ this.branchForm.patchValue({
2755
+ acabrn_isactive: !currentValue
2756
+ });
2757
+ }
2758
+ /**
2759
+ * Toggle locked status on card click
2760
+ */
2761
+ onLockedCardClick() {
2762
+ if (this.isViewMode())
2763
+ return;
2764
+ const currentValue = this.branchForm.get('acabrn_islocked')?.value;
2765
+ this.branchForm.patchValue({
2766
+ acabrn_islocked: !currentValue
2767
+ });
2768
+ }
2769
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytClassProgramBranchFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2770
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideLytClassProgramBranchFormComponent, isStandalone: true, selector: "cide-academics-class-program-branch-form", ngImport: i0, template: "<!-- \r\n CLASS PROGRAM BRANCH FORM COMPONENT\r\n \r\n Enterprise-Level Styling with Tailwind CSS\r\n Features: Responsive grids, proper typography, enhanced user experience\r\n-->\r\n\r\n<div class=\"tw-w-full tw-h-full\">\r\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"branchForm\"\r\n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\r\n\r\n <!-- Simple Header Section -->\r\n <div class=\"tw-table-row tw-w-full tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n \r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">account_tree</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">\r\n {{ formTitle }}\r\n </h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <!-- Back button or other actions can be added here if needed -->\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Form Content -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-6\">\r\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\r\n \r\n <!-- Error Message -->\r\n @if (error()) {\r\n <div class=\"tw-mb-6 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\r\n <div class=\"tw-flex tw-items-start\">\r\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\r\n <div class=\"tw-ml-3\">\r\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\r\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Basic Branch Information -->\r\n <div class=\"tw-space-y-6\">\r\n <!-- Class Program Selection -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-1 tw-gap-6\">\r\n <div class=\"tw-space-y-2\">\r\n <label class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Class Program *</label>\r\n <cide-ele-select \r\n formControlName=\"acabrn_class_program_id_acacpm\" \r\n placeholder=\"Select class program\"\r\n [disabled]=\"isViewMode()\" \r\n valueKey=\"_id\" \r\n labelKey=\"acacpm_alise_title\" \r\n [options]=\"programClasses()\">\r\n </cide-ele-select>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">\r\n <cide-ele-icon name=\"info\" class=\"tw-w-4 tw-h-4 tw-mr-1\"></cide-ele-icon>\r\n Sequence will be automatically assigned based on the order in the listing\r\n </p>\r\n </div>\r\n </div>\r\n\r\n <!-- Branch Name and Code -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\r\n <div>\r\n <cide-ele-input \r\n label=\"Branch Name *\" \r\n formControlName=\"acabrn_name\"\r\n placeholder=\"e.g., Computer Science Branch\" \r\n size=\"md\" \r\n leadingIcon=\"account_tree\"\r\n [disabled]=\"isViewMode()\">\r\n </cide-ele-input>\r\n </div>\r\n\r\n <div>\r\n <cide-ele-input \r\n label=\"Branch Code *\" \r\n formControlName=\"acabrn_code\"\r\n placeholder=\"e.g., CS\" \r\n size=\"md\" \r\n leadingIcon=\"code\"\r\n [disabled]=\"isViewMode()\">\r\n </cide-ele-input>\r\n </div>\r\n </div>\r\n\r\n <!-- Status and Lock Options -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200 tw-cursor-pointer hover:tw-bg-gray-100 tw-transition-colors tw-duration-200\"\r\n [class.tw-cursor-not-allowed]=\"isViewMode()\"\r\n [class.tw-opacity-60]=\"isViewMode()\"\r\n (click)=\"onActiveCardClick()\">\r\n <cide-ele-input formControlName=\"acabrn_isactive\" type=\"checkbox\" size=\"md\" [disabled]=\"isViewMode()\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Active</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Enable/disable this branch</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200 tw-cursor-pointer hover:tw-bg-gray-100 tw-transition-colors tw-duration-200\"\r\n [class.tw-cursor-not-allowed]=\"isViewMode()\"\r\n [class.tw-opacity-60]=\"isViewMode()\"\r\n (click)=\"onLockedCardClick()\">\r\n <cide-ele-input formControlName=\"acabrn_islocked\" type=\"checkbox\" size=\"md\" [disabled]=\"isViewMode()\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Locked</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Prevent modifications</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Form Actions -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-2 tw-bg-gray-50 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-flex tw-justify-end tw-gap-4\">\r\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"resetForm()\" leftIcon=\"refresh\"\r\n [disabled]=\"loading()\">\r\n Reset Form\r\n </button>\r\n\r\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"onCancel()\" leftIcon=\"close\"\r\n [disabled]=\"loading()\">\r\n {{ isViewMode() ? 'Close' : 'Cancel' }}\r\n </button>\r\n\r\n @if (!isViewMode()) {\r\n <button cideEleButton type=\"submit\" variant=\"primary\" [disabled]=\"loading() || branchForm.invalid\"\r\n [loading]=\"loading()\" leftIcon=\"save\">\r\n {{ submitButtonText }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton]", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "ngModel", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey"], outputs: ["ngModelChange", "change", "searchChange"] }] });
2771
+ }
2772
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideLytClassProgramBranchFormComponent, decorators: [{
2773
+ type: Component,
2774
+ args: [{ selector: 'cide-academics-class-program-branch-form', standalone: true, imports: [
2775
+ CommonModule,
2776
+ ReactiveFormsModule,
2777
+ CideInputComponent,
2778
+ CideEleButtonComponent,
2779
+ CideIconComponent,
2780
+ CideSelectComponent,
2781
+ ], template: "<!-- \r\n CLASS PROGRAM BRANCH FORM COMPONENT\r\n \r\n Enterprise-Level Styling with Tailwind CSS\r\n Features: Responsive grids, proper typography, enhanced user experience\r\n-->\r\n\r\n<div class=\"tw-w-full tw-h-full\">\r\n <form class=\"tw-w-full tw-table tw-h-full tw-bg-transparent\" [formGroup]=\"branchForm\"\r\n [class.tw-opacity-60]=\"loading()\" (ngSubmit)=\"onSubmit()\">\r\n\r\n <!-- Simple Header Section -->\r\n <div class=\"tw-table-row tw-w-full tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n \r\n <!-- Title -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">account_tree</cide-ele-icon>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">\r\n {{ formTitle }}\r\n </h5>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0 sm:tw-space-x-3\">\r\n <!-- Back button or other actions can be added here if needed -->\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Form Content -->\r\n <div class=\"tw-table-row\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-6\">\r\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\r\n \r\n <!-- Error Message -->\r\n @if (error()) {\r\n <div class=\"tw-mb-6 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\r\n <div class=\"tw-flex tw-items-start\">\r\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\r\n <div class=\"tw-ml-3\">\r\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\r\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Basic Branch Information -->\r\n <div class=\"tw-space-y-6\">\r\n <!-- Class Program Selection -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-1 tw-gap-6\">\r\n <div class=\"tw-space-y-2\">\r\n <label class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Class Program *</label>\r\n <cide-ele-select \r\n formControlName=\"acabrn_class_program_id_acacpm\" \r\n placeholder=\"Select class program\"\r\n [disabled]=\"isViewMode()\" \r\n valueKey=\"_id\" \r\n labelKey=\"acacpm_alise_title\" \r\n [options]=\"programClasses()\">\r\n </cide-ele-select>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">\r\n <cide-ele-icon name=\"info\" class=\"tw-w-4 tw-h-4 tw-mr-1\"></cide-ele-icon>\r\n Sequence will be automatically assigned based on the order in the listing\r\n </p>\r\n </div>\r\n </div>\r\n\r\n <!-- Branch Name and Code -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\r\n <div>\r\n <cide-ele-input \r\n label=\"Branch Name *\" \r\n formControlName=\"acabrn_name\"\r\n placeholder=\"e.g., Computer Science Branch\" \r\n size=\"md\" \r\n leadingIcon=\"account_tree\"\r\n [disabled]=\"isViewMode()\">\r\n </cide-ele-input>\r\n </div>\r\n\r\n <div>\r\n <cide-ele-input \r\n label=\"Branch Code *\" \r\n formControlName=\"acabrn_code\"\r\n placeholder=\"e.g., CS\" \r\n size=\"md\" \r\n leadingIcon=\"code\"\r\n [disabled]=\"isViewMode()\">\r\n </cide-ele-input>\r\n </div>\r\n </div>\r\n\r\n <!-- Status and Lock Options -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200 tw-cursor-pointer hover:tw-bg-gray-100 tw-transition-colors tw-duration-200\"\r\n [class.tw-cursor-not-allowed]=\"isViewMode()\"\r\n [class.tw-opacity-60]=\"isViewMode()\"\r\n (click)=\"onActiveCardClick()\">\r\n <cide-ele-input formControlName=\"acabrn_isactive\" type=\"checkbox\" size=\"md\" [disabled]=\"isViewMode()\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Active</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Enable/disable this branch</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-border tw-border-gray-200 tw-cursor-pointer hover:tw-bg-gray-100 tw-transition-colors tw-duration-200\"\r\n [class.tw-cursor-not-allowed]=\"isViewMode()\"\r\n [class.tw-opacity-60]=\"isViewMode()\"\r\n (click)=\"onLockedCardClick()\">\r\n <cide-ele-input formControlName=\"acabrn_islocked\" type=\"checkbox\" size=\"md\" [disabled]=\"isViewMode()\">\r\n </cide-ele-input>\r\n <div class=\"tw-flex tw-flex-col\">\r\n <span class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Locked</span>\r\n <span class=\"tw-text-xs tw-text-gray-500\">Prevent modifications</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Form Actions -->\r\n <div class=\"tw-table-row tw-h-0\">\r\n <div class=\"tw-table-cell tw-w-full tw-px-6 tw-py-2 tw-bg-gray-50 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-flex tw-justify-end tw-gap-4\">\r\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"resetForm()\" leftIcon=\"refresh\"\r\n [disabled]=\"loading()\">\r\n Reset Form\r\n </button>\r\n\r\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"onCancel()\" leftIcon=\"close\"\r\n [disabled]=\"loading()\">\r\n {{ isViewMode() ? 'Close' : 'Cancel' }}\r\n </button>\r\n\r\n @if (!isViewMode()) {\r\n <button cideEleButton type=\"submit\" variant=\"primary\" [disabled]=\"loading() || branchForm.invalid\"\r\n [loading]=\"loading()\" leftIcon=\"save\">\r\n {{ submitButtonText }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n</div>\r\n\r\n" }]
2782
+ }], ctorParameters: () => [] });
2783
+
2784
+ var classProgramBranchForm_component = /*#__PURE__*/Object.freeze({
2785
+ __proto__: null,
2786
+ CideLytClassProgramBranchFormComponent: CideLytClassProgramBranchFormComponent
2787
+ });
2788
+
2789
+ // Class Program Branch Management Module
2790
+ // This module provides components and services for managing class program branches
2791
+ // Components
2792
+
2793
+ /*
2794
+ * Public API Surface of cloud-ide-academics
2795
+ */
2796
+
2797
+ /**
2798
+ * Generated bundle index. Do not edit.
2799
+ */
2800
+
2801
+ export { AcademicYearCreateComponent as A, CideLytProgramClassService as C, CideLytAcademicYearService as a, CideLytClassProgramBranchService as b, academicsRoutes as c, AcademicYearListComponent as d, CideLytAcademicYearMappingService as e, CideLytClassProgramBranchListComponent as f, CideLytClassProgramBranchFormComponent as g };
2802
+ //# sourceMappingURL=cloud-ide-academics-cloud-ide-academics-BP1hZ-yx.mjs.map