cloud-ide-admin 1.0.2 → 1.0.4

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.
@@ -1,14 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, Component, inject, signal, ViewChild } from '@angular/core';
2
+ import { Injectable, Component } from '@angular/core';
3
3
  import { CideLytSharedWrapperComponent } from 'cloud-ide-layout';
4
- import * as i1 from '@angular/forms';
5
- import { FormBuilder, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
6
- import { ActivatedRoute, Router } from '@angular/router';
7
- import { HttpClient } from '@angular/common/http';
8
- import { cidePath, hostManagerRoutesUrl, coreRoutesUrl, generateStringFromObject, userRoutesUrl, generateObjectFromString } from 'cloud-ide-lms-model';
9
- import { CideInputComponent, CideSelectComponent, CideTextareaComponent, CideEleFileInputComponent, CideEleTabComponent, CideEleButtonComponent, CideIconComponent, CideEleDataGridComponent, TooltipDirective } from 'cloud-ide-element';
10
- import { Subject, takeUntil, debounceTime, distinctUntilChanged } from 'rxjs';
11
- import { CommonModule } from '@angular/common';
4
+ import { authGuard } from 'cloud-ide-auth';
12
5
 
13
6
  class CideAdmAdminService {
14
7
  constructor() { }
@@ -45,1807 +38,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
45
38
  ` }]
46
39
  }] });
47
40
 
48
- class CideAdmEntityService {
49
- http = inject(HttpClient);
50
- getEntityTypes() {
51
- return this.http.get('/api/core/entity-types');
52
- }
53
- getCurrencies() {
54
- return this.http.get('/api/core/currencies');
55
- }
56
- getUsers() {
57
- return this.http.get('/api/core/users');
58
- }
59
- getPostalCodes() {
60
- return this.http.get('/api/core/postal-codes');
61
- }
62
- /**
63
- * Save entity data using coreRoutesUrl?.entity endpoint
64
- * @param data - Entity data to save
65
- * @param logoFile - Optional logo file
66
- * @returns Observable of the save response
67
- */
68
- saveUpdateEntity(data) {
69
- const url = cidePath.join([
70
- hostManagerRoutesUrl.cideSuiteHost,
71
- coreRoutesUrl.module,
72
- coreRoutesUrl?.entity
73
- ]);
74
- console.log('🏢 ENTITY SERVICE: Making POST request to:', url);
75
- console.log('🏢 ENTITY SERVICE: Data payload:', data);
76
- return this.http.post(url, data);
77
- }
78
- /**
79
- * Get entity by ID
80
- * @param entityId - ID of the entity to retrieve
81
- * @returns Observable of the entity data
82
- */
83
- getEntityById(entityId) {
84
- const payload = {
85
- syen_id: entityId
86
- };
87
- const query = generateStringFromObject(payload);
88
- const url = cidePath.join([
89
- hostManagerRoutesUrl.cideSuiteHost,
90
- coreRoutesUrl.module,
91
- coreRoutesUrl?.entity,
92
- query
93
- ]);
94
- return this.http.get(url);
95
- }
96
- /**
97
- * Delete entity by ID
98
- * @param entityId - ID of the entity to delete
99
- * @returns Observable of the delete response
100
- */
101
- deleteEntity(entityId) {
102
- const url = cidePath.join([
103
- hostManagerRoutesUrl.cideSuiteHost,
104
- coreRoutesUrl.module,
105
- coreRoutesUrl?.entity,
106
- entityId
107
- ]);
108
- console.log('🏢 ENTITY SERVICE: Making DELETE request to:', url);
109
- return this.http.delete(url);
110
- }
111
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
112
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityService, providedIn: 'root' });
113
- }
114
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityService, decorators: [{
115
- type: Injectable,
116
- args: [{
117
- providedIn: 'root'
118
- }]
119
- }] });
120
-
121
- class GeneralMasterSelectService {
122
- http = inject(HttpClient);
123
- /**
124
- * Get general master data from API
125
- * @param body - MGeneralMaster payload with sygmt_code
126
- * @returns Observable of generalMasterListControllerResponse
127
- */
128
- getGeneralMasterData(body) {
129
- const url = cidePath.join([
130
- hostManagerRoutesUrl.cideSuiteHost,
131
- coreRoutesUrl.module,
132
- coreRoutesUrl?.generalMaster
133
- ]);
134
- console.log('🔍 GENERAL MASTER SERVICE: Making API call to:', url);
135
- console.log('🔍 GENERAL MASTER SERVICE: Payload:', body);
136
- return this.http.post(url, body);
137
- }
138
- /**
139
- * Get general master data by code
140
- * @param code - The general master code
141
- * @returns Observable of generalMasterListControllerResponse
142
- */
143
- getGeneralMasterByCode(code) {
144
- const payload = {
145
- sygmt_code: code
146
- };
147
- return this.getGeneralMasterData(payload);
148
- }
149
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: GeneralMasterSelectService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
150
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: GeneralMasterSelectService, providedIn: 'root' });
151
- }
152
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: GeneralMasterSelectService, decorators: [{
153
- type: Injectable,
154
- args: [{
155
- providedIn: 'root'
156
- }]
157
- }] });
158
-
159
- class PinCodeSelectService {
160
- http = inject(HttpClient);
161
- /**
162
- * Get pin code data from API
163
- * @param body - MPinCodeSelect payload with sypin_pincode
164
- * @returns Observable of pinCodeSelectControllerResponse
165
- */
166
- getPinCodeData(body) {
167
- const url = cidePath.join([
168
- hostManagerRoutesUrl.cideSuiteHost,
169
- coreRoutesUrl.module,
170
- coreRoutesUrl?.pinCode
171
- ]);
172
- console.log('🔍 PIN CODE SERVICE: Making API call to:', url);
173
- console.log('🔍 PIN CODE SERVICE: Payload:', body);
174
- return this.http.post(url, body);
175
- }
176
- /**
177
- * Get pin code data by pincode
178
- * @param pincode - The pin code to search for
179
- * @returns Observable of pinCodeSelectControllerResponse
180
- */
181
- getPinCodeByCode(pincode) {
182
- const payload = {
183
- sypin_pincode: pincode
184
- };
185
- return this.getPinCodeData(payload);
186
- }
187
- /**
188
- * Get all postal codes
189
- * @returns Observable of pinCodeSelectControllerResponse
190
- */
191
- getAllPostalCodes() {
192
- const payload = { sypin_pincode: '440022' };
193
- return this.getPinCodeData(payload);
194
- }
195
- /**
196
- * Search pin codes with partial match
197
- * @param searchTerm - Partial pin code or area name to search
198
- * @returns Observable of pinCodeSelectControllerResponse
199
- */
200
- searchPinCodes(payload) {
201
- return this.getPinCodeData(payload);
202
- }
203
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: PinCodeSelectService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
204
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: PinCodeSelectService, providedIn: 'root' });
205
- }
206
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: PinCodeSelectService, decorators: [{
207
- type: Injectable,
208
- args: [{
209
- providedIn: 'root'
210
- }]
211
- }] });
212
-
213
- class UserSelectService {
214
- http = inject(HttpClient);
215
- /**
216
- * Get user data from API
217
- * @param body - MUserSelect payload
218
- * @returns Observable of userSelectControllerResponse
219
- */
220
- getUserData(body) {
221
- const url = cidePath.join([
222
- hostManagerRoutesUrl.cideSuiteHost,
223
- userRoutesUrl.module,
224
- userRoutesUrl?.user
225
- ]);
226
- console.log('🔍 USER SELECT SERVICE: Making API call to:', url);
227
- console.log('🔍 USER SELECT SERVICE: Payload:', body);
228
- return this.http.post(url, body);
229
- }
230
- /**
231
- * Get all users
232
- * @returns Observable of userSelectControllerResponse
233
- */
234
- getAllUsers() {
235
- const payload = {};
236
- return this.getUserData(payload);
237
- }
238
- /**
239
- * Search users by full name
240
- * @param userFullname - The user full name to search for
241
- * @returns Observable of userSelectControllerResponse
242
- */
243
- searchUsersByFullname(payload) {
244
- return this.getUserData(payload);
245
- }
246
- /**
247
- * Search users with filters
248
- * @param filters - Filter parameters for user search
249
- * @returns Observable of userSelectControllerResponse
250
- */
251
- searchUsers(filters) {
252
- const payload = { ...filters };
253
- return this.getUserData(payload);
254
- }
255
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: UserSelectService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
256
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: UserSelectService, providedIn: 'root' });
257
- }
258
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: UserSelectService, decorators: [{
259
- type: Injectable,
260
- args: [{
261
- providedIn: 'root'
262
- }]
263
- }] });
264
-
265
- class CurrencySelectService {
266
- http = inject(HttpClient);
267
- /**
268
- * Get currency data from API
269
- * @returns Observable of currencyListControllerResponse
270
- */
271
- getAllCurrencies(body) {
272
- const query = generateStringFromObject(body);
273
- const url = cidePath.join([
274
- hostManagerRoutesUrl.cideSuiteHost,
275
- coreRoutesUrl.module,
276
- coreRoutesUrl?.currency,
277
- query
278
- ]);
279
- console.log('🔍 CURRENCY SERVICE: Making API call to:', url);
280
- return this.http.get(url);
281
- }
282
- /**
283
- * Search currencies with filters
284
- * @param filters - MSycrList payload for filtering
285
- * @returns Observable of currencyListControllerResponse
286
- */
287
- searchCurrencies(filters) {
288
- const url = cidePath.join([
289
- hostManagerRoutesUrl.cideSuiteHost,
290
- coreRoutesUrl.module,
291
- coreRoutesUrl?.currency
292
- ]);
293
- console.log('🔍 CURRENCY SERVICE: Making search API call to:', url);
294
- console.log('🔍 CURRENCY SERVICE: Filters:', filters);
295
- return this.http.post(url, filters);
296
- }
297
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CurrencySelectService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
298
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CurrencySelectService, providedIn: 'root' });
299
- }
300
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CurrencySelectService, decorators: [{
301
- type: Injectable,
302
- args: [{
303
- providedIn: 'root'
304
- }]
305
- }] });
306
-
307
- class CountrySelectService {
308
- http = inject(HttpClient);
309
- /**
310
- * Get country data from API
311
- * @returns Observable of country response
312
- */
313
- getAllCountries(body) {
314
- const query = generateStringFromObject(body);
315
- const url = cidePath.join([
316
- hostManagerRoutesUrl.cideSuiteHost,
317
- coreRoutesUrl.module,
318
- coreRoutesUrl.country,
319
- query
320
- ]);
321
- console.log('🔍 COUNTRY SERVICE: Making API call to:', url);
322
- return this.http.get(url);
323
- }
324
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CountrySelectService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
325
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CountrySelectService, providedIn: 'root' });
326
- }
327
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CountrySelectService, decorators: [{
328
- type: Injectable,
329
- args: [{
330
- providedIn: 'root'
331
- }]
332
- }] });
333
-
334
- class CideAdmEntityComponent {
335
- // Reactive form
336
- entityForm;
337
- entityTypes = signal([], ...(ngDevMode ? [{ debugName: "entityTypes" }] : []));
338
- currencies = signal([], ...(ngDevMode ? [{ debugName: "currencies" }] : []));
339
- users = signal([], ...(ngDevMode ? [{ debugName: "users" }] : []));
340
- postalCodes = signal([], ...(ngDevMode ? [{ debugName: "postalCodes" }] : []));
341
- photoIdDocuments = signal([], ...(ngDevMode ? [{ debugName: "photoIdDocuments" }] : []));
342
- countries = signal([], ...(ngDevMode ? [{ debugName: "countries" }] : []));
343
- // Store the full pin code data for auto-population
344
- pinCodeDataMap = new Map();
345
- // Store logo file for upload
346
- logoFile;
347
- loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
348
- error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
349
- success = signal(null, ...(ngDevMode ? [{ debugName: "success" }] : []));
350
- // Loading states for individual dropdowns
351
- postalCodesLoading = signal(false, ...(ngDevMode ? [{ debugName: "postalCodesLoading" }] : []));
352
- usersLoading = signal(false, ...(ngDevMode ? [{ debugName: "usersLoading" }] : []));
353
- countriesLoading = signal(false, ...(ngDevMode ? [{ debugName: "countriesLoading" }] : []));
354
- // Entity mode and ID
355
- isEditMode = signal(false, ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
356
- entityId = signal(null, ...(ngDevMode ? [{ debugName: "entityId" }] : []));
357
- // Tab configuration
358
- activeTab = signal('basic', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
359
- entityTabs = signal([
360
- { id: 'basic', label: 'Basic Information', icon: 'ℹ️' },
361
- { id: 'corporate', label: 'Corporate Address', icon: '🏢' },
362
- { id: 'contact', label: 'Contact Information', icon: '📧' },
363
- { id: 'registered', label: 'Registered Address', icon: '🏠' },
364
- { id: 'documents', label: 'Documents & Media', icon: '📄' }
365
- ], ...(ngDevMode ? [{ debugName: "entityTabs" }] : []));
366
- // Modern dependency injection using inject()
367
- entityService = inject(CideAdmEntityService);
368
- generalMasterService = inject(GeneralMasterSelectService);
369
- pinCodeService = inject(PinCodeSelectService);
370
- userService = inject(UserSelectService);
371
- currencyService = inject(CurrencySelectService);
372
- countryService = inject(CountrySelectService);
373
- fb = inject(FormBuilder);
374
- route = inject(ActivatedRoute);
375
- destroy$ = new Subject();
376
- globalErrorHandler;
377
- globalRejectionHandler;
378
- constructor() {
379
- this.entityForm = this.fb.group({
380
- // Basic Information
381
- syen_name: ['', [Validators.required]],
382
- syen_entity_code: ['', [Validators.required, Validators.maxLength(40)]],
383
- syen_entity_type_gmst: ['', [Validators.required]],
384
- syen_udise_no: [''],
385
- syen_affiliation_no: [''],
386
- syen_isactive: [true],
387
- // Corporate Address
388
- syen_corporate_address: [''],
389
- syen_corporate_city_sypin: [''],
390
- syen_corporate_state_sypin: [''],
391
- syen_corporate_country_syctr: [''],
392
- syen_corporate_pin_sypin: [''],
393
- // Contact Information
394
- syen_corporate_contact_person_user: [''],
395
- syen_corporate_phone: [''],
396
- syen_corporate_phone_alt: [''],
397
- syen_corporate_fax: [''],
398
- syen_corporate_email: ['', [Validators.email]],
399
- syen_corporate_email_alt: ['', [Validators.email]],
400
- syen_website: ['', [Validators.pattern(/^https?:\/\/.+/)]],
401
- syen_currency_sycr: [''],
402
- // Registered Address
403
- syen_registered_address: [''],
404
- syen_registered_city_sypin: [''],
405
- syen_registered_state_sypin: [''],
406
- syen_registered_country_syctr: [''],
407
- syen_registered_pin_sypin: [''],
408
- syen_registered_contact_person_user: [''],
409
- syen_registered_phone: [''],
410
- syen_registered_email: ['', [Validators.email]],
411
- syen_registered_fax: [''],
412
- // Documents
413
- syen_photo_id_cyfm: ['']
414
- });
415
- // Listen for postal code changes to auto-populate address fields
416
- this.setupPostalCodeListeners();
417
- }
418
- ngOnInit() {
419
- // Add global error handler to catch any unhandled errors
420
- const errorHandler = (event) => {
421
- console.error('💥 GLOBAL ERROR:', event.error);
422
- };
423
- const rejectionHandler = (event) => {
424
- console.error('💥 UNHANDLED PROMISE REJECTION:', event.reason);
425
- };
426
- window.addEventListener('error', errorHandler);
427
- window.addEventListener('unhandledrejection', rejectionHandler);
428
- // Store handlers for cleanup
429
- this.globalErrorHandler = errorHandler;
430
- this.globalRejectionHandler = rejectionHandler;
431
- // Check for entity ID in query parameters
432
- this.checkForEntityId();
433
- this.loadDropdowns();
434
- }
435
- ngOnDestroy() {
436
- // Clean up global event listeners
437
- if (this.globalErrorHandler) {
438
- window.removeEventListener('error', this.globalErrorHandler);
439
- }
440
- if (this.globalRejectionHandler) {
441
- window.removeEventListener('unhandledrejection', this.globalRejectionHandler);
442
- }
443
- // Clean up RxJS subscriptions
444
- this.destroy$.next();
445
- this.destroy$.complete();
446
- }
447
- // Check for entity ID in query parameters
448
- checkForEntityId() {
449
- console.log('🔍 Checking for entity ID in query parameters', this.route.params);
450
- this.route.params.pipe(takeUntil(this.destroy$)).subscribe(params => {
451
- console.log('🔍 Query params:', params);
452
- // Check for entityId, id, or entity parameter
453
- const queryParams = params['query'];
454
- const queryData = generateObjectFromString(queryParams);
455
- // If entityId is an object string (from generateStringFromObject), try to parse it
456
- const entityId = queryData.syen_id;
457
- if (entityId) {
458
- console.log('🔍 Entity ID found in query params:', entityId);
459
- this.entityId.set(entityId);
460
- this.isEditMode.set(true);
461
- this.loadEntityData(entityId);
462
- }
463
- else {
464
- console.log('🆕 No entity ID found - creating new entity');
465
- this.isEditMode.set(false);
466
- this.entityId.set(null);
467
- }
468
- });
469
- }
470
- // Load entity data for editing
471
- loadEntityData(entityId) {
472
- this.loading.set(true);
473
- this.error.set(null);
474
- console.log('📥 Loading entity data for ID:', entityId);
475
- this.entityService.getEntityById(entityId).pipe(takeUntil(this.destroy$)).subscribe({
476
- next: (response) => {
477
- console.log('✅ Entity data loaded:', response);
478
- if (response?.success && response?.data) {
479
- // Handle both array and single object responses
480
- const entityData = Array.isArray(response.data) ? response.data[0] : response.data;
481
- if (entityData) {
482
- this.populateFormWithEntityData(entityData);
483
- this.success.set('Entity data loaded successfully');
484
- }
485
- else {
486
- this.error.set('Entity data not found');
487
- console.error('❌ Entity data not found in response:', response);
488
- }
489
- }
490
- else {
491
- this.error.set('Failed to load entity data');
492
- console.error('❌ Entity data response invalid:', response);
493
- }
494
- this.loading.set(false);
495
- },
496
- error: (err) => {
497
- console.error('❌ Failed to load entity data:', err);
498
- let errorMessage = 'Failed to load entity data.';
499
- if (err?.error?.message) {
500
- errorMessage = err.error.message;
501
- }
502
- else if (err?.message) {
503
- errorMessage = err.message;
504
- }
505
- else if (err?.status === 404) {
506
- errorMessage = 'Entity not found.';
507
- }
508
- else if (err?.status === 500) {
509
- errorMessage = 'Server error. Please try again later.';
510
- }
511
- this.error.set(errorMessage);
512
- this.loading.set(false);
513
- }
514
- });
515
- }
516
- // Populate form with entity data
517
- populateFormWithEntityData(entityData) {
518
- try {
519
- console.log('📝 Populating form with entity data:', entityData);
520
- // Map the entity data to form controls - only use properties that exist in entityResponseData
521
- const formData = {
522
- // Basic Information
523
- syen_name: entityData.syen_name || '',
524
- syen_entity_code: entityData.syen_entity_code || '',
525
- syen_entity_type_gmst: entityData.syen_entity_type_gmst || '',
526
- syen_isactive: entityData.syen_isactive !== undefined ? entityData.syen_isactive : true,
527
- // Contact Information (only properties that exist in entityResponseData)
528
- syen_corporate_contact_person_user: entityData.syen_corporate_contact_person_user || '',
529
- syen_corporate_phone: entityData.syen_corporate_phone || '',
530
- syen_corporate_email: entityData.syen_corporate_email || '',
531
- // Set default values for other fields since they're not in entityResponseData
532
- syen_udise_no: entityData.syen_udise_no || '',
533
- syen_affiliation_no: entityData.syen_affiliation_no || '',
534
- syen_corporate_address: entityData.syen_corporate_address || '',
535
- syen_corporate_city_sypin: entityData.syen_corporate_city_sypin || '',
536
- syen_corporate_state_sypin: entityData.syen_corporate_state_sypin || '',
537
- syen_corporate_country_syctr: entityData.syen_corporate_country_syctr || '',
538
- syen_corporate_pin_sypin: entityData.syen_corporate_pin_sypin || '',
539
- syen_corporate_phone_alt: entityData.syen_corporate_phone_alt || '',
540
- syen_corporate_fax: entityData.syen_corporate_fax || '',
541
- syen_corporate_email_alt: entityData.syen_corporate_email_alt || '',
542
- syen_website: entityData.syen_website || '',
543
- syen_currency_sycr: entityData.syen_currency_sycr || '',
544
- syen_registered_address: entityData.syen_registered_address || '',
545
- syen_registered_city_sypin: entityData.syen_registered_city_sypin || '',
546
- syen_registered_state_sypin: entityData.syen_registered_state_sypin || '',
547
- syen_registered_country_syctr: entityData.syen_registered_country_syctr || '',
548
- syen_registered_pin_sypin: entityData.syen_registered_pin_sypin || '',
549
- syen_registered_contact_person_user: entityData.syen_registered_contact_person_user || '',
550
- syen_registered_phone: entityData.syen_registered_phone || '',
551
- syen_registered_email: entityData.syen_registered_email || '',
552
- syen_registered_fax: entityData.syen_registered_fax || '',
553
- syen_photo_id_cyfm: entityData.syen_photo_id_cyfm || ''
554
- };
555
- // Patch the form with the entity data
556
- this.entityForm.patchValue(formData, { emitEvent: false });
557
- console.log('✅ Form populated successfully');
558
- }
559
- catch (error) {
560
- console.error('💥 Error populating form with entity data:', error);
561
- this.error.set('Error loading entity data into form');
562
- }
563
- }
564
- // Setup listeners for postal code changes
565
- setupPostalCodeListeners() {
566
- // Corporate postal code listener
567
- this.entityForm.get('syen_corporate_pin_sypin')?.valueChanges.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.destroy$)).subscribe(pinCodeId => {
568
- if (pinCodeId) {
569
- this.populateAddressFromPinCode(pinCodeId, 'corporate');
570
- }
571
- });
572
- // Registered postal code listener
573
- this.entityForm.get('syen_registered_pin_sypin')?.valueChanges.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.destroy$)).subscribe(pinCodeId => {
574
- if (pinCodeId) {
575
- this.populateAddressFromPinCode(pinCodeId, 'registered');
576
- }
577
- });
578
- }
579
- // Auto-populate address fields based on selected postal code
580
- populateAddressFromPinCode(pinCodeId, addressType) {
581
- const pinCodeData = this.pinCodeDataMap.get(pinCodeId);
582
- console.log('🔍 Pin Code Data:', pinCodeData);
583
- if (!pinCodeData) {
584
- console.warn(`Pin code data not found for ID: ${pinCodeId}`);
585
- return;
586
- }
587
- const prefix = addressType === 'corporate' ? 'syen_corporate' : 'syen_registered';
588
- // Populate city, state, and country fields
589
- this.entityForm.patchValue({
590
- [`${prefix}_city_sypin`]: pinCodeData.sypin_district || '',
591
- [`${prefix}_state_sypin`]: pinCodeData.sypin_state_name || '',
592
- [`${prefix}_country_syctr`]: pinCodeData.sypin_country_id_syctr || ''
593
- }, { emitEvent: false });
594
- console.log(`📍 Auto-populated ${addressType} address from pin code:`, {
595
- city: pinCodeData.sypin_district,
596
- state: pinCodeData.sypin_state_name,
597
- country: pinCodeData.sypin_country_id_syctr
598
- });
599
- }
600
- loadDropdowns() {
601
- try {
602
- console.log('🚀 Loading dropdowns...');
603
- // Load entity types via general master service
604
- this.generalMasterService.getGeneralMasterByCode('core_entity_type').subscribe({
605
- next: (response) => {
606
- try {
607
- console.log('✅ Entity types response:', response);
608
- const types = this.transformGeneralMasterToDropdown(response);
609
- this.entityTypes.set(types);
610
- console.log('📋 Loaded entity types:', types.length);
611
- }
612
- catch (error) {
613
- console.error('💥 Entity types transform error:', error);
614
- this.entityTypes.set([]);
615
- }
616
- },
617
- error: (err) => {
618
- console.error('❌ Failed to load entity types:', err);
619
- this.entityTypes.set([]);
620
- }
621
- });
622
- // Load currencies via currency service
623
- this.currencyService.getAllCurrencies({}).subscribe({
624
- next: (response) => {
625
- try {
626
- console.log('✅ Currencies response:', response);
627
- const currencies = this.transformCurrencyToDropdown(response);
628
- this.currencies.set(currencies);
629
- console.log('💰 Loaded currencies:', currencies.length);
630
- }
631
- catch (error) {
632
- console.error('💥 Currencies transform error:', error);
633
- this.currencies.set([]);
634
- }
635
- },
636
- error: (err) => {
637
- console.error('❌ Failed to load currencies:', err);
638
- this.currencies.set([]);
639
- }
640
- });
641
- // Load users via user service
642
- this.userService.getAllUsers().subscribe({
643
- next: (response) => {
644
- try {
645
- console.log('✅ Users response:', response);
646
- const users = this.transformUserToDropdown(response);
647
- this.users.set(users);
648
- console.log('👥 Loaded users:', users.length);
649
- }
650
- catch (error) {
651
- console.error('💥 Users transform error:', error);
652
- this.users.set([]);
653
- }
654
- },
655
- error: (err) => {
656
- console.error('❌ Failed to load users:', err);
657
- this.users.set([]);
658
- }
659
- });
660
- // Load postal codes via pin code service
661
- this.pinCodeService.getAllPostalCodes().subscribe({
662
- next: (response) => {
663
- try {
664
- console.log('✅ Postal codes response:', response);
665
- const postalCodes = this.transformPinCodeToDropdown(response);
666
- this.postalCodes.set(postalCodes);
667
- console.log('📮 Loaded postal codes:', postalCodes.length);
668
- }
669
- catch (error) {
670
- console.error('💥 Postal codes transform error:', error);
671
- this.postalCodes.set([]);
672
- }
673
- },
674
- error: (err) => {
675
- console.error('❌ Failed to load postal codes:', err);
676
- this.postalCodes.set([]);
677
- }
678
- });
679
- // Load photo ID documents via general master service
680
- this.generalMasterService.getGeneralMasterByCode('core_photo_id_document').subscribe({
681
- next: (response) => {
682
- try {
683
- console.log('✅ Photo ID documents response:', response);
684
- const documents = this.transformGeneralMasterToDropdown(response);
685
- this.photoIdDocuments.set(documents);
686
- console.log('📄 Loaded photo ID documents:', documents.length);
687
- }
688
- catch (error) {
689
- console.error('💥 Photo ID documents transform error:', error);
690
- this.photoIdDocuments.set([]);
691
- }
692
- },
693
- error: (err) => {
694
- console.error('❌ Failed to load photo ID documents:', err);
695
- // Fallback to static data
696
- this.photoIdDocuments.set([
697
- { value: 'passport', label: 'Passport' },
698
- { value: 'license', label: 'Driver License' },
699
- { value: 'national_id', label: 'National ID' },
700
- { value: 'voter_id', label: 'Voter ID' },
701
- { value: 'other', label: 'Other' }
702
- ]);
703
- }
704
- });
705
- // Load countries via country service
706
- this.countryService.getAllCountries({}).subscribe({
707
- next: (response) => {
708
- try {
709
- console.log('✅ Countries response:', response);
710
- const countries = this.transformCountryToDropdown(response);
711
- this.countries.set(countries);
712
- console.log('🌍 Loaded countries:', countries.length);
713
- }
714
- catch (error) {
715
- console.error('💥 Countries transform error:', error);
716
- this.countries.set([]);
717
- }
718
- },
719
- error: (err) => {
720
- console.error('❌ Failed to load countries:', err);
721
- this.countries.set([]);
722
- }
723
- });
724
- }
725
- catch (error) {
726
- console.error('💥 LOADDROPDOWNS EXCEPTION:', error);
727
- }
728
- }
729
- // Helper method to transform general master response to dropdown options
730
- transformGeneralMasterToDropdown(response) {
731
- if (!response?.success || !response?.data) {
732
- return [];
733
- }
734
- let dataArray = [];
735
- // Handle different response structures - all general master data is in core_general_master
736
- if (Array.isArray(response.data)) {
737
- dataArray = response.data;
738
- }
739
- return dataArray.map((item, index) => {
740
- return {
741
- // API response already includes value and label fields
742
- value: item.value || item._id || `value_${index}`,
743
- label: item.label || item.sygms_title || 'Untitled'
744
- };
745
- });
746
- }
747
- // Helper method to transform currency response to dropdown options
748
- transformCurrencyToDropdown(response) {
749
- if (!response?.success || !response?.data) {
750
- return [];
751
- }
752
- console.log('🔍 Currency Response:', response);
753
- // Handle different response structures
754
- let dataArray = [];
755
- if (Array.isArray(response.data)) {
756
- dataArray = response.data;
757
- }
758
- return dataArray.map((item) => {
759
- return {
760
- value: item._id,
761
- label: `${item.sycr_code} - ${item.sycr_name} (${item.sycr_symbol})`
762
- };
763
- });
764
- }
765
- // Helper method to transform user response to dropdown options
766
- transformUserToDropdown(response) {
767
- if (!response?.success || !response?.data) {
768
- return [];
769
- }
770
- let dataArray = [];
771
- // Handle different response structures
772
- if (response.data.auth_user_mst) {
773
- dataArray = response.data.auth_user_mst;
774
- }
775
- else if (Array.isArray(response.data)) {
776
- dataArray = response.data;
777
- }
778
- return dataArray.map((item) => {
779
- return {
780
- value: item._id || "",
781
- label: item?.user_fullname || ""
782
- };
783
- });
784
- }
785
- // Helper method to transform pin code response to dropdown options
786
- transformPinCodeToDropdown(response) {
787
- if (!response?.success || !response?.data) {
788
- return [];
789
- }
790
- let dataArray = [];
791
- // Handle different response structures
792
- if ('core_pin_code' in response.data && response.data.core_pin_code) {
793
- dataArray = response.data.core_pin_code;
794
- }
795
- // Clear the data map and rebuild it
796
- this.pinCodeDataMap.clear();
797
- return dataArray.map((item) => {
798
- const pinCodeId = String(item._id);
799
- // Store the full pin code data for auto-population
800
- this.pinCodeDataMap.set(pinCodeId, item);
801
- // API response already includes value and label fields
802
- return {
803
- value: pinCodeId,
804
- label: `${item.sypin_pincode} - ${item.sypin_office_name || 'Unknown Office'}`
805
- };
806
- });
807
- }
808
- // Helper method to transform country response to dropdown options
809
- transformCountryToDropdown(response) {
810
- try {
811
- if (!response?.success || !response?.data) {
812
- console.warn('⚠️ Country response missing success or data:', response);
813
- return [];
814
- }
815
- console.log('🔍 Country Response:', response);
816
- let dataArray = [];
817
- // Handle different response structures
818
- if (Array.isArray(response.data)) {
819
- dataArray = response.data;
820
- }
821
- else if (response.data) {
822
- dataArray = response.data;
823
- }
824
- console.log('🔍 Country data array length:', dataArray.length);
825
- return dataArray.map((item) => {
826
- return {
827
- value: item._id || "",
828
- label: `${item.syctr_country_iso_name || 'Unknown'} (${item.syctr_country_iso_code_two_char || 'XX'})`
829
- };
830
- });
831
- }
832
- catch (error) {
833
- console.error('💥 COUNTRY TRANSFORM EXCEPTION:', error);
834
- return [];
835
- }
836
- }
837
- // Helper method to get form control
838
- getControl(controlName) {
839
- return this.entityForm.get(controlName);
840
- }
841
- // Handle postal code search with debouncing
842
- onPostalCodeSearch(event) {
843
- try {
844
- console.log('🔍 POSTAL CODE SEARCH EVENT:', event);
845
- // Set loading state
846
- this.postalCodesLoading.set(true);
847
- const payload = {
848
- sypin_pincode: event.query || "",
849
- sypin_id: event.value || ""
850
- };
851
- console.log('🔍 POSTAL CODE PAYLOAD:', payload);
852
- this.pinCodeService.searchPinCodes(payload).pipe(takeUntil(this.destroy$)).subscribe({
853
- next: (response) => {
854
- console.log('✅ POSTAL CODE SEARCH SUCCESS:', response);
855
- const postalCodes = this.transformPinCodeToDropdown(response);
856
- this.postalCodes.set(postalCodes);
857
- console.log('📮 Updated postal codes count:', postalCodes.length);
858
- },
859
- error: (err) => {
860
- console.error('❌ POSTAL CODE SEARCH ERROR:', err);
861
- this.postalCodes.set([]);
862
- },
863
- complete: () => {
864
- // Clear loading state
865
- this.postalCodesLoading.set(false);
866
- }
867
- });
868
- }
869
- catch (error) {
870
- console.error('💥 POSTAL CODE SEARCH EXCEPTION:', error);
871
- this.postalCodes.set([]);
872
- this.postalCodesLoading.set(false);
873
- }
874
- }
875
- // Handle user search
876
- onUserSearch(event) {
877
- try {
878
- console.log('🔍 USER SEARCH EVENT:', event);
879
- // Set loading state
880
- this.usersLoading.set(true);
881
- const payload = {
882
- user_fullname: event?.query || "",
883
- user_id: event?.value || "",
884
- };
885
- console.log('🔍 USER SEARCH PAYLOAD:', payload);
886
- this.userService.searchUsersByFullname(payload).subscribe({
887
- next: (response) => {
888
- console.log('✅ USER SEARCH SUCCESS:', response);
889
- const users = this.transformUserToDropdown(response);
890
- this.users.set(users);
891
- console.log('👥 Updated users count:', users.length);
892
- },
893
- error: (err) => {
894
- console.error('❌ USER SEARCH ERROR:', err);
895
- this.users.set([]);
896
- },
897
- complete: () => {
898
- // Clear loading state
899
- this.usersLoading.set(false);
900
- }
901
- });
902
- }
903
- catch (error) {
904
- console.error('💥 USER SEARCH EXCEPTION:', error);
905
- this.users.set([]);
906
- this.usersLoading.set(false);
907
- }
908
- }
909
- // Handle country search
910
- onCountrySearch(event) {
911
- try {
912
- console.log('🔍 COUNTRY SEARCH EVENT:', event);
913
- // Set loading state
914
- this.countriesLoading.set(true);
915
- const payload = {
916
- query: event.query,
917
- syctr_id: event.value,
918
- };
919
- console.log('🔍 COUNTRY SEARCH PAYLOAD:', payload);
920
- this.countryService.getAllCountries(payload).subscribe({
921
- next: (response) => {
922
- console.log('✅ COUNTRY SEARCH SUCCESS:', response);
923
- const countries = this.transformCountryToDropdown(response);
924
- this.countries.set(countries);
925
- console.log('🌍 Updated countries count:', countries.length);
926
- },
927
- error: (err) => {
928
- console.error('❌ COUNTRY SEARCH ERROR:', err);
929
- this.countries.set([]);
930
- },
931
- complete: () => {
932
- // Clear loading state
933
- this.countriesLoading.set(false);
934
- }
935
- });
936
- }
937
- catch (error) {
938
- console.error('💥 COUNTRY SEARCH EXCEPTION:', error);
939
- this.countries.set([]);
940
- this.countriesLoading.set(false);
941
- }
942
- }
943
- // Handle postal code selection
944
- onPostalCodeSelection(event) {
945
- let pinCodeId = '';
946
- if (typeof event === 'string') {
947
- pinCodeId = event;
948
- }
949
- else {
950
- const target = event.target;
951
- pinCodeId = target?.value || '';
952
- }
953
- console.log('📍 Postal Code Selected:', pinCodeId);
954
- // The auto-population is handled by the form value change listeners
955
- // This method can be used for additional logic if needed
956
- }
957
- // Check if a field has an error
958
- hasError(controlName, errorType) {
959
- const control = this.getControl(controlName);
960
- if (!control)
961
- return false;
962
- if (errorType) {
963
- return control.hasError(errorType) && (control.dirty || control.touched);
964
- }
965
- return control.invalid && (control.dirty || control.touched);
966
- }
967
- // Get error message for a field
968
- getErrorMessage(controlName) {
969
- const control = this.getControl(controlName);
970
- if (!control || !control.errors)
971
- return '';
972
- const fieldName = controlName.replace('syen_', '').replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
973
- if (control.hasError('required')) {
974
- return `${fieldName} is required`;
975
- }
976
- if (control.hasError('maxlength')) {
977
- return `Maximum length is ${control.errors['maxlength'].requiredLength} characters`;
978
- }
979
- if (control.hasError('email')) {
980
- return 'Please enter a valid email address';
981
- }
982
- if (control.hasError('pattern')) {
983
- return 'Please enter a valid URL starting with http:// or https://';
984
- }
985
- return 'Invalid input';
986
- }
987
- // Get form validation summary
988
- getFormValidationSummary() {
989
- const errors = [];
990
- Object.keys(this.entityForm.controls).forEach(key => {
991
- const control = this.entityForm.get(key);
992
- if (control && control.invalid && (control.dirty || control.touched)) {
993
- errors.push(this.getErrorMessage(key));
994
- }
995
- });
996
- return errors;
997
- }
998
- // Check if form is valid
999
- get isFormValid() {
1000
- return this.entityForm.valid;
1001
- }
1002
- // Get current mode for display
1003
- get currentMode() {
1004
- return this.isEditMode() ? 'Edit' : 'Create';
1005
- }
1006
- // Get current entity ID for display
1007
- get currentEntityId() {
1008
- return this.entityId();
1009
- }
1010
- onFileChange(event) {
1011
- if (event && event.length > 0) {
1012
- this.logoFile = event[0];
1013
- console.log('�� Logo File Selected:', this.logoFile.name);
1014
- }
1015
- else {
1016
- this.logoFile = undefined;
1017
- console.log('📄 No logo file selected.');
1018
- }
1019
- }
1020
- onTabChange(tab) {
1021
- this.activeTab.set(tab.id);
1022
- }
1023
- onSubmit() {
1024
- if (this.entityForm.valid) {
1025
- this.loading.set(true);
1026
- this.error.set(null);
1027
- this.success.set(null);
1028
- const formData = this.entityForm.value;
1029
- const isEdit = this.isEditMode();
1030
- const entityId = this.entityId();
1031
- console.log(`🏢 ENTITY ${isEdit ? 'UPDATE' : 'CREATE'}: Form data:`, formData);
1032
- // Validate required fields before submission
1033
- const requiredFields = ['syen_name', 'syen_entity_code', 'syen_entity_type_gmst'];
1034
- const missingFields = requiredFields.filter(field => !formData[field]);
1035
- if (missingFields.length > 0) {
1036
- this.error.set(`Missing required fields: ${missingFields.join(', ')}`);
1037
- this.loading.set(false);
1038
- return;
1039
- }
1040
- // Add entity ID to form data if in edit mode
1041
- if (isEdit && entityId) {
1042
- formData._id = entityId;
1043
- }
1044
- const saveOperation = this.entityService.saveUpdateEntity(formData);
1045
- saveOperation.pipe(takeUntil(this.destroy$))
1046
- .subscribe({
1047
- next: (response) => {
1048
- console.log(`✅ ENTITY ${isEdit ? 'UPDATE' : 'CREATE'} SUCCESS:`, response);
1049
- if (response?.success) {
1050
- const successMessage = isEdit
1051
- ? 'Entity updated successfully!'
1052
- : 'Entity created successfully!';
1053
- this.success.set(successMessage);
1054
- // Update the entity ID if it's a new entity
1055
- if (!isEdit && response?.data) {
1056
- const entityData = Array.isArray(response.data) ? response.data[0] : response.data;
1057
- if (entityData?._id) {
1058
- this.entityId.set(entityData._id);
1059
- this.isEditMode.set(true);
1060
- }
1061
- }
1062
- // Optionally redirect to list or stay on form
1063
- // this.router.navigate(['/admin/entities']);
1064
- }
1065
- else {
1066
- this.error.set(response?.message || `Failed to ${isEdit ? 'update' : 'create'} entity. Please try again.`);
1067
- }
1068
- this.loading.set(false);
1069
- },
1070
- error: (err) => {
1071
- console.error(`❌ ENTITY ${isEdit ? 'UPDATE' : 'CREATE'} ERROR:`, err);
1072
- let errorMessage = `Failed to ${isEdit ? 'update' : 'save'} entity settings.`;
1073
- if (err?.error?.message) {
1074
- errorMessage = err.error.message;
1075
- }
1076
- else if (err?.message) {
1077
- errorMessage = err.message;
1078
- }
1079
- else if (err?.status === 400) {
1080
- errorMessage = 'Invalid data provided. Please check your input.';
1081
- }
1082
- else if (err?.status === 404 && isEdit) {
1083
- errorMessage = 'Entity not found. It may have been deleted.';
1084
- }
1085
- else if (err?.status === 409) {
1086
- errorMessage = 'Entity with this code already exists. Please use a different code.';
1087
- }
1088
- else if (err?.status === 500) {
1089
- errorMessage = 'Server error. Please try again later.';
1090
- }
1091
- this.error.set(errorMessage);
1092
- this.loading.set(false);
1093
- }
1094
- });
1095
- }
1096
- else {
1097
- // Mark all fields as touched to show validation errors
1098
- this.entityForm.markAllAsTouched();
1099
- const validationErrors = this.getFormValidationSummary();
1100
- console.warn('⚠️ FORM VALIDATION ERRORS:', validationErrors);
1101
- this.error.set(`Please fix the following errors: ${validationErrors.join(', ')}`);
1102
- }
1103
- }
1104
- onReset() {
1105
- // Clear logo file
1106
- this.logoFile = undefined;
1107
- // Reset form to initial values
1108
- this.entityForm.reset({
1109
- syen_name: '',
1110
- syen_entity_type_gmst: '',
1111
- syen_entity_code: '',
1112
- syen_udise_no: '',
1113
- syen_affiliation_no: '',
1114
- syen_isactive: true,
1115
- syen_corporate_address: '',
1116
- syen_corporate_pin_sypin: '',
1117
- syen_corporate_city_sypin: '',
1118
- syen_corporate_state_sypin: '',
1119
- syen_corporate_country_syctr: '',
1120
- syen_corporate_contact_person_user: '',
1121
- syen_corporate_phone: '',
1122
- syen_corporate_phone_alt: '',
1123
- syen_corporate_fax: '',
1124
- syen_corporate_email: '',
1125
- syen_corporate_email_alt: '',
1126
- syen_website: '',
1127
- syen_currency_sycr: '',
1128
- syen_registered_address: '',
1129
- syen_registered_pin_sypin: '',
1130
- syen_registered_city_sypin: '',
1131
- syen_registered_state_sypin: '',
1132
- syen_registered_country_syctr: '',
1133
- syen_registered_contact_person_user: '',
1134
- syen_registered_phone: '',
1135
- syen_registered_fax: '',
1136
- syen_registered_email: '',
1137
- syen_photo_id_cyfm: ''
1138
- });
1139
- this.success.set(null);
1140
- this.error.set(null);
1141
- console.log('🔄 Form reset completed');
1142
- }
1143
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1144
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideAdmEntityComponent, isStandalone: true, selector: "cide-adm-entity", ngImport: i0, template: "<!-- \n DYNAMIC GRID SYSTEM FEATURES:\n \n Basic Grids: grid-1, grid-2, grid-3, grid-4, grid-5, grid-6\n \n Auto-fit Grids: grid-auto-fit-sm/md/lg/xl (dynamic columns based on content)\n Auto-fill Grids: grid-auto-fill-sm/md/lg (always fill available space)\n \n Custom Ratios: grid-ratio-1-2, grid-ratio-2-1, grid-ratio-1-3, grid-ratio-3-1, etc.\n Fractional: grid-quarter-three, grid-third-two, grid-half-half\n \n Gap Control: gap-xs, gap-sm, gap-md, gap-lg, gap-xl\n Specific Gaps: row-gap-xs/sm/md/lg, col-gap-xs/sm/md/lg\n \n Alignment: align-start/center/end/stretch, justify-start/center/end/stretch\n \n Responsive: xl-grid-*, lg-grid-*, md-grid-*, sm-grid-*, xs-grid-*\n \n Grid Items: span-1/2/3/4/5/6/full, row-span-*, start-*, end-*\n Item Alignment: self-start/center/end/stretch, justify-self-*\n \n Special: grid-dense (auto-fills gaps), grid-masonry (masonry layout)\n-->\n\n<div class=\"entity-form-container\">\n <form class=\"entity-form\" [formGroup]=\"entityForm\" [class.loading]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n \n <!-- Header Section -->\n <div class=\"form-header\">\n <h2 class=\"form-title\">Create New Entity</h2>\n <p class=\"form-subtitle\">Add a new educational institution to the system</p>\n </div>\n\n <!-- Success and Error Messages -->\n @if (success()) {\n <div class=\"alert alert-success\">\n <svg class=\"alert-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"></path>\n </svg>\n {{ success() }}\n </div>\n }\n @if (error()) {\n <div class=\"alert alert-error\">\n <svg class=\"alert-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n {{ error() }}\n </div>\n }\n\n <!-- Tab Navigation -->\n <div class=\"form-tabs\">\n <cide-ele-tab \n [tabs]=\"entityTabs()\"\n [activeTabId]=\"activeTab()\"\n size=\"md\"\n variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\"\n [class.loading]=\"loading()\">\n @switch (activeTab()) {\n \n @case ('basic') {\n <!-- Basic Information Section -->\n <div class=\"form-section\">\n <div class=\"grid grid-auto-fit-md gap-md lg-grid-2 md-grid-1\">\n <div class=\"grid-item span-2 md-span-full\">\n <cide-ele-input \n id=\"syen_name\" \n type=\"text\"\n label=\"Institution Name\" \n formControlName=\"syen_name\"\n placeholder=\"Enter full institution name\">\n </cide-ele-input>\n </div>\n \n <cide-ele-input \n label=\"Institution Code\" \n formControlName=\"syen_entity_code\"\n id=\"syen_entity_code\"\n placeholder=\"Enter unique code (max 40 characters)\">\n </cide-ele-input>\n </div>\n\n <div class=\"grid grid-ratio-2-1-1 gap-md lg-grid-3 md-grid-2 sm-grid-1\">\n <cide-ele-select \n label=\"Entity Type\" \n [options]=\"entityTypes()\" \n formControlName=\"syen_entity_type_gmst\"\n placeholder=\"Select entity type\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"UDISE Number\" \n formControlName=\"syen_udise_no\"\n placeholder=\"Enter UDISE number\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Affiliation Number\" \n formControlName=\"syen_affiliation_no\"\n placeholder=\"Enter affiliation number\">\n </cide-ele-input>\n </div>\n\n <div class=\"grid grid-1 gap-sm\">\n <div class=\"checkbox-field\">\n <label class=\"checkbox-label\">\n <input \n type=\"checkbox\" \n formControlName=\"syen_isactive\"\n class=\"checkbox-input\" />\n <span class=\"checkbox-text\">Active Status</span>\n <span class=\"checkbox-description\">Enable this entity for system operations</span>\n </label>\n </div>\n </div>\n </div>\n }\n\n @case ('corporate') {\n <!-- Corporate Address Section -->\n <div class=\"form-section\">\n <div class=\"grid grid-1 gap-md\">\n <div class=\"grid-item span-full\">\n <cide-ele-textarea \n label=\"Corporate Address\" \n formControlName=\"syen_corporate_address\"\n placeholder=\"Enter complete corporate address\"\n [rows]=\"3\">\n </cide-ele-textarea>\n </div>\n </div>\n\n <div class=\"grid grid-auto-fit-sm gap-lg xl-grid-4 lg-grid-3 md-grid-2 sm-grid-1 align-end\">\n <cide-ele-select \n label=\"Postal Code\"\n [options]=\"postalCodes()\" \n formControlName=\"syen_corporate_pin_sypin\"\n placeholder=\"Select postal code\"\n [searchable]=\"true\"\n [loading]=\"postalCodesLoading()\"\n (searchChange)=\"onPostalCodeSearch($event)\"\n (selectionChange)=\"onPostalCodeSelection($event)\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"City\" \n formControlName=\"syen_corporate_city_sypin\"\n placeholder=\"Enter city\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"State\" \n formControlName=\"syen_corporate_state_sypin\"\n placeholder=\"Enter state\">\n </cide-ele-input>\n \n <cide-ele-select \n label=\"Country\" \n [options]=\"countries()\" \n formControlName=\"syen_corporate_country_syctr\"\n placeholder=\"Select country\"\n [searchable]=\"true\"\n [loading]=\"countriesLoading()\"\n (searchChange)=\"onCountrySearch($event)\">\n </cide-ele-select>\n </div>\n </div>\n }\n\n @case ('contact') {\n <!-- Contact Information Section -->\n <div class=\"form-section\">\n <div class=\"grid grid-ratio-3-1 gap-lg md-grid-2 sm-grid-1 justify-stretch\">\n <div class=\"grid-item justify-self-stretch\">\n <cide-ele-select \n label=\"Primary Contact Person\"\n [options]=\"users()\" \n formControlName=\"syen_corporate_contact_person_user\"\n placeholder=\"Select contact person\"\n [searchable]=\"true\"\n [loading]=\"usersLoading()\"\n (searchChange)=\"onUserSearch($event)\">\n </cide-ele-select>\n </div>\n \n <div class=\"grid-item justify-self-stretch\">\n <cide-ele-select \n label=\"Currency\" \n [options]=\"currencies()\" \n formControlName=\"syen_currency_sycr\"\n placeholder=\"Select currency\">\n </cide-ele-select>\n </div>\n </div>\n\n <div class=\"grid grid-auto-fill-md gap-md col-gap-lg row-gap-sm xl-grid-3 lg-grid-2 md-grid-1 grid-dense\">\n <cide-ele-input \n label=\"Primary Phone\" \n formControlName=\"syen_corporate_phone\"\n type=\"tel\"\n placeholder=\"Enter phone number\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Alternate Phone\" \n formControlName=\"syen_corporate_phone_alt\"\n type=\"tel\"\n placeholder=\"Enter alternate phone\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Fax Number\" \n formControlName=\"syen_corporate_fax\"\n placeholder=\"Enter fax number\">\n </cide-ele-input>\n </div>\n\n <div class=\"grid grid-ratio-1-2-1 gap-xl lg-grid-3 md-grid-2 sm-grid-1 align-center\">\n <div class=\"grid-item self-stretch\">\n <cide-ele-input \n label=\"Primary Email\" \n formControlName=\"syen_corporate_email\"\n type=\"email\"\n placeholder=\"Enter primary email\">\n </cide-ele-input>\n </div>\n \n <div class=\"grid-item span-2 lg-span-1 self-stretch\">\n <cide-ele-input \n label=\"Website URL\" \n formControlName=\"syen_website\"\n type=\"url\"\n placeholder=\"Enter website URL\">\n </cide-ele-input>\n </div>\n \n <div class=\"grid-item self-stretch\">\n <cide-ele-input \n label=\"Alternate Email\" \n formControlName=\"syen_corporate_email_alt\"\n type=\"email\"\n placeholder=\"Enter alternate email\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n\n @case ('registered') {\n <!-- Registered Address Section -->\n <div class=\"form-section\">\n <div class=\"grid grid-1\">\n <cide-ele-textarea \n label=\"Registered Address\" \n formControlName=\"syen_registered_address\"\n placeholder=\"Enter complete registered address\"\n [rows]=\"3\">\n </cide-ele-textarea>\n </div>\n\n <div class=\"grid grid-4\">\n <cide-ele-select \n label=\"Registered Postal Code\"\n [options]=\"postalCodes()\" \n formControlName=\"syen_registered_pin_sypin\"\n placeholder=\"Select postal code\"\n [searchable]=\"true\"\n [loading]=\"postalCodesLoading()\"\n (searchChange)=\"onPostalCodeSearch($event)\"\n (selectionChange)=\"onPostalCodeSelection($event)\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"Registered City\" \n formControlName=\"syen_registered_city_sypin\"\n placeholder=\"Enter city\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Registered State\" \n formControlName=\"syen_registered_state_sypin\"\n placeholder=\"Enter state\">\n </cide-ele-input>\n \n <cide-ele-select \n label=\"Registered Country\" \n [options]=\"countries()\" \n formControlName=\"syen_registered_country_syctr\"\n placeholder=\"Select country\"\n [searchable]=\"true\"\n [loading]=\"countriesLoading()\"\n (searchChange)=\"onCountrySearch($event)\">\n </cide-ele-select>\n </div>\n\n <div class=\"grid grid-3\">\n <cide-ele-select \n label=\"Registered Contact Person\"\n [options]=\"users()\" \n formControlName=\"syen_registered_contact_person_user\"\n placeholder=\"Select contact person\"\n [searchable]=\"true\"\n [loading]=\"usersLoading()\"\n (searchChange)=\"onUserSearch($event)\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"Registered Phone\" \n formControlName=\"syen_registered_phone\"\n type=\"tel\"\n placeholder=\"Enter phone number\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Registered Email\" \n formControlName=\"syen_registered_email\"\n type=\"email\"\n placeholder=\"Enter email\">\n </cide-ele-input>\n @if (hasError('syen_registered_email')) {\n <div class=\"error-message\">{{ getErrorMessage('syen_registered_email') }}</div>\n }\n </div>\n\n <div class=\"grid grid-1\">\n <cide-ele-input \n label=\"Registered Fax\" \n formControlName=\"syen_registered_fax\"\n placeholder=\"Enter fax number\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n @case ('documents') {\n <!-- Documents Section -->\n <div class=\"form-section\">\n <!-- Photo ID Document -->\n <div class=\"grid grid-1 gap-md\">\n <cide-ele-select \n label=\"Photo ID Document\" \n [options]=\"photoIdDocuments()\" \n formControlName=\"syen_photo_id_cyfm\"\n placeholder=\"Select photo ID document\">\n </cide-ele-select>\n </div>\n\n <!-- Logo Upload -->\n <div class=\"grid grid-quarter-three gap-lg md-grid-1 align-center\">\n <div class=\"grid-item self-center justify-self-center\">\n <!-- Logo preview placeholder -->\n <div style=\"width: 120px; height: 120px; border: 2px dashed #cbd5e1; border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #9ca3af; font-size: 0.875rem; text-align: center;\">\n Logo Preview\n </div>\n </div>\n <div class=\"grid-item self-stretch\">\n <cide-ele-file-input \n label=\"Upload Logo\" \n accept=\"image/*\" \n [multiple]=\"false\" \n (fileChange)=\"onFileChange($event)\"\n placeholder=\"Select institution logo or image\">\n </cide-ele-file-input>\n </div>\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Form Actions -->\n <div class=\"form-actions\">\n <button cideEleButton\n type=\"button\" \n variant=\"secondary\" \n (click)=\"onReset()\" \n leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n \n <button cideEleButton\n type=\"submit\" \n variant=\"primary\" \n [disabled]=\"loading() || entityForm.invalid\"\n [loading]=\"loading()\"\n leftIcon=\"check\">\n Create Entity\n </button>\n </div>\n </form>\n</div> ", styles: [".entity-form-container{background:transparent;padding:1rem;width:100%;box-sizing:border-box}.entity-form{max-width:1200px;margin:0 auto;background:transparent;border:none;box-shadow:none;width:100%}.entity-form.loading{opacity:.6;pointer-events:none}.form-header{background:transparent;color:#1f2937;padding:1.25rem 0;text-align:left}.form-header .form-title{font-size:1.5rem;font-weight:700;margin:0 0 .25rem;color:#1f2937}.form-header .form-subtitle{font-size:.95rem;opacity:.7;margin:0;font-weight:400;color:#6b7280}.form-section{padding:1.25rem 0;border-bottom:none;margin-bottom:1.5rem}.form-section:last-of-type{margin-bottom:0}.form-section .section-title{font-size:1.125rem;font-weight:600;color:#1f2937;margin:0 0 1rem;padding-bottom:.5rem;border-bottom:1px solid #e5e7eb;position:relative}.form-section .section-title:after{content:\"\";position:absolute;bottom:-1px;left:0;width:40px;height:1px;background:#667eea;border-radius:1px}.grid{display:grid;gap:1rem;margin-bottom:.75rem;transition:all .3s ease}.grid:last-child{margin-bottom:0}.grid.grid-1{grid-template-columns:1fr}.grid.grid-2{grid-template-columns:repeat(2,1fr)}.grid.grid-3{grid-template-columns:repeat(3,1fr)}.grid.grid-4{grid-template-columns:repeat(4,1fr)}.grid.grid-5{grid-template-columns:repeat(5,1fr)}.grid.grid-6{grid-template-columns:repeat(6,1fr)}.grid.grid-auto-fit-sm{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}.grid.grid-auto-fit-md{grid-template-columns:repeat(auto-fit,minmax(250px,1fr))}.grid.grid-auto-fit-lg{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}.grid.grid-auto-fit-xl{grid-template-columns:repeat(auto-fit,minmax(350px,1fr))}.grid.grid-auto-fill-sm{grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}.grid.grid-auto-fill-md{grid-template-columns:repeat(auto-fill,minmax(250px,1fr))}.grid.grid-auto-fill-lg{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}.grid.grid-ratio-1-2{grid-template-columns:1fr 2fr}.grid.grid-ratio-2-1{grid-template-columns:2fr 1fr}.grid.grid-ratio-1-3{grid-template-columns:1fr 3fr}.grid.grid-ratio-3-1{grid-template-columns:3fr 1fr}.grid.grid-ratio-1-2-1{grid-template-columns:1fr 2fr 1fr}.grid.grid-ratio-2-1-1{grid-template-columns:2fr 1fr 1fr}.grid.grid-quarter-three{grid-template-columns:1fr 3fr}.grid.grid-third-two{grid-template-columns:1fr 2fr}.grid.grid-half-half{grid-template-columns:1fr 1fr}.grid.gap-xs{gap:.25rem}.grid.gap-sm{gap:.5rem}.grid.gap-md{gap:1rem}.grid.gap-lg{gap:1.5rem}.grid.gap-xl{gap:2rem}.grid.row-gap-xs{row-gap:.25rem}.grid.row-gap-sm{row-gap:.5rem}.grid.row-gap-md{row-gap:1rem}.grid.row-gap-lg{row-gap:1.5rem}.grid.col-gap-xs{column-gap:.25rem}.grid.col-gap-sm{column-gap:.5rem}.grid.col-gap-md{column-gap:1rem}.grid.col-gap-lg{column-gap:1.5rem}.grid.align-start{align-items:start}.grid.align-center{align-items:center}.grid.align-end{align-items:end}.grid.align-stretch{align-items:stretch}.grid.justify-start{justify-items:start}.grid.justify-center{justify-items:center}.grid.justify-end{justify-items:end}.grid.justify-stretch{justify-items:stretch}.grid.grid-dense{grid-auto-flow:dense}.grid.grid-masonry{grid-auto-rows:min-content;align-items:start}@media (min-width: 1200px){.grid.xl-grid-1{grid-template-columns:1fr}.grid.xl-grid-2{grid-template-columns:repeat(2,1fr)}.grid.xl-grid-3{grid-template-columns:repeat(3,1fr)}.grid.xl-grid-4{grid-template-columns:repeat(4,1fr)}.grid.xl-grid-5{grid-template-columns:repeat(5,1fr)}.grid.xl-grid-6{grid-template-columns:repeat(6,1fr)}}@media (max-width: 1199px) and (min-width: 992px){.grid.lg-grid-1{grid-template-columns:1fr}.grid.lg-grid-2{grid-template-columns:repeat(2,1fr)}.grid.lg-grid-3{grid-template-columns:repeat(3,1fr)}.grid.lg-grid-4{grid-template-columns:repeat(4,1fr)}}@media (max-width: 991px) and (min-width: 768px){.grid.md-grid-1{grid-template-columns:1fr}.grid.md-grid-2{grid-template-columns:repeat(2,1fr)}.grid.md-grid-3{grid-template-columns:repeat(3,1fr)}}@media (max-width: 767px) and (min-width: 576px){.grid.sm-grid-1{grid-template-columns:1fr}.grid.sm-grid-2{grid-template-columns:repeat(2,1fr)}}@media (max-width: 575px){.grid.xs-grid-1{grid-template-columns:1fr}}@media (max-width: 1024px){.grid.grid-4:not([class*=lg-grid]):not([class*=md-grid]){grid-template-columns:repeat(2,1fr)}.grid.grid-5:not([class*=lg-grid]):not([class*=md-grid]),.grid.grid-6:not([class*=lg-grid]):not([class*=md-grid]){grid-template-columns:repeat(3,1fr)}}@media (max-width: 768px){.grid{gap:.75rem}.grid.grid-2:not([class*=sm-grid]):not([class*=xs-grid]),.grid.grid-3:not([class*=sm-grid]):not([class*=xs-grid]),.grid.grid-4:not([class*=sm-grid]):not([class*=xs-grid]),.grid.grid-5:not([class*=sm-grid]):not([class*=xs-grid]),.grid.grid-6:not([class*=sm-grid]):not([class*=xs-grid]){grid-template-columns:1fr}.grid.gap-lg{gap:1rem}.grid.gap-xl{gap:1.25rem}}@media (max-width: 480px){.grid{gap:.5rem}.grid:not([class*=xs-grid]){grid-template-columns:1fr!important}.grid.gap-md{gap:.75rem}.grid.gap-lg,.grid.gap-xl{gap:1rem}}.grid-item.span-1{grid-column:span 1}.grid-item.span-2{grid-column:span 2}.grid-item.span-3{grid-column:span 3}.grid-item.span-4{grid-column:span 4}.grid-item.span-5{grid-column:span 5}.grid-item.span-6{grid-column:span 6}.grid-item.span-full{grid-column:1/-1}.grid-item.row-span-1{grid-row:span 1}.grid-item.row-span-2{grid-row:span 2}.grid-item.row-span-3{grid-row:span 3}.grid-item.row-span-4{grid-row:span 4}.grid-item.start-1{grid-column-start:1}.grid-item.start-2{grid-column-start:2}.grid-item.start-3{grid-column-start:3}.grid-item.start-4{grid-column-start:4}.grid-item.end-1{grid-column-end:1}.grid-item.end-2{grid-column-end:2}.grid-item.end-3{grid-column-end:3}.grid-item.end-4{grid-column-end:4}.grid-item.end-auto{grid-column-end:auto}.grid-item.self-start{align-self:start}.grid-item.self-center{align-self:center}.grid-item.self-end{align-self:end}.grid-item.self-stretch{align-self:stretch}.grid-item.justify-self-start{justify-self:start}.grid-item.justify-self-center{justify-self:center}.grid-item.justify-self-end{justify-self:end}.grid-item.justify-self-stretch{justify-self:stretch}@media (max-width: 768px){.grid-item.md-span-1{grid-column:span 1}.grid-item.md-span-2{grid-column:span 2}.grid-item.md-span-full{grid-column:1/-1}}@media (max-width: 480px){.grid-item.sm-span-full{grid-column:1/-1}}.checkbox-field{margin:.25rem 0}.checkbox-label{display:flex;flex-direction:column;gap:.25rem;cursor:pointer;padding:.75rem 0;background:transparent;border:none;border-radius:0;transition:all .2s ease}.checkbox-label:hover{background:#667eea05}.checkbox-label .checkbox-input{width:1rem;height:1rem;accent-color:#667eea;border-radius:3px;margin-bottom:.125rem}.checkbox-label .checkbox-text{font-weight:600;color:#374151;font-size:.875rem}.checkbox-label .checkbox-description{font-size:.75rem;color:#6b7280;margin-top:.125rem}.alert{display:flex;align-items:center;gap:.5rem;padding:.75rem 0;margin:1rem 0;border-radius:0;font-weight:500;font-size:.875rem;border-left:3px solid}.alert .alert-icon{width:1rem;height:1rem;flex-shrink:0}.alert.alert-success{background:#dcfce74d;border-left-color:#22c55e;color:#166534}.alert.alert-error{background:#fef2f24d;border-left-color:#ef4444;color:#dc2626}.error-message{font-size:.75rem;color:#dc2626;margin-top:.25rem;padding-left:.125rem;font-weight:500}.form-tabs{padding:0;margin:1rem 0;border-bottom:1px solid #e5e7eb}.tab-content{transition:opacity .2s ease}.tab-content.loading{opacity:.6;pointer-events:none}.form-actions{display:flex;justify-content:flex-end;gap:.75rem;padding:1rem 0;background:#fff;border-top:1px solid #e5e7eb;margin-top:2rem;position:sticky;bottom:0}@media (max-width: 640px){.form-actions{flex-direction:column-reverse}}.btn{display:inline-flex;align-items:center;justify-content:center;gap:.375rem;padding:.5rem 1rem;font-weight:600;font-size:.8125rem;border-radius:6px;border:none;cursor:pointer;transition:all .2s ease;min-width:120px;position:relative}.btn .btn-icon{width:.875rem;height:.875rem}.btn:disabled{opacity:.6;cursor:not-allowed}.btn.btn-primary{background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;box-shadow:0 4px 6px -1px #667eea4d}.btn.btn-primary:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 8px 12px -2px #667eea66}.btn.btn-primary:active:not(:disabled){transform:translateY(0)}.btn.btn-secondary{background:#fff;color:#6b7280;border:2px solid #e5e7eb}.btn.btn-secondary:hover:not(:disabled){background:#f9fafb;border-color:#d1d5db;color:#374151}.entity-type-selector{display:flex;flex-direction:column;gap:.375rem}.input-label{font-size:.875rem;font-weight:500;color:#374151;margin-bottom:.25rem}.entity-type-button{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem;background:#fff;border:1px solid #d1d5db;border-radius:6px;cursor:pointer;transition:all .15s ease;text-align:left;font-size:.875rem;color:#6b7280}.entity-type-button:hover{border-color:#9ca3af;background:#f9fafb}.entity-type-button:focus{outline:none;border-color:var(--cide-theme-primary-color);box-shadow:0 0 0 3px #3b82f61a}.entity-type-button.has-value{color:#374151}.entity-type-button.invalid{border-color:#dc2626;color:#dc2626}.entity-type-button.invalid:hover{border-color:#b91c1c}.entity-type-button.invalid:focus{border-color:#dc2626;box-shadow:0 0 0 3px #dc26261a}.entity-type-button .button-text{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.entity-type-button .button-icon{width:1rem;height:1rem;margin-left:.5rem;flex-shrink:0}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}cide-ele-input,cide-ele-select,cide-ele-textarea,cide-ele-file-input{transition:all .2s ease}@media (max-width: 768px){.entity-form-container{padding:.75rem}.form-header{padding:1rem 0}.form-header .form-title{font-size:1.25rem}.form-header .form-subtitle{font-size:.875rem}.form-tabs{margin:.5rem 0}.tab-content{padding:1rem 0 5rem}.form-section{padding:1rem 0}.form-section .section-title{font-size:1rem}.form-actions{padding:1rem 0;margin-top:1.5rem}}@media (max-width: 480px){.entity-form-container{padding:.25rem}.form-header{padding:.75rem 0}.form-tabs{margin:.25rem 0}.tab-content{padding:.75rem 0 4rem}.form-section{padding:.75rem 0}.form-actions{padding:.75rem 0;margin-top:1rem}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { 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: 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"], outputs: ["ngModelChange", "change", "searchChange"] }, { 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: CideEleFileInputComponent, selector: "cide-ele-file-input", inputs: ["label", "accept", "multiple", "disabled", "helperText", "errorText"], outputs: ["fileChange"] }, { kind: "component", type: CideEleTabComponent, selector: "cide-ele-tab", inputs: ["tabs", "activeTabId", "size", "variant", "fullWidth", "disabled"], outputs: ["tabChange"] }, { 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"] }] });
1145
- }
1146
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityComponent, decorators: [{
1147
- type: Component,
1148
- args: [{ selector: 'cide-adm-entity', standalone: true, imports: [
1149
- ReactiveFormsModule,
1150
- CideInputComponent,
1151
- CideSelectComponent,
1152
- CideTextareaComponent,
1153
- CideEleFileInputComponent,
1154
- CideEleTabComponent,
1155
- CideEleButtonComponent
1156
- ], template: "<!-- \n DYNAMIC GRID SYSTEM FEATURES:\n \n Basic Grids: grid-1, grid-2, grid-3, grid-4, grid-5, grid-6\n \n Auto-fit Grids: grid-auto-fit-sm/md/lg/xl (dynamic columns based on content)\n Auto-fill Grids: grid-auto-fill-sm/md/lg (always fill available space)\n \n Custom Ratios: grid-ratio-1-2, grid-ratio-2-1, grid-ratio-1-3, grid-ratio-3-1, etc.\n Fractional: grid-quarter-three, grid-third-two, grid-half-half\n \n Gap Control: gap-xs, gap-sm, gap-md, gap-lg, gap-xl\n Specific Gaps: row-gap-xs/sm/md/lg, col-gap-xs/sm/md/lg\n \n Alignment: align-start/center/end/stretch, justify-start/center/end/stretch\n \n Responsive: xl-grid-*, lg-grid-*, md-grid-*, sm-grid-*, xs-grid-*\n \n Grid Items: span-1/2/3/4/5/6/full, row-span-*, start-*, end-*\n Item Alignment: self-start/center/end/stretch, justify-self-*\n \n Special: grid-dense (auto-fills gaps), grid-masonry (masonry layout)\n-->\n\n<div class=\"entity-form-container\">\n <form class=\"entity-form\" [formGroup]=\"entityForm\" [class.loading]=\"loading()\" (ngSubmit)=\"onSubmit()\">\n \n <!-- Header Section -->\n <div class=\"form-header\">\n <h2 class=\"form-title\">Create New Entity</h2>\n <p class=\"form-subtitle\">Add a new educational institution to the system</p>\n </div>\n\n <!-- Success and Error Messages -->\n @if (success()) {\n <div class=\"alert alert-success\">\n <svg class=\"alert-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"></path>\n </svg>\n {{ success() }}\n </div>\n }\n @if (error()) {\n <div class=\"alert alert-error\">\n <svg class=\"alert-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"></path>\n </svg>\n {{ error() }}\n </div>\n }\n\n <!-- Tab Navigation -->\n <div class=\"form-tabs\">\n <cide-ele-tab \n [tabs]=\"entityTabs()\"\n [activeTabId]=\"activeTab()\"\n size=\"md\"\n variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\"\n [class.loading]=\"loading()\">\n @switch (activeTab()) {\n \n @case ('basic') {\n <!-- Basic Information Section -->\n <div class=\"form-section\">\n <div class=\"grid grid-auto-fit-md gap-md lg-grid-2 md-grid-1\">\n <div class=\"grid-item span-2 md-span-full\">\n <cide-ele-input \n id=\"syen_name\" \n type=\"text\"\n label=\"Institution Name\" \n formControlName=\"syen_name\"\n placeholder=\"Enter full institution name\">\n </cide-ele-input>\n </div>\n \n <cide-ele-input \n label=\"Institution Code\" \n formControlName=\"syen_entity_code\"\n id=\"syen_entity_code\"\n placeholder=\"Enter unique code (max 40 characters)\">\n </cide-ele-input>\n </div>\n\n <div class=\"grid grid-ratio-2-1-1 gap-md lg-grid-3 md-grid-2 sm-grid-1\">\n <cide-ele-select \n label=\"Entity Type\" \n [options]=\"entityTypes()\" \n formControlName=\"syen_entity_type_gmst\"\n placeholder=\"Select entity type\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"UDISE Number\" \n formControlName=\"syen_udise_no\"\n placeholder=\"Enter UDISE number\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Affiliation Number\" \n formControlName=\"syen_affiliation_no\"\n placeholder=\"Enter affiliation number\">\n </cide-ele-input>\n </div>\n\n <div class=\"grid grid-1 gap-sm\">\n <div class=\"checkbox-field\">\n <label class=\"checkbox-label\">\n <input \n type=\"checkbox\" \n formControlName=\"syen_isactive\"\n class=\"checkbox-input\" />\n <span class=\"checkbox-text\">Active Status</span>\n <span class=\"checkbox-description\">Enable this entity for system operations</span>\n </label>\n </div>\n </div>\n </div>\n }\n\n @case ('corporate') {\n <!-- Corporate Address Section -->\n <div class=\"form-section\">\n <div class=\"grid grid-1 gap-md\">\n <div class=\"grid-item span-full\">\n <cide-ele-textarea \n label=\"Corporate Address\" \n formControlName=\"syen_corporate_address\"\n placeholder=\"Enter complete corporate address\"\n [rows]=\"3\">\n </cide-ele-textarea>\n </div>\n </div>\n\n <div class=\"grid grid-auto-fit-sm gap-lg xl-grid-4 lg-grid-3 md-grid-2 sm-grid-1 align-end\">\n <cide-ele-select \n label=\"Postal Code\"\n [options]=\"postalCodes()\" \n formControlName=\"syen_corporate_pin_sypin\"\n placeholder=\"Select postal code\"\n [searchable]=\"true\"\n [loading]=\"postalCodesLoading()\"\n (searchChange)=\"onPostalCodeSearch($event)\"\n (selectionChange)=\"onPostalCodeSelection($event)\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"City\" \n formControlName=\"syen_corporate_city_sypin\"\n placeholder=\"Enter city\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"State\" \n formControlName=\"syen_corporate_state_sypin\"\n placeholder=\"Enter state\">\n </cide-ele-input>\n \n <cide-ele-select \n label=\"Country\" \n [options]=\"countries()\" \n formControlName=\"syen_corporate_country_syctr\"\n placeholder=\"Select country\"\n [searchable]=\"true\"\n [loading]=\"countriesLoading()\"\n (searchChange)=\"onCountrySearch($event)\">\n </cide-ele-select>\n </div>\n </div>\n }\n\n @case ('contact') {\n <!-- Contact Information Section -->\n <div class=\"form-section\">\n <div class=\"grid grid-ratio-3-1 gap-lg md-grid-2 sm-grid-1 justify-stretch\">\n <div class=\"grid-item justify-self-stretch\">\n <cide-ele-select \n label=\"Primary Contact Person\"\n [options]=\"users()\" \n formControlName=\"syen_corporate_contact_person_user\"\n placeholder=\"Select contact person\"\n [searchable]=\"true\"\n [loading]=\"usersLoading()\"\n (searchChange)=\"onUserSearch($event)\">\n </cide-ele-select>\n </div>\n \n <div class=\"grid-item justify-self-stretch\">\n <cide-ele-select \n label=\"Currency\" \n [options]=\"currencies()\" \n formControlName=\"syen_currency_sycr\"\n placeholder=\"Select currency\">\n </cide-ele-select>\n </div>\n </div>\n\n <div class=\"grid grid-auto-fill-md gap-md col-gap-lg row-gap-sm xl-grid-3 lg-grid-2 md-grid-1 grid-dense\">\n <cide-ele-input \n label=\"Primary Phone\" \n formControlName=\"syen_corporate_phone\"\n type=\"tel\"\n placeholder=\"Enter phone number\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Alternate Phone\" \n formControlName=\"syen_corporate_phone_alt\"\n type=\"tel\"\n placeholder=\"Enter alternate phone\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Fax Number\" \n formControlName=\"syen_corporate_fax\"\n placeholder=\"Enter fax number\">\n </cide-ele-input>\n </div>\n\n <div class=\"grid grid-ratio-1-2-1 gap-xl lg-grid-3 md-grid-2 sm-grid-1 align-center\">\n <div class=\"grid-item self-stretch\">\n <cide-ele-input \n label=\"Primary Email\" \n formControlName=\"syen_corporate_email\"\n type=\"email\"\n placeholder=\"Enter primary email\">\n </cide-ele-input>\n </div>\n \n <div class=\"grid-item span-2 lg-span-1 self-stretch\">\n <cide-ele-input \n label=\"Website URL\" \n formControlName=\"syen_website\"\n type=\"url\"\n placeholder=\"Enter website URL\">\n </cide-ele-input>\n </div>\n \n <div class=\"grid-item self-stretch\">\n <cide-ele-input \n label=\"Alternate Email\" \n formControlName=\"syen_corporate_email_alt\"\n type=\"email\"\n placeholder=\"Enter alternate email\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n\n @case ('registered') {\n <!-- Registered Address Section -->\n <div class=\"form-section\">\n <div class=\"grid grid-1\">\n <cide-ele-textarea \n label=\"Registered Address\" \n formControlName=\"syen_registered_address\"\n placeholder=\"Enter complete registered address\"\n [rows]=\"3\">\n </cide-ele-textarea>\n </div>\n\n <div class=\"grid grid-4\">\n <cide-ele-select \n label=\"Registered Postal Code\"\n [options]=\"postalCodes()\" \n formControlName=\"syen_registered_pin_sypin\"\n placeholder=\"Select postal code\"\n [searchable]=\"true\"\n [loading]=\"postalCodesLoading()\"\n (searchChange)=\"onPostalCodeSearch($event)\"\n (selectionChange)=\"onPostalCodeSelection($event)\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"Registered City\" \n formControlName=\"syen_registered_city_sypin\"\n placeholder=\"Enter city\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Registered State\" \n formControlName=\"syen_registered_state_sypin\"\n placeholder=\"Enter state\">\n </cide-ele-input>\n \n <cide-ele-select \n label=\"Registered Country\" \n [options]=\"countries()\" \n formControlName=\"syen_registered_country_syctr\"\n placeholder=\"Select country\"\n [searchable]=\"true\"\n [loading]=\"countriesLoading()\"\n (searchChange)=\"onCountrySearch($event)\">\n </cide-ele-select>\n </div>\n\n <div class=\"grid grid-3\">\n <cide-ele-select \n label=\"Registered Contact Person\"\n [options]=\"users()\" \n formControlName=\"syen_registered_contact_person_user\"\n placeholder=\"Select contact person\"\n [searchable]=\"true\"\n [loading]=\"usersLoading()\"\n (searchChange)=\"onUserSearch($event)\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"Registered Phone\" \n formControlName=\"syen_registered_phone\"\n type=\"tel\"\n placeholder=\"Enter phone number\">\n </cide-ele-input>\n \n <cide-ele-input \n label=\"Registered Email\" \n formControlName=\"syen_registered_email\"\n type=\"email\"\n placeholder=\"Enter email\">\n </cide-ele-input>\n @if (hasError('syen_registered_email')) {\n <div class=\"error-message\">{{ getErrorMessage('syen_registered_email') }}</div>\n }\n </div>\n\n <div class=\"grid grid-1\">\n <cide-ele-input \n label=\"Registered Fax\" \n formControlName=\"syen_registered_fax\"\n placeholder=\"Enter fax number\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n @case ('documents') {\n <!-- Documents Section -->\n <div class=\"form-section\">\n <!-- Photo ID Document -->\n <div class=\"grid grid-1 gap-md\">\n <cide-ele-select \n label=\"Photo ID Document\" \n [options]=\"photoIdDocuments()\" \n formControlName=\"syen_photo_id_cyfm\"\n placeholder=\"Select photo ID document\">\n </cide-ele-select>\n </div>\n\n <!-- Logo Upload -->\n <div class=\"grid grid-quarter-three gap-lg md-grid-1 align-center\">\n <div class=\"grid-item self-center justify-self-center\">\n <!-- Logo preview placeholder -->\n <div style=\"width: 120px; height: 120px; border: 2px dashed #cbd5e1; border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #9ca3af; font-size: 0.875rem; text-align: center;\">\n Logo Preview\n </div>\n </div>\n <div class=\"grid-item self-stretch\">\n <cide-ele-file-input \n label=\"Upload Logo\" \n accept=\"image/*\" \n [multiple]=\"false\" \n (fileChange)=\"onFileChange($event)\"\n placeholder=\"Select institution logo or image\">\n </cide-ele-file-input>\n </div>\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Form Actions -->\n <div class=\"form-actions\">\n <button cideEleButton\n type=\"button\" \n variant=\"secondary\" \n (click)=\"onReset()\" \n leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n \n <button cideEleButton\n type=\"submit\" \n variant=\"primary\" \n [disabled]=\"loading() || entityForm.invalid\"\n [loading]=\"loading()\"\n leftIcon=\"check\">\n Create Entity\n </button>\n </div>\n </form>\n</div> ", styles: [".entity-form-container{background:transparent;padding:1rem;width:100%;box-sizing:border-box}.entity-form{max-width:1200px;margin:0 auto;background:transparent;border:none;box-shadow:none;width:100%}.entity-form.loading{opacity:.6;pointer-events:none}.form-header{background:transparent;color:#1f2937;padding:1.25rem 0;text-align:left}.form-header .form-title{font-size:1.5rem;font-weight:700;margin:0 0 .25rem;color:#1f2937}.form-header .form-subtitle{font-size:.95rem;opacity:.7;margin:0;font-weight:400;color:#6b7280}.form-section{padding:1.25rem 0;border-bottom:none;margin-bottom:1.5rem}.form-section:last-of-type{margin-bottom:0}.form-section .section-title{font-size:1.125rem;font-weight:600;color:#1f2937;margin:0 0 1rem;padding-bottom:.5rem;border-bottom:1px solid #e5e7eb;position:relative}.form-section .section-title:after{content:\"\";position:absolute;bottom:-1px;left:0;width:40px;height:1px;background:#667eea;border-radius:1px}.grid{display:grid;gap:1rem;margin-bottom:.75rem;transition:all .3s ease}.grid:last-child{margin-bottom:0}.grid.grid-1{grid-template-columns:1fr}.grid.grid-2{grid-template-columns:repeat(2,1fr)}.grid.grid-3{grid-template-columns:repeat(3,1fr)}.grid.grid-4{grid-template-columns:repeat(4,1fr)}.grid.grid-5{grid-template-columns:repeat(5,1fr)}.grid.grid-6{grid-template-columns:repeat(6,1fr)}.grid.grid-auto-fit-sm{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}.grid.grid-auto-fit-md{grid-template-columns:repeat(auto-fit,minmax(250px,1fr))}.grid.grid-auto-fit-lg{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}.grid.grid-auto-fit-xl{grid-template-columns:repeat(auto-fit,minmax(350px,1fr))}.grid.grid-auto-fill-sm{grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}.grid.grid-auto-fill-md{grid-template-columns:repeat(auto-fill,minmax(250px,1fr))}.grid.grid-auto-fill-lg{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}.grid.grid-ratio-1-2{grid-template-columns:1fr 2fr}.grid.grid-ratio-2-1{grid-template-columns:2fr 1fr}.grid.grid-ratio-1-3{grid-template-columns:1fr 3fr}.grid.grid-ratio-3-1{grid-template-columns:3fr 1fr}.grid.grid-ratio-1-2-1{grid-template-columns:1fr 2fr 1fr}.grid.grid-ratio-2-1-1{grid-template-columns:2fr 1fr 1fr}.grid.grid-quarter-three{grid-template-columns:1fr 3fr}.grid.grid-third-two{grid-template-columns:1fr 2fr}.grid.grid-half-half{grid-template-columns:1fr 1fr}.grid.gap-xs{gap:.25rem}.grid.gap-sm{gap:.5rem}.grid.gap-md{gap:1rem}.grid.gap-lg{gap:1.5rem}.grid.gap-xl{gap:2rem}.grid.row-gap-xs{row-gap:.25rem}.grid.row-gap-sm{row-gap:.5rem}.grid.row-gap-md{row-gap:1rem}.grid.row-gap-lg{row-gap:1.5rem}.grid.col-gap-xs{column-gap:.25rem}.grid.col-gap-sm{column-gap:.5rem}.grid.col-gap-md{column-gap:1rem}.grid.col-gap-lg{column-gap:1.5rem}.grid.align-start{align-items:start}.grid.align-center{align-items:center}.grid.align-end{align-items:end}.grid.align-stretch{align-items:stretch}.grid.justify-start{justify-items:start}.grid.justify-center{justify-items:center}.grid.justify-end{justify-items:end}.grid.justify-stretch{justify-items:stretch}.grid.grid-dense{grid-auto-flow:dense}.grid.grid-masonry{grid-auto-rows:min-content;align-items:start}@media (min-width: 1200px){.grid.xl-grid-1{grid-template-columns:1fr}.grid.xl-grid-2{grid-template-columns:repeat(2,1fr)}.grid.xl-grid-3{grid-template-columns:repeat(3,1fr)}.grid.xl-grid-4{grid-template-columns:repeat(4,1fr)}.grid.xl-grid-5{grid-template-columns:repeat(5,1fr)}.grid.xl-grid-6{grid-template-columns:repeat(6,1fr)}}@media (max-width: 1199px) and (min-width: 992px){.grid.lg-grid-1{grid-template-columns:1fr}.grid.lg-grid-2{grid-template-columns:repeat(2,1fr)}.grid.lg-grid-3{grid-template-columns:repeat(3,1fr)}.grid.lg-grid-4{grid-template-columns:repeat(4,1fr)}}@media (max-width: 991px) and (min-width: 768px){.grid.md-grid-1{grid-template-columns:1fr}.grid.md-grid-2{grid-template-columns:repeat(2,1fr)}.grid.md-grid-3{grid-template-columns:repeat(3,1fr)}}@media (max-width: 767px) and (min-width: 576px){.grid.sm-grid-1{grid-template-columns:1fr}.grid.sm-grid-2{grid-template-columns:repeat(2,1fr)}}@media (max-width: 575px){.grid.xs-grid-1{grid-template-columns:1fr}}@media (max-width: 1024px){.grid.grid-4:not([class*=lg-grid]):not([class*=md-grid]){grid-template-columns:repeat(2,1fr)}.grid.grid-5:not([class*=lg-grid]):not([class*=md-grid]),.grid.grid-6:not([class*=lg-grid]):not([class*=md-grid]){grid-template-columns:repeat(3,1fr)}}@media (max-width: 768px){.grid{gap:.75rem}.grid.grid-2:not([class*=sm-grid]):not([class*=xs-grid]),.grid.grid-3:not([class*=sm-grid]):not([class*=xs-grid]),.grid.grid-4:not([class*=sm-grid]):not([class*=xs-grid]),.grid.grid-5:not([class*=sm-grid]):not([class*=xs-grid]),.grid.grid-6:not([class*=sm-grid]):not([class*=xs-grid]){grid-template-columns:1fr}.grid.gap-lg{gap:1rem}.grid.gap-xl{gap:1.25rem}}@media (max-width: 480px){.grid{gap:.5rem}.grid:not([class*=xs-grid]){grid-template-columns:1fr!important}.grid.gap-md{gap:.75rem}.grid.gap-lg,.grid.gap-xl{gap:1rem}}.grid-item.span-1{grid-column:span 1}.grid-item.span-2{grid-column:span 2}.grid-item.span-3{grid-column:span 3}.grid-item.span-4{grid-column:span 4}.grid-item.span-5{grid-column:span 5}.grid-item.span-6{grid-column:span 6}.grid-item.span-full{grid-column:1/-1}.grid-item.row-span-1{grid-row:span 1}.grid-item.row-span-2{grid-row:span 2}.grid-item.row-span-3{grid-row:span 3}.grid-item.row-span-4{grid-row:span 4}.grid-item.start-1{grid-column-start:1}.grid-item.start-2{grid-column-start:2}.grid-item.start-3{grid-column-start:3}.grid-item.start-4{grid-column-start:4}.grid-item.end-1{grid-column-end:1}.grid-item.end-2{grid-column-end:2}.grid-item.end-3{grid-column-end:3}.grid-item.end-4{grid-column-end:4}.grid-item.end-auto{grid-column-end:auto}.grid-item.self-start{align-self:start}.grid-item.self-center{align-self:center}.grid-item.self-end{align-self:end}.grid-item.self-stretch{align-self:stretch}.grid-item.justify-self-start{justify-self:start}.grid-item.justify-self-center{justify-self:center}.grid-item.justify-self-end{justify-self:end}.grid-item.justify-self-stretch{justify-self:stretch}@media (max-width: 768px){.grid-item.md-span-1{grid-column:span 1}.grid-item.md-span-2{grid-column:span 2}.grid-item.md-span-full{grid-column:1/-1}}@media (max-width: 480px){.grid-item.sm-span-full{grid-column:1/-1}}.checkbox-field{margin:.25rem 0}.checkbox-label{display:flex;flex-direction:column;gap:.25rem;cursor:pointer;padding:.75rem 0;background:transparent;border:none;border-radius:0;transition:all .2s ease}.checkbox-label:hover{background:#667eea05}.checkbox-label .checkbox-input{width:1rem;height:1rem;accent-color:#667eea;border-radius:3px;margin-bottom:.125rem}.checkbox-label .checkbox-text{font-weight:600;color:#374151;font-size:.875rem}.checkbox-label .checkbox-description{font-size:.75rem;color:#6b7280;margin-top:.125rem}.alert{display:flex;align-items:center;gap:.5rem;padding:.75rem 0;margin:1rem 0;border-radius:0;font-weight:500;font-size:.875rem;border-left:3px solid}.alert .alert-icon{width:1rem;height:1rem;flex-shrink:0}.alert.alert-success{background:#dcfce74d;border-left-color:#22c55e;color:#166534}.alert.alert-error{background:#fef2f24d;border-left-color:#ef4444;color:#dc2626}.error-message{font-size:.75rem;color:#dc2626;margin-top:.25rem;padding-left:.125rem;font-weight:500}.form-tabs{padding:0;margin:1rem 0;border-bottom:1px solid #e5e7eb}.tab-content{transition:opacity .2s ease}.tab-content.loading{opacity:.6;pointer-events:none}.form-actions{display:flex;justify-content:flex-end;gap:.75rem;padding:1rem 0;background:#fff;border-top:1px solid #e5e7eb;margin-top:2rem;position:sticky;bottom:0}@media (max-width: 640px){.form-actions{flex-direction:column-reverse}}.btn{display:inline-flex;align-items:center;justify-content:center;gap:.375rem;padding:.5rem 1rem;font-weight:600;font-size:.8125rem;border-radius:6px;border:none;cursor:pointer;transition:all .2s ease;min-width:120px;position:relative}.btn .btn-icon{width:.875rem;height:.875rem}.btn:disabled{opacity:.6;cursor:not-allowed}.btn.btn-primary{background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;box-shadow:0 4px 6px -1px #667eea4d}.btn.btn-primary:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 8px 12px -2px #667eea66}.btn.btn-primary:active:not(:disabled){transform:translateY(0)}.btn.btn-secondary{background:#fff;color:#6b7280;border:2px solid #e5e7eb}.btn.btn-secondary:hover:not(:disabled){background:#f9fafb;border-color:#d1d5db;color:#374151}.entity-type-selector{display:flex;flex-direction:column;gap:.375rem}.input-label{font-size:.875rem;font-weight:500;color:#374151;margin-bottom:.25rem}.entity-type-button{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem;background:#fff;border:1px solid #d1d5db;border-radius:6px;cursor:pointer;transition:all .15s ease;text-align:left;font-size:.875rem;color:#6b7280}.entity-type-button:hover{border-color:#9ca3af;background:#f9fafb}.entity-type-button:focus{outline:none;border-color:var(--cide-theme-primary-color);box-shadow:0 0 0 3px #3b82f61a}.entity-type-button.has-value{color:#374151}.entity-type-button.invalid{border-color:#dc2626;color:#dc2626}.entity-type-button.invalid:hover{border-color:#b91c1c}.entity-type-button.invalid:focus{border-color:#dc2626;box-shadow:0 0 0 3px #dc26261a}.entity-type-button .button-text{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.entity-type-button .button-icon{width:1rem;height:1rem;margin-left:.5rem;flex-shrink:0}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}cide-ele-input,cide-ele-select,cide-ele-textarea,cide-ele-file-input{transition:all .2s ease}@media (max-width: 768px){.entity-form-container{padding:.75rem}.form-header{padding:1rem 0}.form-header .form-title{font-size:1.25rem}.form-header .form-subtitle{font-size:.875rem}.form-tabs{margin:.5rem 0}.tab-content{padding:1rem 0 5rem}.form-section{padding:1rem 0}.form-section .section-title{font-size:1rem}.form-actions{padding:1rem 0;margin-top:1.5rem}}@media (max-width: 480px){.entity-form-container{padding:.25rem}.form-header{padding:.75rem 0}.form-tabs{margin:.25rem 0}.tab-content{padding:.75rem 0 4rem}.form-section{padding:.75rem 0}.form-actions{padding:.75rem 0;margin-top:1rem}}\n"] }]
1157
- }], ctorParameters: () => [] });
1158
-
1159
- var cideAdmEntity_component = /*#__PURE__*/Object.freeze({
1160
- __proto__: null,
1161
- CideAdmEntityComponent: CideAdmEntityComponent
1162
- });
1163
-
1164
- class CideAdmEntityListService {
1165
- http = inject(HttpClient);
1166
- /**
1167
- * Get list of entities using the proper API endpoint
1168
- * @param body - MEntity payload for filtering/pagination
1169
- * @returns Observable of entityControllerResponse
1170
- */
1171
- getEntityList(body) {
1172
- const query = generateStringFromObject(body);
1173
- const url = cidePath.join([
1174
- hostManagerRoutesUrl.cideSuiteHost,
1175
- coreRoutesUrl.module,
1176
- coreRoutesUrl.entity,
1177
- query
1178
- ]);
1179
- console.log('🔍 ENTITY SERVICE: Making API call to:', url);
1180
- console.log('🔍 ENTITY SERVICE: Payload:', body);
1181
- return this.http.get(url);
1182
- }
1183
- /**
1184
- * Get entity list with default parameters
1185
- * @returns Observable of entityControllerResponse
1186
- */
1187
- getAllEntities() {
1188
- const defaultPayload = {};
1189
- return this.getEntityList(defaultPayload);
1190
- }
1191
- /**
1192
- * Get filtered entity list
1193
- * @param filters - Filter parameters
1194
- * @returns Observable of entityControllerResponse
1195
- */
1196
- getFilteredEntities(filters) {
1197
- const payload = { ...filters };
1198
- return this.getEntityList(payload);
1199
- }
1200
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityListService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1201
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityListService, providedIn: 'root' });
1202
- }
1203
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityListService, decorators: [{
1204
- type: Injectable,
1205
- args: [{
1206
- providedIn: 'root'
1207
- }]
1208
- }] });
1209
-
1210
- class CideAdmEntityListComponent {
1211
- // Modern dependency injection using inject()
1212
- router = inject(Router); // Made public for template access
1213
- entityService = inject(CideAdmEntityListService);
1214
- // ViewChild reference to the grid component
1215
- gridComponent;
1216
- // State management using Angular Signals
1217
- entities = signal([], ...(ngDevMode ? [{ debugName: "entities" }] : []));
1218
- loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1219
- error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
1220
- searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
1221
- currentPage = signal(1, ...(ngDevMode ? [{ debugName: "currentPage" }] : []));
1222
- pageSize = signal(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
1223
- totalItems = signal(0, ...(ngDevMode ? [{ debugName: "totalItems" }] : []));
1224
- selectedEntityType = signal('', ...(ngDevMode ? [{ debugName: "selectedEntityType" }] : []));
1225
- // Getter and setter for ngModel compatibility
1226
- get selectedEntityTypeValue() {
1227
- return this.selectedEntityType();
1228
- }
1229
- set selectedEntityTypeValue(value) {
1230
- this.selectedEntityType.set(value);
1231
- }
1232
- // Pagination calculations
1233
- totalPages = signal(0, ...(ngDevMode ? [{ debugName: "totalPages" }] : []));
1234
- hasNextPage = signal(false, ...(ngDevMode ? [{ debugName: "hasNextPage" }] : []));
1235
- hasPreviousPage = signal(false, ...(ngDevMode ? [{ debugName: "hasPreviousPage" }] : []));
1236
- jumpToPage = 1;
1237
- loadStartTime = 0;
1238
- // Filter options
1239
- entityTypeOptions = signal([
1240
- { value: '', label: 'All Entity Types' },
1241
- { value: 'school', label: 'School' },
1242
- { value: 'college', label: 'College' },
1243
- { value: 'university', label: 'University' },
1244
- { value: 'institute', label: 'Institute' }
1245
- ], ...(ngDevMode ? [{ debugName: "entityTypeOptions" }] : []));
1246
- // Grid configuration signal
1247
- gridConfig = signal({
1248
- id: 'entity-list-grid',
1249
- title: '',
1250
- subtitle: '',
1251
- columns: [
1252
- {
1253
- key: 'details',
1254
- header: 'Entity Details',
1255
- type: 'custom',
1256
- width: 'lg',
1257
- truncate: true,
1258
- align: 'left',
1259
- renderer: 'entityDetailsRenderer'
1260
- },
1261
- {
1262
- key: 'contact',
1263
- header: 'Contact Information',
1264
- type: 'custom',
1265
- width: 'lg',
1266
- truncate: true,
1267
- align: 'left',
1268
- renderer: 'contactInfoRenderer'
1269
- },
1270
- {
1271
- key: 'syen_isactive',
1272
- header: 'Status',
1273
- type: 'status',
1274
- width: 'md',
1275
- truncate: false,
1276
- align: 'center',
1277
- statusConfig: {
1278
- activeValue: true,
1279
- activeLabel: 'Active',
1280
- inactiveLabel: 'Inactive',
1281
- activeClass: 'tw-bg-green-100 tw-text-green-800',
1282
- inactiveClass: 'tw-bg-red-100 tw-text-red-800'
1283
- }
1284
- },
1285
- {
1286
- key: 'syen_entity_type_gmst',
1287
- header: 'Entity Type',
1288
- type: 'text',
1289
- width: 'md',
1290
- truncate: false,
1291
- align: 'center'
1292
- },
1293
- {
1294
- key: 'actions',
1295
- header: 'Actions',
1296
- type: 'actions',
1297
- width: 'md',
1298
- truncate: false,
1299
- align: 'right',
1300
- actions: [
1301
- {
1302
- key: 'edit',
1303
- label: 'Edit',
1304
- icon: 'pencil',
1305
- variant: 'outline',
1306
- tooltip: 'Edit entity',
1307
- onClick: 'onEditEntity'
1308
- },
1309
- {
1310
- key: 'delete',
1311
- label: 'Delete',
1312
- icon: 'trash',
1313
- variant: 'danger',
1314
- tooltip: 'Delete entity',
1315
- onClick: 'onDeleteEntity'
1316
- }
1317
- ]
1318
- }
1319
- ],
1320
- data: [],
1321
- trackBy: '_id',
1322
- pagination: {
1323
- enabled: true,
1324
- pageSize: 10,
1325
- pageSizeOptions: [10, 25, 50, 100],
1326
- showQuickJump: true,
1327
- showPageInfo: true,
1328
- showRefresh: true
1329
- },
1330
- search: {
1331
- enabled: true,
1332
- placeholder: 'Search entities...',
1333
- searchableColumns: ['syen_name', 'syen_entity_code', 'syen_corporate_email'],
1334
- debounceMs: 300
1335
- },
1336
- loading: {
1337
- useDefer: true,
1338
- skeletonRows: 5,
1339
- showOverlay: false
1340
- },
1341
- responsive: true,
1342
- striped: false,
1343
- bordered: true,
1344
- compact: false,
1345
- fullHeight: true,
1346
- onRowClick: 'onEntityRowClick',
1347
- onRefresh: 'onEntityRefresh',
1348
- tree: {
1349
- enabled: true,
1350
- primaryKey: '_id',
1351
- foreignKey: 'syen_parent_entity_id',
1352
- childrenKey: 'children',
1353
- levelKey: 'level',
1354
- expandedKey: 'isExpanded',
1355
- hasChildrenKey: 'hasChildren'
1356
- }
1357
- }, ...(ngDevMode ? [{ debugName: "gridConfig" }] : []));
1358
- // Custom renderers for complex columns
1359
- customRenderers = {
1360
- entityDetailsRenderer: (value, row) => {
1361
- const entityCode = row.syen_entity_code || 'N/A';
1362
- const entityName = row.syen_name || 'Unknown Entity';
1363
- return `
1364
- <div class="tw-flex tw-items-center tw-space-x-3">
1365
- <div class="tw-flex-shrink-0 tw-w-10 tw-h-10 tw-bg-blue-100 tw-rounded-full tw-flex tw-items-center tw-justify-center">
1366
- <span class="tw-text-blue-600 tw-font-semibold tw-text-sm">
1367
- ${entityCode.substring(0, 2).toUpperCase()}
1368
- </span>
1369
- </div>
1370
- <div class="tw-flex-1 tw-min-w-0">
1371
- <p class="tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate" title="${entityName}">
1372
- ${entityName}
1373
- </p>
1374
- <p class="tw-text-sm tw-text-gray-500 tw-truncate" title="${entityCode}">
1375
- Code: ${entityCode}
1376
- </p>
1377
- </div>
1378
- </div>
1379
- `;
1380
- },
1381
- contactInfoRenderer: (value, row) => {
1382
- const contactPerson = row.syen_corporate_contact_person_user || 'N/A';
1383
- const email = row.syen_corporate_email || 'N/A';
1384
- const phone = row.syen_corporate_phone ? String(row.syen_corporate_phone) : 'N/A';
1385
- return `
1386
- <div class="tw-space-y-1">
1387
- <p class="tw-text-sm tw-text-gray-900 tw-truncate tw-flex tw-items-center" title="${contactPerson}">
1388
- <svg class="tw-flex-shrink-0 tw-w-4 tw-h-4 tw-text-gray-400 tw-mr-2" fill="currentColor" viewBox="0 0 20 20">
1389
- <path d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"/>
1390
- </svg>
1391
- <span class="tw-truncate">${contactPerson}</span>
1392
- </p>
1393
- <p class="tw-text-sm tw-text-gray-600 tw-truncate tw-flex tw-items-center" title="${email}">
1394
- <svg class="tw-flex-shrink-0 tw-w-4 tw-h-4 tw-text-gray-400 tw-mr-2" fill="currentColor" viewBox="0 0 20 20">
1395
- <path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z"/>
1396
- <path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z"/>
1397
- </svg>
1398
- <span class="tw-truncate">${email}</span>
1399
- </p>
1400
- <p class="tw-text-sm tw-text-gray-600 tw-truncate tw-flex tw-items-center" title="${phone}">
1401
- <svg class="tw-flex-shrink-0 tw-w-4 tw-h-4 tw-text-gray-400 tw-mr-2" fill="currentColor" viewBox="0 0 20 20">
1402
- <path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z"/>
1403
- </svg>
1404
- <span class="tw-truncate">${phone}</span>
1405
- </p>
1406
- </div>
1407
- `;
1408
- }
1409
- };
1410
- // Action handlers
1411
- actionHandlers = {
1412
- onEditEntity: (entity) => {
1413
- const query = generateStringFromObject({
1414
- syen_id: entity._id
1415
- });
1416
- this.router.navigate(['control-panel', 'entity-create', query]);
1417
- },
1418
- onDeleteEntity: (entity) => {
1419
- const entityName = entity.syen_name || 'this entity';
1420
- if (confirm(`Are you sure you want to delete ${entityName}?`)) {
1421
- this.onDeleteEntityConfirmed(entity._id || '');
1422
- }
1423
- }
1424
- };
1425
- ngOnInit() {
1426
- console.log('🔧 ENTITY LIST: Component initializing');
1427
- this.updatePaginationState();
1428
- // Set initial loading state to false to allow grid to render
1429
- this.loading.set(false);
1430
- // Load entities from API
1431
- this.loadEntities();
1432
- }
1433
- // Grid event handler
1434
- onGridEvent(event) {
1435
- console.log('📡 GRID EVENT: Received grid event:', event.type, event);
1436
- switch (event.type) {
1437
- case 'rowClick':
1438
- this.onEntityRowClick(event.data);
1439
- break;
1440
- case 'refresh':
1441
- this.onEntityRefresh();
1442
- break;
1443
- case 'search':
1444
- this.onEntitySearch(event.data);
1445
- break;
1446
- case 'pageChange':
1447
- this.onEntityPageChange(event.data);
1448
- break;
1449
- default:
1450
- console.log('Unhandled grid event:', event.type);
1451
- }
1452
- }
1453
- // Event handlers for grid events
1454
- onEntityRowClick(entity) {
1455
- console.log('Entity row clicked:', entity);
1456
- this.router.navigate(['admin', 'entity', 'view', entity._id]);
1457
- }
1458
- onEntityRefresh() {
1459
- console.log('Refreshing entities...');
1460
- this.loadEntities(true);
1461
- }
1462
- onEntitySearch(query) {
1463
- console.log('Search entities:', query);
1464
- this.searchQuery.set(query);
1465
- // The grid handles the actual filtering
1466
- }
1467
- onEntityPageChange(page) {
1468
- console.log('Page changed to:', page);
1469
- this.currentPage.set(page);
1470
- // Reload data for the new page
1471
- this.loadEntities(false);
1472
- }
1473
- onDeleteEntityConfirmed(entityId) {
1474
- // In a real app, you'd call the API to delete
1475
- console.log('Deleting entity:', entityId);
1476
- // For now, just reload the entities
1477
- this.loadEntities(true);
1478
- }
1479
- // Update grid data method
1480
- updateGridData(entities) {
1481
- console.log('📊 GRID UPDATE: Updating grid with', entities.length, 'entities');
1482
- console.log('📊 GRID UPDATE: Sample entity data:', entities[0] || 'No entities');
1483
- // Set the entities signal
1484
- this.entities.set(entities);
1485
- // Update grid configuration with new data and ensure loading is false
1486
- this.gridConfig.update(config => ({
1487
- ...config,
1488
- data: entities
1489
- }));
1490
- // Ensure loading states are cleared
1491
- this.loading.set(false);
1492
- // Clear page change loading state in the grid component
1493
- if (this.gridComponent) {
1494
- this.gridComponent.clearPageChangeLoading();
1495
- }
1496
- console.log('📊 GRID UPDATE: Grid config updated successfully');
1497
- console.log('📊 GRID UPDATE: Current grid data length:', this.gridConfig().data.length);
1498
- console.log('📊 GRID UPDATE: Loading state:', this.loading());
1499
- console.log('📊 GRID UPDATE: Full grid config for debugging:', JSON.stringify(this.gridConfig(), null, 2));
1500
- }
1501
- loadEntities(isRefresh = false) {
1502
- if (isRefresh) {
1503
- console.log('🔄 ENTITY LIST: Refreshing entities');
1504
- // Set the grid's refresh state to true
1505
- if (this.gridComponent) {
1506
- this.gridComponent.setRefreshing(true);
1507
- }
1508
- }
1509
- else {
1510
- this.loading.set(true);
1511
- console.log('🔍 ENTITY LIST: Loading entities from API');
1512
- }
1513
- this.error.set(null);
1514
- this.loadStartTime = Date.now();
1515
- this.entityService.getAllEntities().subscribe({
1516
- next: (response) => {
1517
- console.log('✅ ENTITY LIST: API response received:', response);
1518
- // Process the response data
1519
- if (response?.data) {
1520
- // Handle both array and single object responses
1521
- const entitiesData = Array.isArray(response.data) ? response.data : [response.data];
1522
- console.log('📋 ENTITY LIST: Processed entities data:', entitiesData.length, 'entities');
1523
- if (entitiesData.length > 0) {
1524
- console.log('📊 ENTITY LIST: First entity sample:', entitiesData[0]);
1525
- this.updateGridData(entitiesData);
1526
- this.totalItems.set(entitiesData.length);
1527
- }
1528
- else {
1529
- console.log('📊 ENTITY LIST: No entities returned, showing test data');
1530
- this.loadTestData();
1531
- }
1532
- }
1533
- else {
1534
- console.warn('⚠️ ENTITY LIST: No data in API response, loading test data');
1535
- this.loadTestData();
1536
- }
1537
- this.updatePaginationState();
1538
- this.loading.set(false);
1539
- // Clear page change loading state in the grid component
1540
- if (this.gridComponent) {
1541
- this.gridComponent.clearPageChangeLoading();
1542
- }
1543
- // Set the grid's refresh state to false when done
1544
- if (isRefresh && this.gridComponent) {
1545
- this.gridComponent.setRefreshing(false);
1546
- }
1547
- },
1548
- error: (err) => {
1549
- console.error('❌ ENTITY LIST: API error:', err);
1550
- console.log('🧪 ENTITY LIST: API failed, loading test data for demonstration');
1551
- // Load test data when API fails
1552
- this.loadTestData();
1553
- this.error.set('API unavailable. Showing sample data.');
1554
- this.loading.set(false);
1555
- // Clear page change loading state in the grid component
1556
- if (this.gridComponent) {
1557
- this.gridComponent.clearPageChangeLoading();
1558
- }
1559
- // Set the grid's refresh state to false when done
1560
- if (isRefresh && this.gridComponent) {
1561
- this.gridComponent.setRefreshing(false);
1562
- }
1563
- }
1564
- });
1565
- }
1566
- loadTestData() {
1567
- console.log('🧪 ENTITY LIST: Loading test data');
1568
- const testData = [
1569
- {
1570
- _id: 'test-1',
1571
- syen_name: 'Test University',
1572
- syen_entity_code: 'TEST001',
1573
- syen_corporate_email: 'test@university.com',
1574
- syen_corporate_contact_person_user: 'John Doe',
1575
- syen_corporate_phone: 9876543210, // Now a number
1576
- syen_isactive: true,
1577
- syen_entity_type_gmst: 'university',
1578
- children: []
1579
- },
1580
- {
1581
- _id: 'test-2',
1582
- syen_name: 'Sample College',
1583
- syen_entity_code: 'SAMP002',
1584
- syen_corporate_email: 'info@samplecollege.edu',
1585
- syen_corporate_contact_person_user: 'Jane Smith',
1586
- syen_corporate_phone: 9876543211,
1587
- syen_isactive: false,
1588
- syen_entity_type_gmst: 'college',
1589
- children: []
1590
- },
1591
- {
1592
- _id: 'test-3',
1593
- syen_name: 'Global Institute of Technology',
1594
- syen_entity_code: 'GIT003',
1595
- syen_corporate_email: 'admin@git.edu',
1596
- syen_corporate_contact_person_user: 'Bob Johnson',
1597
- syen_corporate_phone: 9876543212,
1598
- syen_isactive: true,
1599
- syen_entity_type_gmst: 'institute',
1600
- children: []
1601
- }
1602
- ];
1603
- console.log('🧪 ENTITY LIST: Test data prepared:', testData);
1604
- this.updateGridData(testData);
1605
- this.totalItems.set(testData.length);
1606
- }
1607
- updatePaginationState() {
1608
- const total = Math.ceil(this.totalItems() / this.pageSize());
1609
- this.totalPages.set(total);
1610
- this.hasNextPage.set(this.currentPage() < total);
1611
- this.hasPreviousPage.set(this.currentPage() > 1);
1612
- }
1613
- onSearch() {
1614
- this.currentPage.set(1);
1615
- this.loadEntities();
1616
- }
1617
- onFilterChange() {
1618
- this.currentPage.set(1);
1619
- this.loadEntities();
1620
- }
1621
- onPageChange(page) {
1622
- if (parseInt(page) >= 1 && parseInt(page) <= this.totalPages()) {
1623
- this.currentPage.set(parseInt(page));
1624
- this.loadEntities();
1625
- }
1626
- }
1627
- onPageSizeChange() {
1628
- this.currentPage.set(1);
1629
- this.loadEntities();
1630
- }
1631
- onRefresh() {
1632
- this.loadEntities(true); // Pass true for refresh
1633
- }
1634
- onAddEntity() {
1635
- // Navigate to entity create form
1636
- this.router.navigate(['/control-panel/entity-create']);
1637
- }
1638
- onEditEntity(entity) {
1639
- // TODO: Implement edit functionality - navigate to edit form with entity ID
1640
- this.router.navigate(['/control-panel/entity-create'], {
1641
- queryParams: { id: entity._id, mode: 'edit' }
1642
- });
1643
- console.log('Edit entity:', entity);
1644
- }
1645
- onViewEntity(entity) {
1646
- // TODO: Implement view functionality
1647
- console.log('View entity:', entity);
1648
- }
1649
- onDeleteEntity(entity) {
1650
- if (confirm(`Are you sure you want to delete "${entity.syen_name}"?`)) {
1651
- // TODO: Implement delete functionality
1652
- console.log('Delete entity:', entity);
1653
- }
1654
- }
1655
- getStatusClass(isActive) {
1656
- return isActive
1657
- ? 'tw-bg-green-100 tw-text-green-800'
1658
- : 'tw-bg-red-100 tw-text-red-800';
1659
- }
1660
- getStatusText(isActive) {
1661
- return isActive ? 'Active' : 'Inactive';
1662
- }
1663
- formatDate(date) {
1664
- if (!date)
1665
- return 'N/A';
1666
- return new Date(date).toLocaleDateString();
1667
- }
1668
- // Pagination helper methods
1669
- getPageNumbers() {
1670
- const total = this.totalPages();
1671
- const current = this.currentPage();
1672
- const delta = 2; // Number of pages to show on each side of current page
1673
- const pages = [];
1674
- const start = Math.max(1, current - delta);
1675
- const end = Math.min(total, current + delta);
1676
- for (let i = start; i <= end; i++) {
1677
- pages.push(i);
1678
- }
1679
- return pages;
1680
- }
1681
- getItemRangeText() {
1682
- const start = (this.currentPage() - 1) * this.pageSize() + 1;
1683
- const end = Math.min(this.currentPage() * this.pageSize(), this.totalItems());
1684
- const total = this.totalItems();
1685
- return `${start}-${end} of ${total}`;
1686
- }
1687
- trackByEntityId(index, entity) {
1688
- return entity?._id || '';
1689
- }
1690
- // ===== Enhanced Pagination Methods =====
1691
- /**
1692
- * Get enhanced page numbers with ellipsis for better navigation
1693
- */
1694
- getEnhancedPageNumbers() {
1695
- const total = this.totalPages();
1696
- const current = this.currentPage();
1697
- const pages = [];
1698
- if (total <= 7) {
1699
- // Show all pages if 7 or fewer
1700
- for (let i = 1; i <= total; i++) {
1701
- pages.push(i);
1702
- }
1703
- }
1704
- else {
1705
- // Always show first page
1706
- pages.push(1);
1707
- if (current <= 4) {
1708
- // Current page is near the beginning
1709
- for (let i = 2; i <= 5; i++) {
1710
- pages.push(i);
1711
- }
1712
- pages.push('...');
1713
- pages.push(total);
1714
- }
1715
- else if (current >= total - 3) {
1716
- // Current page is near the end
1717
- pages.push('...');
1718
- for (let i = total - 4; i <= total; i++) {
1719
- pages.push(i);
1720
- }
1721
- }
1722
- else {
1723
- // Current page is in the middle
1724
- pages.push('...');
1725
- for (let i = current - 1; i <= current + 1; i++) {
1726
- pages.push(i);
1727
- }
1728
- pages.push('...');
1729
- pages.push(total);
1730
- }
1731
- }
1732
- return pages;
1733
- }
1734
- /**
1735
- * Calculate progress percentage based on current position
1736
- */
1737
- getProgressPercentage() {
1738
- if (this.totalPages() === 0)
1739
- return 0;
1740
- return Math.round((this.currentPage() / this.totalPages()) * 100);
1741
- }
1742
- /**
1743
- * Jump to specific page functionality
1744
- */
1745
- onJumpToPage() {
1746
- if (this.jumpToPage >= 1 && this.jumpToPage <= this.totalPages()) {
1747
- this.onPageChange(this.jumpToPage);
1748
- }
1749
- }
1750
- /**
1751
- * Get simulated load time for performance display
1752
- */
1753
- getLoadTime() {
1754
- return this.loadStartTime > 0 ? Date.now() - this.loadStartTime : 0;
1755
- }
1756
- /**
1757
- * Get total data size for display
1758
- */
1759
- getTotalDataSize() {
1760
- return this.totalItems();
1761
- }
1762
- /**
1763
- * Export current page entities
1764
- */
1765
- onExportCurrentPage() {
1766
- const currentPageEntities = this.entities();
1767
- console.log('Exporting current page:', currentPageEntities);
1768
- // TODO: Implement actual export functionality
1769
- alert(`Exporting ${currentPageEntities.length} entities from current page`);
1770
- }
1771
- /**
1772
- * Export all entities
1773
- */
1774
- onExportAll() {
1775
- console.log('Exporting all entities');
1776
- // TODO: Implement actual export functionality
1777
- alert(`Exporting all ${this.totalItems()} entities`);
1778
- }
1779
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1780
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideAdmEntityListComponent, isStandalone: true, selector: "cide-adm-entity-list", viewQueries: [{ propertyName: "gridComponent", first: true, predicate: CideEleDataGridComponent, descendants: true }], ngImport: i0, template: "<!-- Entity List Container -->\n<div class=\"entity-list-container tw-bg-white tw-shadow-lg tw-rounded-lg tw-overflow-hidden\">\n \n <!-- Header Section with Filters -->\n <div class=\"tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\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-4 sm:tw-space-y-0\">\n \n <!-- Title -->\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <cide-ele-icon class=\"tw-text-blue-600\">apartment</cide-ele-icon>\n <div>\n <h5 class=\"tw-text-md tw-font-semibold tw-text-gray-900\">Entity Management</h5>\n <p class=\"tw-text-sm tw-text-gray-600\">Manage and view all entities in the system</p>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <!-- Entity Type Filter -->\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <label for=\"entityTypeFilter\" class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Type:</label>\n <cide-ele-select\n id=\"entityTypeFilter\"\n [options]=\"entityTypeOptions()\"\n [(ngModel)]=\"selectedEntityTypeValue\"\n (ngModelChange)=\"loadEntities()\"\n class=\"tw-min-w-40\">\n </cide-ele-select>\n </div>\n\n <!-- Add Entity Button -->\n <button\n cideEleButton\n variant=\"primary\"\n size=\"sm\"\n (click)=\"router.navigate(['control-panel', 'entity-create'])\"\n class=\"tw-whitespace-nowrap tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"xs\" class=\"tw-w-6 tw-h-5\">add</cide-ele-icon>\n Add Entity\n </button>\n </div>\n </div>\n\n <!-- Error Message -->\n @if (error()) {\n <div class=\"tw-mt-4 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\n <div class=\"tw-flex\">\n <cide-ele-icon name=\"exclamation-triangle\" class=\"tw-text-red-400\"></cide-ele-icon>\n <div class=\"tw-ml-3\">\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800\">Error</h3>\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1\">{{ error() }}</p>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Data Grid Component -->\n <cide-ele-data-grid\n [config]=\"gridConfig()\"\n [customRenderers]=\"customRenderers\"\n [actionHandlers]=\"actionHandlers\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n\n</div>", styles: [".entity-list-container table tr{transition:background-color .15s ease}.entity-list-container table th{font-weight:600;letter-spacing:.025em}.entity-list-container table td{vertical-align:top}.entity-list-container .tw-text-red-600:hover{background-color:theme(\"colors.red.50\")}.entity-list-container .tw-animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.entity-list-container .tw-overflow-x-auto{scrollbar-width:thin;scrollbar-color:theme(\"colors.gray.300\") theme(\"colors.gray.100\")}.entity-list-container .tw-overflow-x-auto::-webkit-scrollbar{height:8px}.entity-list-container .tw-overflow-x-auto::-webkit-scrollbar-track{background:theme(\"colors.gray.100\");border-radius:4px}.entity-list-container .tw-overflow-x-auto::-webkit-scrollbar-thumb{background:theme(\"colors.gray.300\");border-radius:4px}.entity-list-container .tw-overflow-x-auto::-webkit-scrollbar-thumb:hover{background:theme(\"colors.gray.400\")}@media (max-width: 768px){.entity-list-container .tw-px-6{padding-left:theme(\"spacing.4\");padding-right:theme(\"spacing.4\")}}\n", ":host{height:100%;display:flex;flex-direction:column}.entity-list-container{height:100%;display:flex;flex-direction:column;overflow:hidden}.tw-overflow-auto{flex:1;min-height:0}cide-ele-data-grid{flex:1;min-height:0;display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: 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"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "customRenderers", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }] });
1781
- }
1782
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideAdmEntityListComponent, decorators: [{
1783
- type: Component,
1784
- args: [{ selector: 'cide-adm-entity-list', standalone: true, imports: [
1785
- CommonModule,
1786
- FormsModule,
1787
- CideInputComponent,
1788
- CideIconComponent,
1789
- CideEleButtonComponent,
1790
- CideSelectComponent,
1791
- TooltipDirective,
1792
- CideEleDataGridComponent
1793
- ], template: "<!-- Entity List Container -->\n<div class=\"entity-list-container tw-bg-white tw-shadow-lg tw-rounded-lg tw-overflow-hidden\">\n \n <!-- Header Section with Filters -->\n <div class=\"tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\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-4 sm:tw-space-y-0\">\n \n <!-- Title -->\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <cide-ele-icon class=\"tw-text-blue-600\">apartment</cide-ele-icon>\n <div>\n <h5 class=\"tw-text-md tw-font-semibold tw-text-gray-900\">Entity Management</h5>\n <p class=\"tw-text-sm tw-text-gray-600\">Manage and view all entities in the system</p>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <!-- Entity Type Filter -->\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <label for=\"entityTypeFilter\" class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Type:</label>\n <cide-ele-select\n id=\"entityTypeFilter\"\n [options]=\"entityTypeOptions()\"\n [(ngModel)]=\"selectedEntityTypeValue\"\n (ngModelChange)=\"loadEntities()\"\n class=\"tw-min-w-40\">\n </cide-ele-select>\n </div>\n\n <!-- Add Entity Button -->\n <button\n cideEleButton\n variant=\"primary\"\n size=\"sm\"\n (click)=\"router.navigate(['control-panel', 'entity-create'])\"\n class=\"tw-whitespace-nowrap tw-flex tw-items-center tw-gap-2\">\n <cide-ele-icon size=\"xs\" class=\"tw-w-6 tw-h-5\">add</cide-ele-icon>\n Add Entity\n </button>\n </div>\n </div>\n\n <!-- Error Message -->\n @if (error()) {\n <div class=\"tw-mt-4 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\n <div class=\"tw-flex\">\n <cide-ele-icon name=\"exclamation-triangle\" class=\"tw-text-red-400\"></cide-ele-icon>\n <div class=\"tw-ml-3\">\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800\">Error</h3>\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1\">{{ error() }}</p>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Data Grid Component -->\n <cide-ele-data-grid\n [config]=\"gridConfig()\"\n [customRenderers]=\"customRenderers\"\n [actionHandlers]=\"actionHandlers\"\n (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n\n</div>", styles: [".entity-list-container table tr{transition:background-color .15s ease}.entity-list-container table th{font-weight:600;letter-spacing:.025em}.entity-list-container table td{vertical-align:top}.entity-list-container .tw-text-red-600:hover{background-color:theme(\"colors.red.50\")}.entity-list-container .tw-animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.entity-list-container .tw-overflow-x-auto{scrollbar-width:thin;scrollbar-color:theme(\"colors.gray.300\") theme(\"colors.gray.100\")}.entity-list-container .tw-overflow-x-auto::-webkit-scrollbar{height:8px}.entity-list-container .tw-overflow-x-auto::-webkit-scrollbar-track{background:theme(\"colors.gray.100\");border-radius:4px}.entity-list-container .tw-overflow-x-auto::-webkit-scrollbar-thumb{background:theme(\"colors.gray.300\");border-radius:4px}.entity-list-container .tw-overflow-x-auto::-webkit-scrollbar-thumb:hover{background:theme(\"colors.gray.400\")}@media (max-width: 768px){.entity-list-container .tw-px-6{padding-left:theme(\"spacing.4\");padding-right:theme(\"spacing.4\")}}\n", ":host{height:100%;display:flex;flex-direction:column}.entity-list-container{height:100%;display:flex;flex-direction:column;overflow:hidden}.tw-overflow-auto{flex:1;min-height:0}cide-ele-data-grid{flex:1;min-height:0;display:flex;flex-direction:column}\n"] }]
1794
- }], propDecorators: { gridComponent: [{
1795
- type: ViewChild,
1796
- args: [CideEleDataGridComponent]
1797
- }] } });
1798
-
1799
- var cideAdmEntityList_component = /*#__PURE__*/Object.freeze({
1800
- __proto__: null,
1801
- CideAdmEntityListComponent: CideAdmEntityListComponent
1802
- });
1803
-
1804
- // import { authGuard } from '../../../../src/app/guards/auth.guard';
1805
41
  const adminRoutes = [{
1806
42
  path: "admin-home",
1807
43
  loadComponent: () => import('./cloud-ide-admin-cide-adm-home-wrapper.component-DpAhYlMT.mjs').then(c => c.CideAdmHomeWrapperComponent),
1808
- // canActivate: [authGuard],
44
+ canActivate: [authGuard],
1809
45
  },
1810
46
  {
1811
47
  path: "home-admin",
1812
48
  loadComponent: () => import('./cloud-ide-admin-cide-adm-home-wrapper.component-DpAhYlMT.mjs').then(c => c.CideAdmHomeWrapperComponent),
1813
- },
1814
- {
1815
- path: "entity-list",
1816
- loadComponent: () => Promise.resolve().then(function () { return cideAdmEntityList_component; }).then(c => c.CideAdmEntityListComponent),
1817
- // canActivate: [authGuard],
1818
- data: {
1819
- reuseTab: true,
1820
- sypg_page_code: "admin_entity_list"
1821
- }
1822
- },
1823
- {
1824
- path: "entity-create",
1825
- loadComponent: () => Promise.resolve().then(function () { return cideAdmEntity_component; }).then(c => c.CideAdmEntityComponent),
1826
- // canActivate: [authGuard],
1827
- data: {
1828
- reuseTab: true,
1829
- sypg_page_code: "core_entity_form"
1830
- }
1831
- },
1832
- {
1833
- path: "entity-create/:query",
1834
- loadComponent: () => Promise.resolve().then(function () { return cideAdmEntity_component; }).then(c => c.CideAdmEntityComponent),
1835
- // canActivate: [authGuard],
1836
- data: {
1837
- reuseTab: true,
1838
- sypg_page_code: "core_entity_form"
1839
- }
49
+ canActivate: [authGuard],
1840
50
  }];
1841
51
 
1842
52
  /*
1843
53
  * Public API Surface of cloud-ide-admin
1844
54
  */
55
+ // Main Admin Service and Component
56
+ // User Master Components (if they exist)
57
+ // export * from './lib/user-master/cide-adm-user-master.component';
58
+ // export * from './lib/user-master/cide-adm-user-master.service';
59
+ // export * from './lib/user-master/cide-adm-user-master-listing.component';
60
+ // export * from './lib/user-master/forms/cide-adm-user-contact-addresses.component';
61
+ // export * from './lib/user-master/forms/cide-adm-user-documents.component';
62
+ // export * from './lib/user-master/forms/cide-adm-user-family-details.component';
63
+ // export * from './lib/user-master/forms/cide-adm-user-attributes.component';
64
+ // export * from './lib/user-master/forms/cide-adm-user-entity-access.component';
1845
65
 
1846
66
  /**
1847
67
  * Generated bundle index. Do not edit.
1848
68
  */
1849
69
 
1850
- export { CideAdmAdminComponent, CideAdmAdminService, CideAdmEntityComponent, CideAdmEntityListComponent, CideAdmEntityService, adminRoutes };
70
+ export { CideAdmAdminComponent, CideAdmAdminService, adminRoutes };
1851
71
  //# sourceMappingURL=cloud-ide-admin.mjs.map