cloud-ide-core 2.0.6 → 2.0.7
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.
- package/fesm2022/cloud-ide-core.mjs +1112 -294
- package/fesm2022/cloud-ide-core.mjs.map +1 -1
- package/index.d.ts +163 -28
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { authGuard } from 'cloud-ide-auth';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { Injectable, Component, inject, DestroyRef, viewChild, signal, computed,
|
|
3
|
+
import { Injectable, Component, inject, DestroyRef, viewChild, signal, computed, ChangeDetectorRef, ViewChild } from '@angular/core';
|
|
4
4
|
import * as i1$1 from '@angular/common';
|
|
5
5
|
import { CommonModule } from '@angular/common';
|
|
6
6
|
import * as i1$2 from '@angular/forms';
|
|
@@ -9,11 +9,11 @@ import { Router, ActivatedRoute } from '@angular/router';
|
|
|
9
9
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
10
10
|
import { BehaviorSubject, throwError, Observable, Subject, takeUntil, debounceTime, distinctUntilChanged } from 'rxjs';
|
|
11
11
|
import { tap, catchError, map } from 'rxjs/operators';
|
|
12
|
-
import { coreRoutesUrl, generateStringFromObject, cidePath, hostManagerRoutesUrl, MDesignationInsertUpdatePayload, generateObjectFromString, userRoutesUrl, AuthUserMstGetByIdPayload, customEncrypt, AuthUserMstListPayload } from 'cloud-ide-lms-model';
|
|
12
|
+
import { coreRoutesUrl, generateStringFromObject, cidePath, hostManagerRoutesUrl, MDesignationInsertUpdatePayload, generateObjectFromString, userRoutesUrl, AuthUserMstGetByIdPayload, customEncrypt, customDecrypt, AuthUserMstListPayload } from 'cloud-ide-lms-model';
|
|
13
13
|
import * as i1 from '@angular/common/http';
|
|
14
14
|
import { HttpClient } from '@angular/common/http';
|
|
15
|
-
import { NotificationService, CideEleDataGridComponent, CideEleButtonComponent, CideInputComponent, CideSelectComponent, CideTextareaComponent, CideIconComponent, CideEleDropdownComponent, ConfirmationService, CideEleGlobalNotificationsComponent, CideEleConfirmationModalComponent, CideEleJsonEditorComponent,
|
|
16
|
-
import { AppStateHelperService } from 'cloud-ide-layout';
|
|
15
|
+
import { NotificationService, CideEleDataGridComponent, CideEleButtonComponent, CideInputComponent, CideSelectComponent, CideTextareaComponent, CideIconComponent, CideEleDropdownComponent, ConfirmationService, CideEleGlobalNotificationsComponent, CideEleConfirmationModalComponent, CideEleJsonEditorComponent, CideEleFileInputComponent, CideEleFileImageDirective, CideEleFileManagerService, CideEleTabComponent } from 'cloud-ide-element';
|
|
16
|
+
import { AppStateHelperService, CideLytFloatingUploadService, CideLytFloatingUploadTriggerDirective } from 'cloud-ide-layout';
|
|
17
17
|
|
|
18
18
|
const coreRoutes = [
|
|
19
19
|
{
|
|
@@ -1361,12 +1361,17 @@ class MenuListComponent {
|
|
|
1361
1361
|
*/
|
|
1362
1362
|
onRowReorder(data) {
|
|
1363
1363
|
console.log('🔄 Row reorder event:', data);
|
|
1364
|
+
console.log('🔄 Changed items (newOrder):', data.newOrder.length);
|
|
1365
|
+
console.log('🔄 All items (allOrders):', data.allOrders?.length || 0);
|
|
1364
1366
|
// Save original order if not already saved
|
|
1365
1367
|
if (this.originalOrder().length === 0) {
|
|
1366
1368
|
this.originalOrder.set([...this.menuItems()]);
|
|
1367
1369
|
}
|
|
1370
|
+
// Use allOrders if available (complete order), otherwise fallback to newOrder (changed items only)
|
|
1371
|
+
const reorderedData = data.allOrders && data.allOrders.length > 0 ? data.allOrders : data.newOrder;
|
|
1372
|
+
console.log('🔄 Using reordered data with', reorderedData.length, 'items');
|
|
1368
1373
|
// Update the displayed data with new order
|
|
1369
|
-
this.menuItems.set(
|
|
1374
|
+
this.menuItems.set(reorderedData);
|
|
1370
1375
|
// Mark that order has changed
|
|
1371
1376
|
this.hasOrderChanged.set(true);
|
|
1372
1377
|
// Update grid data
|
|
@@ -1386,25 +1391,33 @@ class MenuListComponent {
|
|
|
1386
1391
|
/**
|
|
1387
1392
|
* Save menu order using the change sequence API
|
|
1388
1393
|
* This method is called by the data grid when save-order action is triggered
|
|
1394
|
+
* Handles both single-level and multi-level (hierarchical) menu structures
|
|
1389
1395
|
*/
|
|
1390
1396
|
saveMenuOrder() {
|
|
1391
1397
|
console.log('💾 Saving menu order...');
|
|
1392
|
-
//
|
|
1398
|
+
// Get all menu items including children (handle both hierarchical and flat structures)
|
|
1399
|
+
const allMenuItems = this.getAllMenuItemsIncludingChildren(this.menuItems());
|
|
1400
|
+
// Update sequence numbers for all items based on their current order
|
|
1401
|
+
const itemsWithUpdatedSequences = allMenuItems.map((item, index) => ({
|
|
1402
|
+
...item,
|
|
1403
|
+
syme_order_by: index + 1
|
|
1404
|
+
}));
|
|
1405
|
+
// Prepare payload for change sequence API with all menu items (including children)
|
|
1393
1406
|
const payload = {
|
|
1394
|
-
menu_sequences:
|
|
1407
|
+
menu_sequences: itemsWithUpdatedSequences.map(item => ({
|
|
1395
1408
|
syme_id: item._id || '',
|
|
1396
1409
|
syme_order_by: item.syme_order_by || 1
|
|
1397
1410
|
}))
|
|
1398
1411
|
};
|
|
1399
|
-
console.log('📤 Sending change sequence payload:', payload);
|
|
1412
|
+
console.log('📤 Sending change sequence payload for', itemsWithUpdatedSequences.length, 'items:', payload);
|
|
1400
1413
|
// Call the change sequence API
|
|
1401
1414
|
this.menuService.changeMenuSequence(payload)
|
|
1402
1415
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1403
1416
|
.subscribe({
|
|
1404
1417
|
next: (response) => {
|
|
1405
1418
|
if (response.success) {
|
|
1406
|
-
console.log('✅ Menu sequence updated successfully');
|
|
1407
|
-
this.notificationService.success(
|
|
1419
|
+
console.log('✅ Menu sequence updated successfully for', itemsWithUpdatedSequences.length, 'items');
|
|
1420
|
+
this.notificationService.success(`Menu sequence updated successfully for ${itemsWithUpdatedSequences.length} items`);
|
|
1408
1421
|
// Reset change flag first
|
|
1409
1422
|
this.hasOrderChanged.set(false);
|
|
1410
1423
|
// Update original order to current state
|
|
@@ -1425,6 +1438,50 @@ class MenuListComponent {
|
|
|
1425
1438
|
}
|
|
1426
1439
|
});
|
|
1427
1440
|
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Get all menu items including children from the current data structure
|
|
1443
|
+
* This handles both hierarchical and flat menu structures
|
|
1444
|
+
*/
|
|
1445
|
+
getAllMenuItemsIncludingChildren(menuItems) {
|
|
1446
|
+
const allItems = [];
|
|
1447
|
+
const processedIds = new Set();
|
|
1448
|
+
const collectItems = (items) => {
|
|
1449
|
+
items.forEach(item => {
|
|
1450
|
+
// Avoid duplicates by checking if item is already processed
|
|
1451
|
+
if (item._id && !processedIds.has(item._id)) {
|
|
1452
|
+
allItems.push(item);
|
|
1453
|
+
processedIds.add(item._id);
|
|
1454
|
+
// Check if item has children property (for hierarchical data from data grid)
|
|
1455
|
+
if (item.children && item.children.length > 0) {
|
|
1456
|
+
collectItems(item.children);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
};
|
|
1461
|
+
// For flat data structure (which is what data grid sends), just return all items
|
|
1462
|
+
// since they're already in the correct order
|
|
1463
|
+
if (this.isFlatDataStructure(menuItems)) {
|
|
1464
|
+
console.log('🔄 Detected flat data structure, returning all items as-is');
|
|
1465
|
+
return menuItems;
|
|
1466
|
+
}
|
|
1467
|
+
// For hierarchical data structure, collect all items recursively
|
|
1468
|
+
collectItems(menuItems);
|
|
1469
|
+
console.log('🔄 Collected', allItems.length, 'menu items including children');
|
|
1470
|
+
console.log('📊 Items structure:', allItems.map(item => ({
|
|
1471
|
+
id: item._id,
|
|
1472
|
+
title: item.syme_title,
|
|
1473
|
+
parent: item.syme_id_syme,
|
|
1474
|
+
hasChildren: item.children ? item.children.length : 0
|
|
1475
|
+
})));
|
|
1476
|
+
return allItems;
|
|
1477
|
+
}
|
|
1478
|
+
/**
|
|
1479
|
+
* Check if the data structure is flat (no children property) or hierarchical
|
|
1480
|
+
*/
|
|
1481
|
+
isFlatDataStructure(menuItems) {
|
|
1482
|
+
// If any item has a children property with items, it's hierarchical
|
|
1483
|
+
return !menuItems.some(item => item.children && item.children.length > 0);
|
|
1484
|
+
}
|
|
1428
1485
|
/**
|
|
1429
1486
|
* Reset drag order to original state
|
|
1430
1487
|
*/
|
|
@@ -1969,7 +2026,9 @@ class MenuListComponent {
|
|
|
1969
2026
|
* Load user rights type ID from general master types
|
|
1970
2027
|
*/
|
|
1971
2028
|
loadUserRightsTypeId() {
|
|
1972
|
-
this.generalMasterTypeService.getTypeList({
|
|
2029
|
+
this.generalMasterTypeService.getTypeList({
|
|
2030
|
+
sygmt_code: "user_rights"
|
|
2031
|
+
})
|
|
1973
2032
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1974
2033
|
.subscribe({
|
|
1975
2034
|
next: (response) => {
|
|
@@ -6327,20 +6386,6 @@ class CideCorePageThemeComponent {
|
|
|
6327
6386
|
return title.includes(q) || code.includes(q) || desc.includes(q);
|
|
6328
6387
|
});
|
|
6329
6388
|
}, ...(ngDevMode ? [{ debugName: "filteredThemes" }] : []));
|
|
6330
|
-
// Helper to resolve preview image URL safely
|
|
6331
|
-
getPreviewUrl(theme) {
|
|
6332
|
-
const id = theme?.sytm_preview_id_fm || '';
|
|
6333
|
-
if (!id)
|
|
6334
|
-
return '';
|
|
6335
|
-
const svcUnknown = this.themeService;
|
|
6336
|
-
const hasGetPreviewUrl = (svc) => typeof svc === 'object' && svc !== null &&
|
|
6337
|
-
'getPreviewUrl' in svc &&
|
|
6338
|
-
typeof svc['getPreviewUrl'] === 'function';
|
|
6339
|
-
if (hasGetPreviewUrl(svcUnknown)) {
|
|
6340
|
-
return svcUnknown.getPreviewUrl(id);
|
|
6341
|
-
}
|
|
6342
|
-
return '';
|
|
6343
|
-
}
|
|
6344
6389
|
// Input handler to avoid $any casts in template
|
|
6345
6390
|
onGallerySearchInput(event) {
|
|
6346
6391
|
const target = event.target;
|
|
@@ -6844,12 +6889,26 @@ class CideCorePageThemeComponent {
|
|
|
6844
6889
|
*/
|
|
6845
6890
|
cancelForm() {
|
|
6846
6891
|
this.resetForm();
|
|
6892
|
+
this.goBack();
|
|
6847
6893
|
}
|
|
6848
6894
|
/**
|
|
6849
6895
|
* Go back to page list
|
|
6850
6896
|
*/
|
|
6851
6897
|
goBack() {
|
|
6852
|
-
|
|
6898
|
+
console.log('🔍 [PageThemeComponent] goBack() called');
|
|
6899
|
+
console.log('🔍 [PageThemeComponent] Current route:', this.router.url);
|
|
6900
|
+
// Try to navigate back to the page management route
|
|
6901
|
+
this.router.navigate(['/core/page']).then(success => {
|
|
6902
|
+
console.log('🔍 [PageThemeComponent] Navigation result:', success);
|
|
6903
|
+
if (!success) {
|
|
6904
|
+
console.log('🔍 [PageThemeComponent] Navigation failed, using browser back');
|
|
6905
|
+
window.history.back();
|
|
6906
|
+
}
|
|
6907
|
+
}).catch(error => {
|
|
6908
|
+
console.error('🔍 [PageThemeComponent] Navigation error:', error);
|
|
6909
|
+
// Fallback: try to go back in browser history
|
|
6910
|
+
window.history.back();
|
|
6911
|
+
});
|
|
6853
6912
|
}
|
|
6854
6913
|
/**
|
|
6855
6914
|
* Reset form
|
|
@@ -7024,8 +7083,33 @@ class CideCorePageThemeComponent {
|
|
|
7024
7083
|
error: () => { this.loading.set(false); }
|
|
7025
7084
|
});
|
|
7026
7085
|
}
|
|
7086
|
+
// File upload methods for preview image
|
|
7087
|
+
getPreviewImageUploadData() {
|
|
7088
|
+
return {
|
|
7089
|
+
altText: 'Theme Preview Image',
|
|
7090
|
+
cyfm_name: 'theme-preview-image',
|
|
7091
|
+
cyfm_alt_text: 'Theme Preview Image',
|
|
7092
|
+
cyfm_type: 'image',
|
|
7093
|
+
cyfm_permissions: ['read'],
|
|
7094
|
+
cyfm_tags: ['theme', 'preview', 'image']
|
|
7095
|
+
};
|
|
7096
|
+
}
|
|
7097
|
+
onPreviewImageUploadSuccess(fileId) {
|
|
7098
|
+
console.log('Preview image uploaded successfully:', fileId);
|
|
7099
|
+
// Update the form control with the uploaded file ID
|
|
7100
|
+
this.themeForm.patchValue({
|
|
7101
|
+
sytm_preview_id_fm: fileId
|
|
7102
|
+
});
|
|
7103
|
+
}
|
|
7104
|
+
onPreviewImageUploadError(error) {
|
|
7105
|
+
console.error('Preview image upload error:', error);
|
|
7106
|
+
this.error.set('Failed to upload preview image: ' + error);
|
|
7107
|
+
}
|
|
7108
|
+
onPreviewImageUploadProgress(progress) {
|
|
7109
|
+
console.log('Preview image upload progress:', progress + '%');
|
|
7110
|
+
}
|
|
7027
7111
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideCorePageThemeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7028
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideCorePageThemeComponent, isStandalone: true, selector: "cide-core-page-theme", viewQueries: [{ propertyName: "themeDetailsRendererTemplate", first: true, predicate: ["themeDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "themeStatusRendererTemplate", first: true, predicate: ["themeStatusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Page Theme Container -->\r\n<div class=\"tw-flex tw-h-full tw-w-full\">\r\n \r\n <!-- Left: Form and header (60%) -->\r\n <div class=\"tw-w-full lg:tw-w-3/5 tw-flex tw-flex-col tw-border-r tw-border-gray-200\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n\r\n <!-- Title and Back Button -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-4\">\r\n <button cideEleButton variant=\"ghost\" size=\"sm\" (click)=\"goBack()\" class=\"tw-text-gray-600 hover:tw-text-gray-900\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_back</cide-ele-icon>\r\n </button>\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">palette</cide-ele-icon>\r\n <div>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Theme Management</h5>\r\n <p class=\"tw-text-sm tw-text-gray-500 tw-m-0\">Page: {{ pageTitle() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n @if (error()) {\r\n <div class=\"tw-mt-4 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\r\n <div class=\"tw-flex tw-items-start\">\r\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\r\n <div class=\"tw-ml-3\">\r\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\r\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Quick Add/Edit Form Section -->\r\n <div class=\"tw-px-6 tw-py-4 tw-bg-white tw-overflow-auto\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\r\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">{{ isEditMode() ? 'edit' : 'add' }}</cide-ele-icon>\r\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-m-0\">{{ isEditMode() ? 'Edit Theme' : 'Quick Add Theme' }}</h6>\r\n </div>\r\n </div>\r\n\r\n <!-- Form (kept as-is) -->\r\n <form [formGroup]=\"themeForm\" (ngSubmit)=\"saveTheme()\" class=\"tw-space-y-4\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-3 tw-gap-4\">\r\n <!-- Theme Title -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_title\" formControlName=\"sytm_title\" placeholder=\"Enter theme title\" label=\"Theme Title*\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <!-- Theme Code -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_theme_code\" formControlName=\"sytm_theme_code\" placeholder=\"Enter theme code\" label=\"Theme Code*\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <!-- Status -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input\r\n id=\"sytm_isactive_cb\"\r\n type=\"checkbox\"\r\n label=\"Active\"\r\n size=\"sm\"\r\n formControlName=\"sytm_isactive\">\r\n </cide-ele-input>\r\n </div>\r\n <!-- Sub Title -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_sub_title\" formControlName=\"sytm_sub_title\" placeholder=\"Enter sub title\" label=\"Sub Title\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <!-- Preview ID -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_preview_id_fm\" formControlName=\"sytm_preview_id_fm\" placeholder=\"Enter preview image ID\" label=\"Preview Image ID\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <!-- Description -->\r\n <div class=\"tw-space-y-2 md:tw-col-span-2\">\r\n <cide-ele-textarea id=\"sytm_desc\" formControlName=\"sytm_desc\" placeholder=\"Enter theme description\" rows=\"2\" label=\"Description\" size=\"sm\"></cide-ele-textarea>\r\n </div>\r\n <!-- Configuration JSON -->\r\n <div class=\"tw-space-y-2 md:tw-col-span-3\">\r\n <cide-ele-json-editor label=\"Configuration JSON\" formControlName=\"sytm_configuration\" [required]=\"true\" [config]=\"{\r\n showLineNumbers: true,\r\n autoFormat: true,\r\n validateOnChange: true,\r\n minHeight: 150,\r\n maxHeight: 300,\r\n placeholder: 'Enter theme configuration JSON...'\r\n }\" helperText=\"Enter valid JSON configuration for the theme\"></cide-ele-json-editor>\r\n </div>\r\n <!-- Layout Configuration + Selection: right-side checkbox list -->\r\n <div class=\"lg:tw-col-span-1 tw-space-y-2\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Layout & Selection</div>\r\n <!-- Selected toggle -->\r\n <div class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-md tw-px-3 tw-py-2\">\r\n <cide-ele-input\r\n id=\"sytm_isselected\"\r\n type=\"checkbox\"\r\n label=\"Selected (Default)\"\r\n size=\"sm\"\r\n formControlName=\"sytm_isselected\">\r\n </cide-ele-input>\r\n </div>\r\n <div formGroupName=\"sytm_layout\" class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-md tw-divide-y tw-overflow-hidden\">\r\n <!-- Sidebar -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_sidebar\">\r\n <cide-ele-input id=\"layout_sidebar_status\" type=\"checkbox\" label=\"Sidebar\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Header -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_header\">\r\n <cide-ele-input id=\"layout_header_status\" type=\"checkbox\" label=\"Header\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Footer -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_footer\">\r\n <cide-ele-input id=\"layout_footer_status\" type=\"checkbox\" label=\"Footer\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Breadcrumb -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_breadcrumb\">\r\n <cide-ele-input id=\"layout_breadcrumb_status\" type=\"checkbox\" label=\"Breadcrumb\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Console -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_console\">\r\n <cide-ele-input id=\"layout_console_status\" type=\"checkbox\" label=\"Console\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Request -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_request\">\r\n <cide-ele-input id=\"layout_request_status\" type=\"checkbox\" label=\"Request\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n </div>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-pt-1\">Toggle active sections. Only one theme can be selected as default. More options can be added here later.</p>\r\n </div>\r\n <!-- Drawer Configuration -->\r\n <div class=\"tw-space-y-2 md:tw-col-span-3\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Drawers</div>\r\n <button cideEleButton type=\"button\" size=\"xs\" variant=\"outline\" (click)=\"addDrawer()\">\r\n Add Drawer\r\n </button>\r\n </div>\r\n\r\n <div formGroupName=\"sytm_layout\">\r\n <div class=\"tw-space-y-2\" formArrayName=\"sytm_layout_drawer\">\r\n <div *ngFor=\"let drawerGrp of drawerArray.controls; let i = index\" [formGroupName]=\"i\" class=\"tw-border tw-border-gray-200 tw-rounded-md tw-p-3 tw-flex tw-items-center tw-gap-3\">\r\n <cide-ele-input id=\"drawer_active_{{i}}\" type=\"checkbox\" label=\"Active\" size=\"sm\" formControlName=\"syth_status\"></cide-ele-input>\r\n <div class=\"tw-flex-1\">\r\n <cide-ele-select\r\n id=\"drawer_config_{{i}}\"\r\n label=\"Drawer For\"\r\n size=\"sm\"\r\n [options]=\"drawerConfigOptions\"\r\n formControlName=\"syth_config_syco_for\">\r\n </cide-ele-select>\r\n </div>\r\n <button cideEleButton type=\"button\" size=\"xs\" variant=\"ghost\" (click)=\"removeDrawer(i)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">delete</cide-ele-icon>\r\n </button>\r\n </div>\r\n <p class=\"tw-text-xs tw-text-gray-500\">Configure multiple drawers as needed.</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Form Actions -->\r\n <div class=\"tw-flex tw-flex-col tw-gap-2 tw-pt-4 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-flex tw-items-center tw-justify-end tw-space-x-3\">\r\n <button cideEleButton type=\"button\" variant=\"outline\" (click)=\"cancelForm()\" [disabled]=\"loading()\">Cancel</button>\r\n <button cideEleButton type=\"submit\" variant=\"primary\" leftIcon=\"add\" [disabled]=\"!themeForm.valid || loading()\" [loading]=\"loading()\">\r\n {{ isEditMode() ? 'Update Theme' : 'Create Theme' }}\r\n </button>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n\r\n <!-- Right: Theme gallery (40%) -->\r\n <div class=\"tw-hidden lg:tw-flex tw-w-2/5 tw-flex-col\">\r\n <!-- (Header consolidated above) -->\r\n\r\n <!-- Gallery list -->\r\n <div class=\"tw-flex-1 tw-overflow-auto tw-bg-gray-50\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-p-4\">\r\n @for (theme of filteredThemes(); track theme._id) {\r\n <div class=\"tw-rounded-md tw-transition tw-cursor-pointer tw-relative\"\r\n [ngClass]=\"theme.sytm_isselected\r\n ? 'tw-border tw-border-blue-500 tw-ring-2 tw-ring-blue-200 tw-bg-blue-50/50'\r\n : 'tw-bg-white tw-border tw-border-gray-200 hover:tw-shadow-sm'\"\r\n (click)=\"editTheme(theme)\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n [attr.aria-selected]=\"theme.sytm_isselected ? 'true' : 'false'\"\r\n [attr.aria-label]=\"'Edit theme ' + (theme.sytm_title || theme.sytm_theme_code)\"\r\n (keydown.enter)=\"editTheme(theme)\"\r\n (keydown.space)=\"$event.preventDefault(); editTheme(theme)\">\r\n\r\n <!-- Selected badge -->\r\n <div *ngIf=\"theme.sytm_isselected\"\r\n class=\"tw-absolute tw-top-2 tw-right-2 tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-rounded-full tw-bg-blue-600 tw-text-white\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">check</cide-ele-icon>\r\n </div>\r\n \r\n <div class=\"tw-aspect-[16/9] tw-bg-gray-100 tw-rounded-t-md tw-overflow-hidden tw-flex tw-items-center tw-justify-center\">\r\n @if (getPreviewUrl(theme)) {\r\n <img [src]=\"getPreviewUrl(theme)\" class=\"tw-w-full tw-h-full tw-object-cover\" alt=\"Preview\" />\r\n } @else {\r\n <div class=\"tw-text-gray-400 tw-text-xs\">No preview</div>\r\n }\r\n </div>\r\n <div class=\"tw-p-3 tw-space-y-1\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\" [title]=\"theme.sytm_title\">{{ theme.sytm_title || 'Untitled Theme' }}</div>\r\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate\" [title]=\"theme.sytm_theme_code\">{{ theme.sytm_theme_code }}</div>\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-pt-1\">\r\n <span class=\"tw-inline-flex tw-items-center tw-gap-1 tw-text-xs\" [ngClass]=\"theme.sytm_isactive ? 'tw-text-green-700' : 'tw-text-red-700'\">\r\n <span class=\"tw-w-1.5 tw-h-1.5 tw-rounded-full\" [ngClass]=\"theme.sytm_isactive ? 'tw-bg-green-500' : 'tw-bg-red-500'\"></span>\r\n {{ theme.sytm_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n <div class=\"tw-flex tw-items-center tw-gap-1\">\r\n <!-- Set Selected Button - Clear and Simple -->\r\n @if (theme.sytm_isselected) {\r\n <span class=\"tw-inline-flex tw-items-center tw-gap-1 tw-px-2 tw-py-1 tw-bg-green-100 tw-text-green-800 tw-rounded-md tw-text-xs tw-font-medium\">\r\n <cide-ele-icon class=\"tw-w-3 tw-h-3\">check</cide-ele-icon>\r\n Selected\r\n </span>\r\n } @else {\r\n <button cideEleButton \r\n variant=\"outline\" \r\n size=\"xs\"\r\n (click)=\"$event.stopPropagation(); setSelectedTheme(theme)\"\r\n [attr.aria-label]=\"'Select ' + (theme.sytm_title || theme.sytm_theme_code) + ' theme'\"\r\n class=\"tw-text-xs\">\r\n Select\r\n </button>\r\n }\r\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"$event.stopPropagation(); editTheme(theme)\"\r\n [attr.aria-label]=\"'Edit theme ' + (theme.sytm_title || theme.sytm_theme_code)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">edit</cide-ele-icon>\r\n </button>\r\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"$event.stopPropagation(); deleteTheme(theme)\"\r\n [attr.aria-label]=\"'Delete theme ' + (theme.sytm_title || theme.sytm_theme_code)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">delete</cide-ele-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (!loading() && filteredThemes().length === 0) {\r\n <div class=\"tw-col-span-full tw-text-center tw-text-xs tw-text-gray-500 tw-py-8\">No themes found</div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- \r\n Angular Template References for Grid Renderers (Best Practice)\r\n \r\n These ng-template elements represent the Angular best practice for custom rendering.\r\n They provide:\r\n - Type safety with template context\r\n - Component lifecycle integration\r\n - Change detection optimization\r\n - Proper event handling\r\n - Accessibility features\r\n \r\n Note: Current data grid uses string renderers for compatibility.\r\n Templates are maintained for future component enhancement.\r\n-->\r\n\r\n<!-- Theme Details Renderer Template -->\r\n<ng-template #themeDetailsRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <div class=\"tw-flex tw-items-center tw-min-w-0\">\r\n <!-- Theme Icon -->\r\n <div class=\"tw-flex-shrink-0\">\r\n <cide-ele-icon \r\n class=\"tw-text-purple-600\" \r\n size=\"xs\">\r\n palette\r\n </cide-ele-icon>\r\n </div>\r\n \r\n <!-- Theme Details -->\r\n <div class=\"tw-ml-3 tw-min-w-0 tw-flex-1\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\" \r\n [title]=\"row.sytm_title\">\r\n {{ row.sytm_title || 'Untitled' }}\r\n </div>\r\n @if (row.sytm_desc) {\r\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate\" \r\n [title]=\"row.sytm_desc\">\r\n {{ row.sytm_desc }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n</ng-template>\r\n\r\n<!-- Theme Status Renderer Template -->\r\n<ng-template #themeStatusRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <span class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-whitespace-nowrap\"\r\n [ngClass]=\"row.sytm_isactive ? 'tw-bg-green-100 tw-text-green-800' : 'tw-bg-red-100 tw-text-red-800'\">\r\n {{ row.sytm_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n</ng-template>\r\n\r\n<!-- Actions Dropdown Renderer Template -->\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown \r\n [items]=\"getActionDropdownItems(row)\"\r\n [config]=\"{ triggerIcon: 'more_vert', triggerSize: 'sm' }\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template> ", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: FormsModule }, { 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: 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", "valueKey", "labelKey"], 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: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }, { kind: "component", type: CideEleJsonEditorComponent, selector: "cide-ele-json-editor", inputs: ["label", "helperText", "required", "disabled", "showCharacterCount", "config"], outputs: ["valueChange", "objectChange", "errorsChange", "validChange"] }] });
|
|
7112
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideCorePageThemeComponent, isStandalone: true, selector: "cide-core-page-theme", viewQueries: [{ propertyName: "themeDetailsRendererTemplate", first: true, predicate: ["themeDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "themeStatusRendererTemplate", first: true, predicate: ["themeStatusRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "actionsDropdownRendererTemplate", first: true, predicate: ["actionsDropdownRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Page Theme Container -->\r\n<div class=\"tw-flex tw-h-full tw-w-full\">\r\n \r\n <!-- Left: Form and header (60%) -->\r\n <div class=\"tw-w-full lg:tw-w-3/5 tw-flex tw-flex-col tw-border-r tw-border-gray-200\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-px-6 tw-py-2 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-2 sm:tw-space-y-0\">\r\n\r\n <!-- Title and Back Button -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-4\">\r\n <button cideEleButton variant=\"ghost\" size=\"sm\" (click)=\"goBack();\" class=\"tw-text-gray-600 hover:tw-text-gray-900\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_back</cide-ele-icon>\r\n </button>\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">palette</cide-ele-icon>\r\n <div>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Theme Management</h5>\r\n <p class=\"tw-text-sm tw-text-gray-500 tw-m-0\">Page: {{ pageTitle() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n @if (error()) {\r\n <div class=\"tw-mt-4 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\r\n <div class=\"tw-flex tw-items-start\">\r\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\r\n <div class=\"tw-ml-3\">\r\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\r\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Quick Add/Edit Form Section -->\r\n <div class=\"tw-px-6 tw-py-3 tw-bg-white tw-overflow-auto\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\r\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">{{ isEditMode() ? 'edit' : 'add' }}</cide-ele-icon>\r\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-m-0\">{{ isEditMode() ? 'Edit Theme' : 'Quick Add Theme' }}</h6>\r\n </div>\r\n </div>\r\n\r\n <!-- Form (kept as-is) -->\r\n <form [formGroup]=\"themeForm\" (ngSubmit)=\"saveTheme()\" class=\"tw-space-y-4\">\r\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-[1fr_200px] tw-gap-4\">\r\n <!-- Left Side: All Input Fields -->\r\n <div class=\"tw-space-y-4\">\r\n <!-- Row 1: Theme Title and Theme Code -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_title\" formControlName=\"sytm_title\" placeholder=\"Enter theme title\" label=\"Theme Title*\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_theme_code\" formControlName=\"sytm_theme_code\" placeholder=\"Enter theme code\" label=\"Theme Code*\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n </div>\r\n \r\n <!-- Row 2: Sub Title and Active Status -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_sub_title\" formControlName=\"sytm_sub_title\" placeholder=\"Enter sub title\" label=\"Sub Title\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <div class=\"tw-space-y-2 tw-flex tw-items-center\">\r\n <cide-ele-input\r\n id=\"sytm_isactive_cb\"\r\n type=\"checkbox\"\r\n label=\"Active\"\r\n size=\"sm\"\r\n formControlName=\"sytm_isactive\">\r\n </cide-ele-input>\r\n </div>\r\n </div>\r\n \r\n <!-- Row 3: Description -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-textarea id=\"sytm_desc\" formControlName=\"sytm_desc\" placeholder=\"Enter theme description\" rows=\"2\" label=\"Description\" size=\"sm\"></cide-ele-textarea>\r\n </div>\r\n </div>\r\n \r\n <!-- Right Side: File Upload -->\r\n <div class=\"tw-flex tw-flex-col tw-justify-start tw-items-center tw-p-0\">\r\n <cide-ele-file-input \r\n id=\"sytm_preview_id_fm\" \r\n formControlName=\"sytm_preview_id_fm\"\r\n accept=\"image/*\"\r\n [showPreview]=\"true\"\r\n [previewBoxMode]=\"true\"\r\n [showFileName]=\"false\"\r\n previewWidth=\"180px\"\r\n previewHeight=\"120px\"\r\n placeholderText=\"Upload Preview Image\"\r\n placeholderIcon=\"image\"\r\n [autoUpload]=\"true\"\r\n [uploadData]=\"getPreviewImageUploadData()\"\r\n (uploadSuccess)=\"onPreviewImageUploadSuccess($event)\"\r\n (uploadError)=\"onPreviewImageUploadError($event)\"\r\n (uploadProgressChange)=\"onPreviewImageUploadProgress($event)\">\r\n </cide-ele-file-input>\r\n </div>\r\n </div>\r\n \r\n <!-- Configuration JSON -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-json-editor label=\"Configuration JSON\" formControlName=\"sytm_configuration\" [required]=\"true\" [config]=\"{\r\n showLineNumbers: true,\r\n autoFormat: true,\r\n validateOnChange: true,\r\n minHeight: 150,\r\n maxHeight: 300,\r\n placeholder: 'Enter theme configuration JSON...'\r\n }\" helperText=\"Enter valid JSON configuration for the theme\"></cide-ele-json-editor>\r\n </div>\r\n <!-- Layout Configuration + Selection -->\r\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-6\">\r\n <div class=\"tw-space-y-2\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Layout & Selection</div>\r\n <!-- Selected toggle -->\r\n <div class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-md tw-px-3 tw-py-2\">\r\n <cide-ele-input\r\n id=\"sytm_isselected\"\r\n type=\"checkbox\"\r\n label=\"Selected (Default)\"\r\n size=\"sm\"\r\n formControlName=\"sytm_isselected\">\r\n </cide-ele-input>\r\n </div>\r\n <div formGroupName=\"sytm_layout\" class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-md tw-divide-y tw-overflow-hidden\">\r\n <!-- Sidebar -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_sidebar\">\r\n <cide-ele-input id=\"layout_sidebar_status\" type=\"checkbox\" label=\"Sidebar\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Header -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_header\">\r\n <cide-ele-input id=\"layout_header_status\" type=\"checkbox\" label=\"Header\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Footer -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_footer\">\r\n <cide-ele-input id=\"layout_footer_status\" type=\"checkbox\" label=\"Footer\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Breadcrumb -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_breadcrumb\">\r\n <cide-ele-input id=\"layout_breadcrumb_status\" type=\"checkbox\" label=\"Breadcrumb\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Console -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_console\">\r\n <cide-ele-input id=\"layout_console_status\" type=\"checkbox\" label=\"Console\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Request -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_request\">\r\n <cide-ele-input id=\"layout_request_status\" type=\"checkbox\" label=\"Request\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n </div>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-pt-1\">Toggle active sections. Only one theme can be selected as default. More options can be added here later.</p>\r\n </div>\r\n \r\n <!-- Drawer Configuration -->\r\n <div class=\"tw-space-y-2\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Drawers</div>\r\n <button cideEleButton type=\"button\" size=\"xs\" variant=\"outline\" (click)=\"addDrawer()\">\r\n Add Drawer\r\n </button>\r\n </div>\r\n\r\n <div formGroupName=\"sytm_layout\">\r\n <div class=\"tw-space-y-2\" formArrayName=\"sytm_layout_drawer\">\r\n <div *ngFor=\"let drawerGrp of drawerArray.controls; let i = index\" [formGroupName]=\"i\" class=\"tw-border tw-border-gray-200 tw-rounded-md tw-p-3 tw-flex tw-items-center tw-gap-3\">\r\n <cide-ele-input id=\"drawer_active_{{i}}\" type=\"checkbox\" label=\"Active\" size=\"sm\" formControlName=\"syth_status\"></cide-ele-input>\r\n <div class=\"tw-flex-1\">\r\n <cide-ele-select\r\n id=\"drawer_config_{{i}}\"\r\n label=\"Drawer For\"\r\n size=\"sm\"\r\n [options]=\"drawerConfigOptions\"\r\n formControlName=\"syth_config_syco_for\">\r\n </cide-ele-select>\r\n </div>\r\n <button cideEleButton type=\"button\" size=\"xs\" variant=\"ghost\" (click)=\"removeDrawer(i)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">delete</cide-ele-icon>\r\n </button>\r\n </div>\r\n <p class=\"tw-text-xs tw-text-gray-500\">Configure multiple drawers as needed.</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Form Actions -->\r\n <div class=\"tw-flex tw-flex-col tw-gap-2 tw-pt-4 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-flex tw-items-center tw-justify-end tw-space-x-3\">\r\n <button cideEleButton type=\"button\" variant=\"outline\" (click)=\"cancelForm()\" [disabled]=\"loading()\">Cancel</button>\r\n <button cideEleButton type=\"submit\" variant=\"primary\" leftIcon=\"add\" [disabled]=\"!themeForm.valid || loading()\" [loading]=\"loading()\">\r\n {{ isEditMode() ? 'Update Theme' : 'Create Theme' }}\r\n </button>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n\r\n <!-- Right: Theme gallery (40%) -->\r\n <div class=\"tw-hidden lg:tw-flex tw-w-2/5 tw-flex-col\">\r\n <!-- (Header consolidated above) -->\r\n\r\n <!-- Gallery list -->\r\n <div class=\"tw-flex-1 tw-overflow-auto tw-bg-gray-50\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-p-4\">\r\n @for (theme of filteredThemes(); track theme._id) {\r\n <div class=\"tw-rounded-md tw-transition tw-cursor-pointer tw-relative\"\r\n [ngClass]=\"theme.sytm_isselected\r\n ? 'tw-border tw-border-blue-500 tw-ring-2 tw-ring-blue-200 tw-bg-blue-50/50'\r\n : 'tw-bg-white tw-border tw-border-gray-200 hover:tw-shadow-sm'\"\r\n (click)=\"editTheme(theme)\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n [attr.aria-selected]=\"theme.sytm_isselected ? 'true' : 'false'\"\r\n [attr.aria-label]=\"'Edit theme ' + (theme.sytm_title || theme.sytm_theme_code)\"\r\n (keydown.enter)=\"editTheme(theme)\"\r\n (keydown.space)=\"$event.preventDefault(); editTheme(theme)\">\r\n\r\n <!-- Selected badge -->\r\n <div *ngIf=\"theme.sytm_isselected\"\r\n class=\"tw-absolute tw-top-2 tw-right-2 tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-rounded-full tw-bg-blue-600 tw-text-white\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">check</cide-ele-icon>\r\n </div>\r\n \r\n <div class=\"tw-aspect-[16/9] tw-bg-gray-100 tw-rounded-t-md tw-overflow-hidden tw-flex tw-items-center tw-justify-center\">\r\n @if (theme.sytm_preview_id_fm) {\r\n <img \r\n cideEleFileImage \r\n [fileId]=\"theme.sytm_preview_id_fm\" \r\n [altText]=\"'Theme Preview'\"\r\n class=\"tw-w-full tw-h-full tw-object-cover\" />\r\n } @else {\r\n <div class=\"tw-text-gray-400 tw-text-xs\">No preview</div>\r\n }\r\n </div>\r\n <div class=\"tw-p-3 tw-space-y-1\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\" [title]=\"theme.sytm_title\">{{ theme.sytm_title || 'Untitled Theme' }}</div>\r\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate\" [title]=\"theme.sytm_theme_code\">{{ theme.sytm_theme_code }}</div>\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-pt-1\">\r\n <span class=\"tw-inline-flex tw-items-center tw-gap-1 tw-text-xs\" [ngClass]=\"theme.sytm_isactive ? 'tw-text-green-700' : 'tw-text-red-700'\">\r\n <span class=\"tw-w-1.5 tw-h-1.5 tw-rounded-full\" [ngClass]=\"theme.sytm_isactive ? 'tw-bg-green-500' : 'tw-bg-red-500'\"></span>\r\n {{ theme.sytm_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n <div class=\"tw-flex tw-items-center tw-gap-1\">\r\n <!-- Set Selected Button - Clear and Simple -->\r\n @if (theme.sytm_isselected) {\r\n <span class=\"tw-inline-flex tw-items-center tw-gap-1 tw-px-2 tw-py-1 tw-bg-green-100 tw-text-green-800 tw-rounded-md tw-text-xs tw-font-medium\">\r\n <cide-ele-icon class=\"tw-w-3 tw-h-3\">check</cide-ele-icon>\r\n Selected\r\n </span>\r\n } @else {\r\n <button cideEleButton \r\n variant=\"outline\" \r\n size=\"xs\"\r\n (click)=\"$event.stopPropagation(); setSelectedTheme(theme)\"\r\n [attr.aria-label]=\"'Select ' + (theme.sytm_title || theme.sytm_theme_code) + ' theme'\"\r\n class=\"tw-text-xs\">\r\n Select\r\n </button>\r\n }\r\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"$event.stopPropagation(); editTheme(theme)\"\r\n [attr.aria-label]=\"'Edit theme ' + (theme.sytm_title || theme.sytm_theme_code)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">edit</cide-ele-icon>\r\n </button>\r\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"$event.stopPropagation(); deleteTheme(theme)\"\r\n [attr.aria-label]=\"'Delete theme ' + (theme.sytm_title || theme.sytm_theme_code)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">delete</cide-ele-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (!loading() && filteredThemes().length === 0) {\r\n <div class=\"tw-col-span-full tw-text-center tw-text-xs tw-text-gray-500 tw-py-8\">No themes found</div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- \r\n Angular Template References for Grid Renderers (Best Practice)\r\n \r\n These ng-template elements represent the Angular best practice for custom rendering.\r\n They provide:\r\n - Type safety with template context\r\n - Component lifecycle integration\r\n - Change detection optimization\r\n - Proper event handling\r\n - Accessibility features\r\n \r\n Note: Current data grid uses string renderers for compatibility.\r\n Templates are maintained for future component enhancement.\r\n-->\r\n\r\n<!-- Theme Details Renderer Template -->\r\n<ng-template #themeDetailsRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <div class=\"tw-flex tw-items-center tw-min-w-0\">\r\n <!-- Theme Icon -->\r\n <div class=\"tw-flex-shrink-0\">\r\n <cide-ele-icon \r\n class=\"tw-text-purple-600\" \r\n size=\"xs\">\r\n palette\r\n </cide-ele-icon>\r\n </div>\r\n \r\n <!-- Theme Details -->\r\n <div class=\"tw-ml-3 tw-min-w-0 tw-flex-1\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\" \r\n [title]=\"row.sytm_title\">\r\n {{ row.sytm_title || 'Untitled' }}\r\n </div>\r\n @if (row.sytm_desc) {\r\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate\" \r\n [title]=\"row.sytm_desc\">\r\n {{ row.sytm_desc }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n</ng-template>\r\n\r\n<!-- Theme Status Renderer Template -->\r\n<ng-template #themeStatusRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <span class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-whitespace-nowrap\"\r\n [ngClass]=\"row.sytm_isactive ? 'tw-bg-green-100 tw-text-green-800' : 'tw-bg-red-100 tw-text-red-800'\">\r\n {{ row.sytm_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n</ng-template>\r\n\r\n<!-- Actions Dropdown Renderer Template -->\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown \r\n [items]=\"getActionDropdownItems(row)\"\r\n [config]=\"{ triggerIcon: 'more_vert', triggerSize: 'sm' }\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template> ", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: FormsModule }, { 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: 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", "valueKey", "labelKey"], 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: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }, { kind: "component", type: CideEleJsonEditorComponent, selector: "cide-ele-json-editor", inputs: ["label", "helperText", "required", "disabled", "showCharacterCount", "config"], outputs: ["valueChange", "objectChange", "errorsChange", "validChange"] }, { kind: "component", type: CideEleFileInputComponent, selector: "cide-ele-file-input", inputs: ["label", "accept", "multiple", "disabled", "required", "helperText", "errorText", "showPreview", "previewWidth", "previewHeight", "previewBoxMode", "showFileName", "placeholderText", "placeholderIcon", "autoUpload", "uploadData"], outputs: ["fileChange", "uploadSuccess", "uploadError", "uploadProgressChange"] }, { kind: "directive", type: CideEleFileImageDirective, selector: "[cideEleFileImage]", inputs: ["fileId", "altText"] }] });
|
|
7029
7113
|
}
|
|
7030
7114
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideCorePageThemeComponent, decorators: [{
|
|
7031
7115
|
type: Component,
|
|
@@ -7040,7 +7124,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
7040
7124
|
CideIconComponent,
|
|
7041
7125
|
CideEleDropdownComponent,
|
|
7042
7126
|
CideEleJsonEditorComponent,
|
|
7043
|
-
], template: "<!-- Page Theme Container -->\r\n<div class=\"tw-flex tw-h-full tw-w-full\">\r\n \r\n <!-- Left: Form and header (60%) -->\r\n <div class=\"tw-w-full lg:tw-w-3/5 tw-flex tw-flex-col tw-border-r tw-border-gray-200\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-px-6 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-3 sm:tw-space-y-0\">\r\n\r\n <!-- Title and Back Button -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-4\">\r\n <button cideEleButton variant=\"ghost\" size=\"sm\" (click)=\"goBack()\" class=\"tw-text-gray-600 hover:tw-text-gray-900\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_back</cide-ele-icon>\r\n </button>\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">palette</cide-ele-icon>\r\n <div>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Theme Management</h5>\r\n <p class=\"tw-text-sm tw-text-gray-500 tw-m-0\">Page: {{ pageTitle() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n @if (error()) {\r\n <div class=\"tw-mt-4 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\r\n <div class=\"tw-flex tw-items-start\">\r\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\r\n <div class=\"tw-ml-3\">\r\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\r\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Quick Add/Edit Form Section -->\r\n <div class=\"tw-px-6 tw-py-4 tw-bg-white tw-overflow-auto\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\r\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">{{ isEditMode() ? 'edit' : 'add' }}</cide-ele-icon>\r\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-m-0\">{{ isEditMode() ? 'Edit Theme' : 'Quick Add Theme' }}</h6>\r\n </div>\r\n </div>\r\n\r\n <!-- Form (kept as-is) -->\r\n <form [formGroup]=\"themeForm\" (ngSubmit)=\"saveTheme()\" class=\"tw-space-y-4\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-3 tw-gap-4\">\r\n <!-- Theme Title -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_title\" formControlName=\"sytm_title\" placeholder=\"Enter theme title\" label=\"Theme Title*\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <!-- Theme Code -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_theme_code\" formControlName=\"sytm_theme_code\" placeholder=\"Enter theme code\" label=\"Theme Code*\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <!-- Status -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input\r\n id=\"sytm_isactive_cb\"\r\n type=\"checkbox\"\r\n label=\"Active\"\r\n size=\"sm\"\r\n formControlName=\"sytm_isactive\">\r\n </cide-ele-input>\r\n </div>\r\n <!-- Sub Title -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_sub_title\" formControlName=\"sytm_sub_title\" placeholder=\"Enter sub title\" label=\"Sub Title\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <!-- Preview ID -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_preview_id_fm\" formControlName=\"sytm_preview_id_fm\" placeholder=\"Enter preview image ID\" label=\"Preview Image ID\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <!-- Description -->\r\n <div class=\"tw-space-y-2 md:tw-col-span-2\">\r\n <cide-ele-textarea id=\"sytm_desc\" formControlName=\"sytm_desc\" placeholder=\"Enter theme description\" rows=\"2\" label=\"Description\" size=\"sm\"></cide-ele-textarea>\r\n </div>\r\n <!-- Configuration JSON -->\r\n <div class=\"tw-space-y-2 md:tw-col-span-3\">\r\n <cide-ele-json-editor label=\"Configuration JSON\" formControlName=\"sytm_configuration\" [required]=\"true\" [config]=\"{\r\n showLineNumbers: true,\r\n autoFormat: true,\r\n validateOnChange: true,\r\n minHeight: 150,\r\n maxHeight: 300,\r\n placeholder: 'Enter theme configuration JSON...'\r\n }\" helperText=\"Enter valid JSON configuration for the theme\"></cide-ele-json-editor>\r\n </div>\r\n <!-- Layout Configuration + Selection: right-side checkbox list -->\r\n <div class=\"lg:tw-col-span-1 tw-space-y-2\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Layout & Selection</div>\r\n <!-- Selected toggle -->\r\n <div class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-md tw-px-3 tw-py-2\">\r\n <cide-ele-input\r\n id=\"sytm_isselected\"\r\n type=\"checkbox\"\r\n label=\"Selected (Default)\"\r\n size=\"sm\"\r\n formControlName=\"sytm_isselected\">\r\n </cide-ele-input>\r\n </div>\r\n <div formGroupName=\"sytm_layout\" class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-md tw-divide-y tw-overflow-hidden\">\r\n <!-- Sidebar -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_sidebar\">\r\n <cide-ele-input id=\"layout_sidebar_status\" type=\"checkbox\" label=\"Sidebar\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Header -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_header\">\r\n <cide-ele-input id=\"layout_header_status\" type=\"checkbox\" label=\"Header\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Footer -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_footer\">\r\n <cide-ele-input id=\"layout_footer_status\" type=\"checkbox\" label=\"Footer\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Breadcrumb -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_breadcrumb\">\r\n <cide-ele-input id=\"layout_breadcrumb_status\" type=\"checkbox\" label=\"Breadcrumb\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Console -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_console\">\r\n <cide-ele-input id=\"layout_console_status\" type=\"checkbox\" label=\"Console\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Request -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_request\">\r\n <cide-ele-input id=\"layout_request_status\" type=\"checkbox\" label=\"Request\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n </div>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-pt-1\">Toggle active sections. Only one theme can be selected as default. More options can be added here later.</p>\r\n </div>\r\n <!-- Drawer Configuration -->\r\n <div class=\"tw-space-y-2 md:tw-col-span-3\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Drawers</div>\r\n <button cideEleButton type=\"button\" size=\"xs\" variant=\"outline\" (click)=\"addDrawer()\">\r\n Add Drawer\r\n </button>\r\n </div>\r\n\r\n <div formGroupName=\"sytm_layout\">\r\n <div class=\"tw-space-y-2\" formArrayName=\"sytm_layout_drawer\">\r\n <div *ngFor=\"let drawerGrp of drawerArray.controls; let i = index\" [formGroupName]=\"i\" class=\"tw-border tw-border-gray-200 tw-rounded-md tw-p-3 tw-flex tw-items-center tw-gap-3\">\r\n <cide-ele-input id=\"drawer_active_{{i}}\" type=\"checkbox\" label=\"Active\" size=\"sm\" formControlName=\"syth_status\"></cide-ele-input>\r\n <div class=\"tw-flex-1\">\r\n <cide-ele-select\r\n id=\"drawer_config_{{i}}\"\r\n label=\"Drawer For\"\r\n size=\"sm\"\r\n [options]=\"drawerConfigOptions\"\r\n formControlName=\"syth_config_syco_for\">\r\n </cide-ele-select>\r\n </div>\r\n <button cideEleButton type=\"button\" size=\"xs\" variant=\"ghost\" (click)=\"removeDrawer(i)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">delete</cide-ele-icon>\r\n </button>\r\n </div>\r\n <p class=\"tw-text-xs tw-text-gray-500\">Configure multiple drawers as needed.</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Form Actions -->\r\n <div class=\"tw-flex tw-flex-col tw-gap-2 tw-pt-4 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-flex tw-items-center tw-justify-end tw-space-x-3\">\r\n <button cideEleButton type=\"button\" variant=\"outline\" (click)=\"cancelForm()\" [disabled]=\"loading()\">Cancel</button>\r\n <button cideEleButton type=\"submit\" variant=\"primary\" leftIcon=\"add\" [disabled]=\"!themeForm.valid || loading()\" [loading]=\"loading()\">\r\n {{ isEditMode() ? 'Update Theme' : 'Create Theme' }}\r\n </button>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n\r\n <!-- Right: Theme gallery (40%) -->\r\n <div class=\"tw-hidden lg:tw-flex tw-w-2/5 tw-flex-col\">\r\n <!-- (Header consolidated above) -->\r\n\r\n <!-- Gallery list -->\r\n <div class=\"tw-flex-1 tw-overflow-auto tw-bg-gray-50\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-p-4\">\r\n @for (theme of filteredThemes(); track theme._id) {\r\n <div class=\"tw-rounded-md tw-transition tw-cursor-pointer tw-relative\"\r\n [ngClass]=\"theme.sytm_isselected\r\n ? 'tw-border tw-border-blue-500 tw-ring-2 tw-ring-blue-200 tw-bg-blue-50/50'\r\n : 'tw-bg-white tw-border tw-border-gray-200 hover:tw-shadow-sm'\"\r\n (click)=\"editTheme(theme)\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n [attr.aria-selected]=\"theme.sytm_isselected ? 'true' : 'false'\"\r\n [attr.aria-label]=\"'Edit theme ' + (theme.sytm_title || theme.sytm_theme_code)\"\r\n (keydown.enter)=\"editTheme(theme)\"\r\n (keydown.space)=\"$event.preventDefault(); editTheme(theme)\">\r\n\r\n <!-- Selected badge -->\r\n <div *ngIf=\"theme.sytm_isselected\"\r\n class=\"tw-absolute tw-top-2 tw-right-2 tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-rounded-full tw-bg-blue-600 tw-text-white\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">check</cide-ele-icon>\r\n </div>\r\n \r\n <div class=\"tw-aspect-[16/9] tw-bg-gray-100 tw-rounded-t-md tw-overflow-hidden tw-flex tw-items-center tw-justify-center\">\r\n @if (getPreviewUrl(theme)) {\r\n <img [src]=\"getPreviewUrl(theme)\" class=\"tw-w-full tw-h-full tw-object-cover\" alt=\"Preview\" />\r\n } @else {\r\n <div class=\"tw-text-gray-400 tw-text-xs\">No preview</div>\r\n }\r\n </div>\r\n <div class=\"tw-p-3 tw-space-y-1\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\" [title]=\"theme.sytm_title\">{{ theme.sytm_title || 'Untitled Theme' }}</div>\r\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate\" [title]=\"theme.sytm_theme_code\">{{ theme.sytm_theme_code }}</div>\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-pt-1\">\r\n <span class=\"tw-inline-flex tw-items-center tw-gap-1 tw-text-xs\" [ngClass]=\"theme.sytm_isactive ? 'tw-text-green-700' : 'tw-text-red-700'\">\r\n <span class=\"tw-w-1.5 tw-h-1.5 tw-rounded-full\" [ngClass]=\"theme.sytm_isactive ? 'tw-bg-green-500' : 'tw-bg-red-500'\"></span>\r\n {{ theme.sytm_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n <div class=\"tw-flex tw-items-center tw-gap-1\">\r\n <!-- Set Selected Button - Clear and Simple -->\r\n @if (theme.sytm_isselected) {\r\n <span class=\"tw-inline-flex tw-items-center tw-gap-1 tw-px-2 tw-py-1 tw-bg-green-100 tw-text-green-800 tw-rounded-md tw-text-xs tw-font-medium\">\r\n <cide-ele-icon class=\"tw-w-3 tw-h-3\">check</cide-ele-icon>\r\n Selected\r\n </span>\r\n } @else {\r\n <button cideEleButton \r\n variant=\"outline\" \r\n size=\"xs\"\r\n (click)=\"$event.stopPropagation(); setSelectedTheme(theme)\"\r\n [attr.aria-label]=\"'Select ' + (theme.sytm_title || theme.sytm_theme_code) + ' theme'\"\r\n class=\"tw-text-xs\">\r\n Select\r\n </button>\r\n }\r\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"$event.stopPropagation(); editTheme(theme)\"\r\n [attr.aria-label]=\"'Edit theme ' + (theme.sytm_title || theme.sytm_theme_code)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">edit</cide-ele-icon>\r\n </button>\r\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"$event.stopPropagation(); deleteTheme(theme)\"\r\n [attr.aria-label]=\"'Delete theme ' + (theme.sytm_title || theme.sytm_theme_code)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">delete</cide-ele-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (!loading() && filteredThemes().length === 0) {\r\n <div class=\"tw-col-span-full tw-text-center tw-text-xs tw-text-gray-500 tw-py-8\">No themes found</div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- \r\n Angular Template References for Grid Renderers (Best Practice)\r\n \r\n These ng-template elements represent the Angular best practice for custom rendering.\r\n They provide:\r\n - Type safety with template context\r\n - Component lifecycle integration\r\n - Change detection optimization\r\n - Proper event handling\r\n - Accessibility features\r\n \r\n Note: Current data grid uses string renderers for compatibility.\r\n Templates are maintained for future component enhancement.\r\n-->\r\n\r\n<!-- Theme Details Renderer Template -->\r\n<ng-template #themeDetailsRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <div class=\"tw-flex tw-items-center tw-min-w-0\">\r\n <!-- Theme Icon -->\r\n <div class=\"tw-flex-shrink-0\">\r\n <cide-ele-icon \r\n class=\"tw-text-purple-600\" \r\n size=\"xs\">\r\n palette\r\n </cide-ele-icon>\r\n </div>\r\n \r\n <!-- Theme Details -->\r\n <div class=\"tw-ml-3 tw-min-w-0 tw-flex-1\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\" \r\n [title]=\"row.sytm_title\">\r\n {{ row.sytm_title || 'Untitled' }}\r\n </div>\r\n @if (row.sytm_desc) {\r\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate\" \r\n [title]=\"row.sytm_desc\">\r\n {{ row.sytm_desc }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n</ng-template>\r\n\r\n<!-- Theme Status Renderer Template -->\r\n<ng-template #themeStatusRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <span class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-whitespace-nowrap\"\r\n [ngClass]=\"row.sytm_isactive ? 'tw-bg-green-100 tw-text-green-800' : 'tw-bg-red-100 tw-text-red-800'\">\r\n {{ row.sytm_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n</ng-template>\r\n\r\n<!-- Actions Dropdown Renderer Template -->\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown \r\n [items]=\"getActionDropdownItems(row)\"\r\n [config]=\"{ triggerIcon: 'more_vert', triggerSize: 'sm' }\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template> " }]
|
|
7127
|
+
CideEleFileInputComponent,
|
|
7128
|
+
CideEleFileImageDirective,
|
|
7129
|
+
], template: "<!-- Page Theme Container -->\r\n<div class=\"tw-flex tw-h-full tw-w-full\">\r\n \r\n <!-- Left: Form and header (60%) -->\r\n <div class=\"tw-w-full lg:tw-w-3/5 tw-flex tw-flex-col tw-border-r tw-border-gray-200\">\r\n\r\n <!-- Header Section -->\r\n <div class=\"tw-px-6 tw-py-2 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\r\n <div class=\"tw-flex tw-flex-col sm:tw-flex-row tw-justify-between tw-items-start sm:tw-items-center tw-space-y-2 sm:tw-space-y-0\">\r\n\r\n <!-- Title and Back Button -->\r\n <div class=\"tw-flex tw-items-center tw-space-x-4\">\r\n <button cideEleButton variant=\"ghost\" size=\"sm\" (click)=\"goBack();\" class=\"tw-text-gray-600 hover:tw-text-gray-900\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">arrow_back</cide-ele-icon>\r\n </button>\r\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">palette</cide-ele-icon>\r\n <div>\r\n <h5 class=\"tw-text-base tw-font-medium tw-text-gray-900 tw-m-0\">Theme Management</h5>\r\n <p class=\"tw-text-sm tw-text-gray-500 tw-m-0\">Page: {{ pageTitle() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n @if (error()) {\r\n <div class=\"tw-mt-4 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\r\n <div class=\"tw-flex tw-items-start\">\r\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\r\n <div class=\"tw-ml-3\">\r\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\r\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Quick Add/Edit Form Section -->\r\n <div class=\"tw-px-6 tw-py-3 tw-bg-white tw-overflow-auto\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\r\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\r\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">{{ isEditMode() ? 'edit' : 'add' }}</cide-ele-icon>\r\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-m-0\">{{ isEditMode() ? 'Edit Theme' : 'Quick Add Theme' }}</h6>\r\n </div>\r\n </div>\r\n\r\n <!-- Form (kept as-is) -->\r\n <form [formGroup]=\"themeForm\" (ngSubmit)=\"saveTheme()\" class=\"tw-space-y-4\">\r\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-[1fr_200px] tw-gap-4\">\r\n <!-- Left Side: All Input Fields -->\r\n <div class=\"tw-space-y-4\">\r\n <!-- Row 1: Theme Title and Theme Code -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_title\" formControlName=\"sytm_title\" placeholder=\"Enter theme title\" label=\"Theme Title*\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_theme_code\" formControlName=\"sytm_theme_code\" placeholder=\"Enter theme code\" label=\"Theme Code*\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n </div>\r\n \r\n <!-- Row 2: Sub Title and Active Status -->\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4\">\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-input id=\"sytm_sub_title\" formControlName=\"sytm_sub_title\" placeholder=\"Enter sub title\" label=\"Sub Title\" size=\"sm\"></cide-ele-input>\r\n </div>\r\n <div class=\"tw-space-y-2 tw-flex tw-items-center\">\r\n <cide-ele-input\r\n id=\"sytm_isactive_cb\"\r\n type=\"checkbox\"\r\n label=\"Active\"\r\n size=\"sm\"\r\n formControlName=\"sytm_isactive\">\r\n </cide-ele-input>\r\n </div>\r\n </div>\r\n \r\n <!-- Row 3: Description -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-textarea id=\"sytm_desc\" formControlName=\"sytm_desc\" placeholder=\"Enter theme description\" rows=\"2\" label=\"Description\" size=\"sm\"></cide-ele-textarea>\r\n </div>\r\n </div>\r\n \r\n <!-- Right Side: File Upload -->\r\n <div class=\"tw-flex tw-flex-col tw-justify-start tw-items-center tw-p-0\">\r\n <cide-ele-file-input \r\n id=\"sytm_preview_id_fm\" \r\n formControlName=\"sytm_preview_id_fm\"\r\n accept=\"image/*\"\r\n [showPreview]=\"true\"\r\n [previewBoxMode]=\"true\"\r\n [showFileName]=\"false\"\r\n previewWidth=\"180px\"\r\n previewHeight=\"120px\"\r\n placeholderText=\"Upload Preview Image\"\r\n placeholderIcon=\"image\"\r\n [autoUpload]=\"true\"\r\n [uploadData]=\"getPreviewImageUploadData()\"\r\n (uploadSuccess)=\"onPreviewImageUploadSuccess($event)\"\r\n (uploadError)=\"onPreviewImageUploadError($event)\"\r\n (uploadProgressChange)=\"onPreviewImageUploadProgress($event)\">\r\n </cide-ele-file-input>\r\n </div>\r\n </div>\r\n \r\n <!-- Configuration JSON -->\r\n <div class=\"tw-space-y-2\">\r\n <cide-ele-json-editor label=\"Configuration JSON\" formControlName=\"sytm_configuration\" [required]=\"true\" [config]=\"{\r\n showLineNumbers: true,\r\n autoFormat: true,\r\n validateOnChange: true,\r\n minHeight: 150,\r\n maxHeight: 300,\r\n placeholder: 'Enter theme configuration JSON...'\r\n }\" helperText=\"Enter valid JSON configuration for the theme\"></cide-ele-json-editor>\r\n </div>\r\n <!-- Layout Configuration + Selection -->\r\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-6\">\r\n <div class=\"tw-space-y-2\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Layout & Selection</div>\r\n <!-- Selected toggle -->\r\n <div class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-md tw-px-3 tw-py-2\">\r\n <cide-ele-input\r\n id=\"sytm_isselected\"\r\n type=\"checkbox\"\r\n label=\"Selected (Default)\"\r\n size=\"sm\"\r\n formControlName=\"sytm_isselected\">\r\n </cide-ele-input>\r\n </div>\r\n <div formGroupName=\"sytm_layout\" class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-md tw-divide-y tw-overflow-hidden\">\r\n <!-- Sidebar -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_sidebar\">\r\n <cide-ele-input id=\"layout_sidebar_status\" type=\"checkbox\" label=\"Sidebar\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Header -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_header\">\r\n <cide-ele-input id=\"layout_header_status\" type=\"checkbox\" label=\"Header\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Footer -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_footer\">\r\n <cide-ele-input id=\"layout_footer_status\" type=\"checkbox\" label=\"Footer\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Breadcrumb -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_breadcrumb\">\r\n <cide-ele-input id=\"layout_breadcrumb_status\" type=\"checkbox\" label=\"Breadcrumb\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Console -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_console\">\r\n <cide-ele-input id=\"layout_console_status\" type=\"checkbox\" label=\"Console\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n <!-- Request -->\r\n <div class=\"tw-px-3 tw-py-2\" formGroupName=\"sytm_layout_request\">\r\n <cide-ele-input id=\"layout_request_status\" type=\"checkbox\" label=\"Request\" size=\"sm\" formControlName=\"status\"></cide-ele-input>\r\n </div>\r\n </div>\r\n <p class=\"tw-text-xs tw-text-gray-500 tw-pt-1\">Toggle active sections. Only one theme can be selected as default. More options can be added here later.</p>\r\n </div>\r\n \r\n <!-- Drawer Configuration -->\r\n <div class=\"tw-space-y-2\">\r\n <div class=\"tw-flex tw-items-center tw-justify-between\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Drawers</div>\r\n <button cideEleButton type=\"button\" size=\"xs\" variant=\"outline\" (click)=\"addDrawer()\">\r\n Add Drawer\r\n </button>\r\n </div>\r\n\r\n <div formGroupName=\"sytm_layout\">\r\n <div class=\"tw-space-y-2\" formArrayName=\"sytm_layout_drawer\">\r\n <div *ngFor=\"let drawerGrp of drawerArray.controls; let i = index\" [formGroupName]=\"i\" class=\"tw-border tw-border-gray-200 tw-rounded-md tw-p-3 tw-flex tw-items-center tw-gap-3\">\r\n <cide-ele-input id=\"drawer_active_{{i}}\" type=\"checkbox\" label=\"Active\" size=\"sm\" formControlName=\"syth_status\"></cide-ele-input>\r\n <div class=\"tw-flex-1\">\r\n <cide-ele-select\r\n id=\"drawer_config_{{i}}\"\r\n label=\"Drawer For\"\r\n size=\"sm\"\r\n [options]=\"drawerConfigOptions\"\r\n formControlName=\"syth_config_syco_for\">\r\n </cide-ele-select>\r\n </div>\r\n <button cideEleButton type=\"button\" size=\"xs\" variant=\"ghost\" (click)=\"removeDrawer(i)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">delete</cide-ele-icon>\r\n </button>\r\n </div>\r\n <p class=\"tw-text-xs tw-text-gray-500\">Configure multiple drawers as needed.</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Form Actions -->\r\n <div class=\"tw-flex tw-flex-col tw-gap-2 tw-pt-4 tw-border-t tw-border-gray-200\">\r\n <div class=\"tw-flex tw-items-center tw-justify-end tw-space-x-3\">\r\n <button cideEleButton type=\"button\" variant=\"outline\" (click)=\"cancelForm()\" [disabled]=\"loading()\">Cancel</button>\r\n <button cideEleButton type=\"submit\" variant=\"primary\" leftIcon=\"add\" [disabled]=\"!themeForm.valid || loading()\" [loading]=\"loading()\">\r\n {{ isEditMode() ? 'Update Theme' : 'Create Theme' }}\r\n </button>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n </div>\r\n\r\n <!-- Right: Theme gallery (40%) -->\r\n <div class=\"tw-hidden lg:tw-flex tw-w-2/5 tw-flex-col\">\r\n <!-- (Header consolidated above) -->\r\n\r\n <!-- Gallery list -->\r\n <div class=\"tw-flex-1 tw-overflow-auto tw-bg-gray-50\">\r\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-p-4\">\r\n @for (theme of filteredThemes(); track theme._id) {\r\n <div class=\"tw-rounded-md tw-transition tw-cursor-pointer tw-relative\"\r\n [ngClass]=\"theme.sytm_isselected\r\n ? 'tw-border tw-border-blue-500 tw-ring-2 tw-ring-blue-200 tw-bg-blue-50/50'\r\n : 'tw-bg-white tw-border tw-border-gray-200 hover:tw-shadow-sm'\"\r\n (click)=\"editTheme(theme)\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n [attr.aria-selected]=\"theme.sytm_isselected ? 'true' : 'false'\"\r\n [attr.aria-label]=\"'Edit theme ' + (theme.sytm_title || theme.sytm_theme_code)\"\r\n (keydown.enter)=\"editTheme(theme)\"\r\n (keydown.space)=\"$event.preventDefault(); editTheme(theme)\">\r\n\r\n <!-- Selected badge -->\r\n <div *ngIf=\"theme.sytm_isselected\"\r\n class=\"tw-absolute tw-top-2 tw-right-2 tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-rounded-full tw-bg-blue-600 tw-text-white\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">check</cide-ele-icon>\r\n </div>\r\n \r\n <div class=\"tw-aspect-[16/9] tw-bg-gray-100 tw-rounded-t-md tw-overflow-hidden tw-flex tw-items-center tw-justify-center\">\r\n @if (theme.sytm_preview_id_fm) {\r\n <img \r\n cideEleFileImage \r\n [fileId]=\"theme.sytm_preview_id_fm\" \r\n [altText]=\"'Theme Preview'\"\r\n class=\"tw-w-full tw-h-full tw-object-cover\" />\r\n } @else {\r\n <div class=\"tw-text-gray-400 tw-text-xs\">No preview</div>\r\n }\r\n </div>\r\n <div class=\"tw-p-3 tw-space-y-1\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\" [title]=\"theme.sytm_title\">{{ theme.sytm_title || 'Untitled Theme' }}</div>\r\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate\" [title]=\"theme.sytm_theme_code\">{{ theme.sytm_theme_code }}</div>\r\n <div class=\"tw-flex tw-items-center tw-justify-between tw-pt-1\">\r\n <span class=\"tw-inline-flex tw-items-center tw-gap-1 tw-text-xs\" [ngClass]=\"theme.sytm_isactive ? 'tw-text-green-700' : 'tw-text-red-700'\">\r\n <span class=\"tw-w-1.5 tw-h-1.5 tw-rounded-full\" [ngClass]=\"theme.sytm_isactive ? 'tw-bg-green-500' : 'tw-bg-red-500'\"></span>\r\n {{ theme.sytm_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n <div class=\"tw-flex tw-items-center tw-gap-1\">\r\n <!-- Set Selected Button - Clear and Simple -->\r\n @if (theme.sytm_isselected) {\r\n <span class=\"tw-inline-flex tw-items-center tw-gap-1 tw-px-2 tw-py-1 tw-bg-green-100 tw-text-green-800 tw-rounded-md tw-text-xs tw-font-medium\">\r\n <cide-ele-icon class=\"tw-w-3 tw-h-3\">check</cide-ele-icon>\r\n Selected\r\n </span>\r\n } @else {\r\n <button cideEleButton \r\n variant=\"outline\" \r\n size=\"xs\"\r\n (click)=\"$event.stopPropagation(); setSelectedTheme(theme)\"\r\n [attr.aria-label]=\"'Select ' + (theme.sytm_title || theme.sytm_theme_code) + ' theme'\"\r\n class=\"tw-text-xs\">\r\n Select\r\n </button>\r\n }\r\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"$event.stopPropagation(); editTheme(theme)\"\r\n [attr.aria-label]=\"'Edit theme ' + (theme.sytm_title || theme.sytm_theme_code)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">edit</cide-ele-icon>\r\n </button>\r\n <button cideEleButton variant=\"ghost\" size=\"xs\" (click)=\"$event.stopPropagation(); deleteTheme(theme)\"\r\n [attr.aria-label]=\"'Delete theme ' + (theme.sytm_title || theme.sytm_theme_code)\">\r\n <cide-ele-icon class=\"tw-w-4 tw-h-4\">delete</cide-ele-icon>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (!loading() && filteredThemes().length === 0) {\r\n <div class=\"tw-col-span-full tw-text-center tw-text-xs tw-text-gray-500 tw-py-8\">No themes found</div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- \r\n Angular Template References for Grid Renderers (Best Practice)\r\n \r\n These ng-template elements represent the Angular best practice for custom rendering.\r\n They provide:\r\n - Type safety with template context\r\n - Component lifecycle integration\r\n - Change detection optimization\r\n - Proper event handling\r\n - Accessibility features\r\n \r\n Note: Current data grid uses string renderers for compatibility.\r\n Templates are maintained for future component enhancement.\r\n-->\r\n\r\n<!-- Theme Details Renderer Template -->\r\n<ng-template #themeDetailsRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <div class=\"tw-flex tw-items-center tw-min-w-0\">\r\n <!-- Theme Icon -->\r\n <div class=\"tw-flex-shrink-0\">\r\n <cide-ele-icon \r\n class=\"tw-text-purple-600\" \r\n size=\"xs\">\r\n palette\r\n </cide-ele-icon>\r\n </div>\r\n \r\n <!-- Theme Details -->\r\n <div class=\"tw-ml-3 tw-min-w-0 tw-flex-1\">\r\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\" \r\n [title]=\"row.sytm_title\">\r\n {{ row.sytm_title || 'Untitled' }}\r\n </div>\r\n @if (row.sytm_desc) {\r\n <div class=\"tw-text-xs tw-text-gray-500 tw-truncate\" \r\n [title]=\"row.sytm_desc\">\r\n {{ row.sytm_desc }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n</ng-template>\r\n\r\n<!-- Theme Status Renderer Template -->\r\n<ng-template #themeStatusRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <span class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-whitespace-nowrap\"\r\n [ngClass]=\"row.sytm_isactive ? 'tw-bg-green-100 tw-text-green-800' : 'tw-bg-red-100 tw-text-red-800'\">\r\n {{ row.sytm_isactive ? 'Active' : 'Inactive' }}\r\n </span>\r\n</ng-template>\r\n\r\n<!-- Actions Dropdown Renderer Template -->\r\n<ng-template #actionsDropdownRendererTemplate let-row=\"row\" let-value=\"value\">\r\n <cide-ele-dropdown \r\n [items]=\"getActionDropdownItems(row)\"\r\n [config]=\"{ triggerIcon: 'more_vert', triggerSize: 'sm' }\"\r\n (itemClick)=\"onDropdownItemClick($event, row)\">\r\n </cide-ele-dropdown>\r\n</ng-template> " }]
|
|
7044
7130
|
}] });
|
|
7045
7131
|
|
|
7046
7132
|
var pageTheme_component = /*#__PURE__*/Object.freeze({
|
|
@@ -11005,11 +11091,13 @@ class CideCoreUserCreateComponent {
|
|
|
11005
11091
|
// Dependency injection
|
|
11006
11092
|
destroyRef = inject(DestroyRef);
|
|
11007
11093
|
fb = inject(FormBuilder);
|
|
11094
|
+
cdr = inject(ChangeDetectorRef);
|
|
11008
11095
|
userMasterService = inject(CideCoreUserMasterService);
|
|
11009
11096
|
entityService = inject(CideCoreEntityManagementService);
|
|
11010
11097
|
designationService = inject(CideCoreDesignationManagementService);
|
|
11011
11098
|
departmentService = inject(CideCoreDepartmentManagementService);
|
|
11012
11099
|
CideCoreGeneralMasterService = inject(CideCoreGeneralMasterService);
|
|
11100
|
+
generalMasterTypeService = inject(CideCoreGeneralMasterTypeService);
|
|
11013
11101
|
pinCodeService = inject(CideCorePinCodeService);
|
|
11014
11102
|
countryService = inject(CideCoreCountryService);
|
|
11015
11103
|
userRoleService = inject(CideCoreUserRoleService);
|
|
@@ -11017,10 +11105,12 @@ class CideCoreUserCreateComponent {
|
|
|
11017
11105
|
router = inject(Router);
|
|
11018
11106
|
route = inject(ActivatedRoute);
|
|
11019
11107
|
appState = inject(AppStateHelperService);
|
|
11108
|
+
floatingUploadService = inject(CideLytFloatingUploadService);
|
|
11020
11109
|
userMasterForm;
|
|
11021
11110
|
activeTab = signal('basic', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
|
|
11022
11111
|
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
11023
11112
|
error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
11113
|
+
success = signal(null, ...(ngDevMode ? [{ debugName: "success" }] : []));
|
|
11024
11114
|
// User information from route
|
|
11025
11115
|
userId = signal('', ...(ngDevMode ? [{ debugName: "userId" }] : []));
|
|
11026
11116
|
isEditMode = signal(false, ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
|
|
@@ -11032,6 +11122,92 @@ class CideCoreUserCreateComponent {
|
|
|
11032
11122
|
familyDetails = signal([], ...(ngDevMode ? [{ debugName: "familyDetails" }] : []));
|
|
11033
11123
|
entityMappings = signal([], ...(ngDevMode ? [{ debugName: "entityMappings" }] : []));
|
|
11034
11124
|
menuRightsMap = signal({}, ...(ngDevMode ? [{ debugName: "menuRightsMap" }] : []));
|
|
11125
|
+
// User rights management
|
|
11126
|
+
userRightsTypeId = signal(null, ...(ngDevMode ? [{ debugName: "userRightsTypeId" }] : []));
|
|
11127
|
+
permissions = signal([], ...(ngDevMode ? [{ debugName: "permissions" }] : []));
|
|
11128
|
+
// Template helpers
|
|
11129
|
+
Object = Object;
|
|
11130
|
+
/**
|
|
11131
|
+
* Get address type label for header display
|
|
11132
|
+
*/
|
|
11133
|
+
getAddressTypeLabel(addressIndex) {
|
|
11134
|
+
const addressTypeId = this.contactAddressesFormArray.at(addressIndex)?.get('sycad_address_type_id_sygms')?.value;
|
|
11135
|
+
if (addressTypeId) {
|
|
11136
|
+
const addressType = this.addressTypeOptions().find(option => option._id === addressTypeId);
|
|
11137
|
+
return addressType?.sygms_title || 'Address';
|
|
11138
|
+
}
|
|
11139
|
+
return 'Address';
|
|
11140
|
+
}
|
|
11141
|
+
/**
|
|
11142
|
+
* Handle address type change to update header
|
|
11143
|
+
*/
|
|
11144
|
+
onAddressTypeChange(addressIndex) {
|
|
11145
|
+
// This method is called when address type changes to trigger header update
|
|
11146
|
+
// The header will automatically update due to change detection
|
|
11147
|
+
}
|
|
11148
|
+
/**
|
|
11149
|
+
* Get document type label for header display
|
|
11150
|
+
*/
|
|
11151
|
+
getDocumentTypeLabel(documentIndex) {
|
|
11152
|
+
const documentTypeId = this.documentsFormArray.at(documentIndex)?.get('syusd_document_type_id_sygms')?.value;
|
|
11153
|
+
if (documentTypeId) {
|
|
11154
|
+
const documentType = this.documentTypeOptions().find(option => option._id === documentTypeId);
|
|
11155
|
+
return documentType?.sygms_title || 'Document';
|
|
11156
|
+
}
|
|
11157
|
+
return 'Document';
|
|
11158
|
+
}
|
|
11159
|
+
/**
|
|
11160
|
+
* Handle document type change to update header
|
|
11161
|
+
*/
|
|
11162
|
+
onDocumentTypeChange(documentIndex) {
|
|
11163
|
+
// This method is called when document type changes to trigger header update
|
|
11164
|
+
// The header will automatically update due to change detection
|
|
11165
|
+
}
|
|
11166
|
+
/**
|
|
11167
|
+
* Handle document files selection
|
|
11168
|
+
*/
|
|
11169
|
+
onDocumentFilesSelected(event, documentIndex) {
|
|
11170
|
+
const target = event.target;
|
|
11171
|
+
const files = target.files;
|
|
11172
|
+
if (!files || files.length === 0)
|
|
11173
|
+
return;
|
|
11174
|
+
console.log(`📎 Files selected for document ${documentIndex}:`, files);
|
|
11175
|
+
// Store files in the document form group or handle upload logic here
|
|
11176
|
+
const documentFormGroup = this.documentsFormArray.at(documentIndex);
|
|
11177
|
+
if (documentFormGroup) {
|
|
11178
|
+
// You can store the files in a custom property or handle upload immediately
|
|
11179
|
+
// For now, we'll store them in a custom property for display
|
|
11180
|
+
const existingFiles = this.getDocumentFiles(documentIndex);
|
|
11181
|
+
const newFiles = Array.from(files);
|
|
11182
|
+
const allFiles = [...existingFiles, ...newFiles];
|
|
11183
|
+
// Store files in the form group's custom property
|
|
11184
|
+
documentFormGroup._uploadedFiles = allFiles;
|
|
11185
|
+
console.log(`📎 Total files for document ${documentIndex}:`, allFiles.length);
|
|
11186
|
+
}
|
|
11187
|
+
}
|
|
11188
|
+
/**
|
|
11189
|
+
* Get document group ID
|
|
11190
|
+
*/
|
|
11191
|
+
getDocumentGroupId(documentIndex) {
|
|
11192
|
+
const documentFormGroup = this.documentsFormArray.at(documentIndex);
|
|
11193
|
+
return documentFormGroup?.get('syusd_photo_group_id_cyfm')?.value || '';
|
|
11194
|
+
}
|
|
11195
|
+
/**
|
|
11196
|
+
* Get uploaded files for a document (legacy method for backward compatibility)
|
|
11197
|
+
*/
|
|
11198
|
+
getDocumentFiles(documentIndex) {
|
|
11199
|
+
// For multiple file upload with group ID, we don't track individual files
|
|
11200
|
+
// Return empty array since files are managed by group ID
|
|
11201
|
+
return [];
|
|
11202
|
+
}
|
|
11203
|
+
/**
|
|
11204
|
+
* Remove a file from document (legacy method for backward compatibility)
|
|
11205
|
+
*/
|
|
11206
|
+
removeDocumentFile(documentIndex, fileName) {
|
|
11207
|
+
// For multiple file upload with group ID, individual file removal is not supported
|
|
11208
|
+
// Files are managed as a group on the server
|
|
11209
|
+
console.log(`📎 Individual file removal not supported for group uploads. Document ${documentIndex}, File: ${fileName}`);
|
|
11210
|
+
}
|
|
11035
11211
|
constructor() {
|
|
11036
11212
|
this.userMasterForm = this.fb.group({
|
|
11037
11213
|
// Basic User Information from auth_user_mst table
|
|
@@ -11093,7 +11269,8 @@ class CideCoreUserCreateComponent {
|
|
|
11093
11269
|
syenm_activeupto: [''],
|
|
11094
11270
|
syenm_isdefault: [false],
|
|
11095
11271
|
syenm_isactive: [true],
|
|
11096
|
-
syenm_isloggedin: [true]
|
|
11272
|
+
syenm_isloggedin: [true],
|
|
11273
|
+
exceptions: this.fb.array([]) // Add exceptions FormArray
|
|
11097
11274
|
});
|
|
11098
11275
|
}
|
|
11099
11276
|
// Helper method to create contact address FormGroup
|
|
@@ -11116,20 +11293,22 @@ class CideCoreUserCreateComponent {
|
|
|
11116
11293
|
}
|
|
11117
11294
|
// Helper method to create document FormGroup
|
|
11118
11295
|
createDocumentFormGroup() {
|
|
11119
|
-
|
|
11296
|
+
const formGroup = this.fb.group({
|
|
11120
11297
|
_id: [''],
|
|
11298
|
+
syusd_user_id_user: [''],
|
|
11121
11299
|
syusd_document_type_id_sygms: [''],
|
|
11122
11300
|
syusd_doc_number: [''],
|
|
11123
11301
|
syusd_doc_name_as_per_doc: [''],
|
|
11124
|
-
syusd_photo_group_id_cyfm: [''],
|
|
11125
11302
|
syusd_doc_issue_date: [''],
|
|
11126
11303
|
syusd_doc_expiry_date: [''],
|
|
11304
|
+
syusd_photo_group_id_cyfm: [''],
|
|
11127
11305
|
syusd_doc_verification_status_id_sygms: [''],
|
|
11128
|
-
|
|
11129
|
-
syusd_document_file_id_cyfm: [''],
|
|
11130
|
-
syusd_document_remarks: [''],
|
|
11306
|
+
syusd_doc_kyc_status_id_sygms: [''],
|
|
11131
11307
|
syusd_isactive: [true]
|
|
11132
11308
|
});
|
|
11309
|
+
// Initialize file storage for this document
|
|
11310
|
+
formGroup._uploadedFiles = [];
|
|
11311
|
+
return formGroup;
|
|
11133
11312
|
}
|
|
11134
11313
|
// Helper method to create family detail FormGroup
|
|
11135
11314
|
createFamilyDetailFormGroup() {
|
|
@@ -11213,7 +11392,7 @@ class CideCoreUserCreateComponent {
|
|
|
11213
11392
|
}
|
|
11214
11393
|
// Handle search change from the select component with debouncing
|
|
11215
11394
|
onUserSearchChange(searchEvent, familyIndex) {
|
|
11216
|
-
const query = searchEvent?.query
|
|
11395
|
+
const query = searchEvent?.query;
|
|
11217
11396
|
// Clear existing debounce timer for this family member
|
|
11218
11397
|
if (this.searchDebounceTimers[familyIndex]) {
|
|
11219
11398
|
clearTimeout(this.searchDebounceTimers[familyIndex]);
|
|
@@ -11239,7 +11418,7 @@ class CideCoreUserCreateComponent {
|
|
|
11239
11418
|
}
|
|
11240
11419
|
// Handle user selection change in the form
|
|
11241
11420
|
onUserSelectionChange(event, familyIndex) {
|
|
11242
|
-
const selectedUserId = event?.
|
|
11421
|
+
const selectedUserId = event?._id;
|
|
11243
11422
|
if (selectedUserId) {
|
|
11244
11423
|
// Find the selected user from the results for this specific family member
|
|
11245
11424
|
const userResults = this.userSearchResults()[familyIndex] || [];
|
|
@@ -11258,26 +11437,124 @@ class CideCoreUserCreateComponent {
|
|
|
11258
11437
|
designationOptions = signal({}, ...(ngDevMode ? [{ debugName: "designationOptions" }] : []));
|
|
11259
11438
|
departmentOptions = signal({}, ...(ngDevMode ? [{ debugName: "departmentOptions" }] : []));
|
|
11260
11439
|
menuOptions = signal([], ...(ngDevMode ? [{ debugName: "menuOptions" }] : []));
|
|
11261
|
-
permissionOptions = signal([], ...(ngDevMode ? [{ debugName: "permissionOptions" }] : []));
|
|
11262
|
-
entityRoleMap = signal({}, ...(ngDevMode ? [{ debugName: "entityRoleMap" }] : []));
|
|
11263
11440
|
// Role permissions grid properties
|
|
11264
11441
|
rolePermissionsGridConfig = signal({
|
|
11265
|
-
id: '
|
|
11266
|
-
|
|
11442
|
+
id: 'menu-list-grid',
|
|
11443
|
+
title: '',
|
|
11444
|
+
subtitle: '',
|
|
11445
|
+
columns: [
|
|
11446
|
+
{
|
|
11447
|
+
key: 'details',
|
|
11448
|
+
header: 'Menu Item',
|
|
11449
|
+
type: 'custom',
|
|
11450
|
+
width: 'auto',
|
|
11451
|
+
truncate: true,
|
|
11452
|
+
align: 'left',
|
|
11453
|
+
renderer: 'menuDetailsRenderer'
|
|
11454
|
+
},
|
|
11455
|
+
{
|
|
11456
|
+
key: 'syme_type',
|
|
11457
|
+
header: 'Type',
|
|
11458
|
+
type: 'custom',
|
|
11459
|
+
width: '120px',
|
|
11460
|
+
truncate: false,
|
|
11461
|
+
align: 'center',
|
|
11462
|
+
renderer: 'menuTypeRenderer'
|
|
11463
|
+
},
|
|
11464
|
+
{
|
|
11465
|
+
key: 'syme_path',
|
|
11466
|
+
header: 'Path',
|
|
11467
|
+
type: 'text',
|
|
11468
|
+
width: '200px',
|
|
11469
|
+
truncate: true,
|
|
11470
|
+
align: 'left'
|
|
11471
|
+
},
|
|
11472
|
+
{
|
|
11473
|
+
key: 'syme_isactive',
|
|
11474
|
+
header: 'Status',
|
|
11475
|
+
type: 'status',
|
|
11476
|
+
width: '100px',
|
|
11477
|
+
truncate: false,
|
|
11478
|
+
align: 'center',
|
|
11479
|
+
statusConfig: {
|
|
11480
|
+
activeValue: true,
|
|
11481
|
+
activeLabel: 'Active',
|
|
11482
|
+
inactiveLabel: 'Inactive',
|
|
11483
|
+
activeClass: 'tw-bg-green-100 tw-text-green-800',
|
|
11484
|
+
inactiveClass: 'tw-bg-red-100 tw-text-red-800'
|
|
11485
|
+
}
|
|
11486
|
+
},
|
|
11487
|
+
{
|
|
11488
|
+
key: 'syme_permissions_id_sygms',
|
|
11489
|
+
header: 'Permissions',
|
|
11490
|
+
type: 'custom',
|
|
11491
|
+
width: '200px',
|
|
11492
|
+
truncate: true,
|
|
11493
|
+
align: 'left',
|
|
11494
|
+
renderer: 'permissionsRenderer'
|
|
11495
|
+
},
|
|
11496
|
+
{
|
|
11497
|
+
key: 'actions',
|
|
11498
|
+
header: '',
|
|
11499
|
+
type: 'custom',
|
|
11500
|
+
width: '60px',
|
|
11501
|
+
truncate: false,
|
|
11502
|
+
align: 'center',
|
|
11503
|
+
renderer: 'actionsDropdownRenderer'
|
|
11504
|
+
}
|
|
11505
|
+
],
|
|
11267
11506
|
data: [],
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11507
|
+
trackBy: '_id',
|
|
11508
|
+
pagination: {
|
|
11509
|
+
enabled: false,
|
|
11510
|
+
pageSize: 10,
|
|
11511
|
+
pageSizeOptions: [10, 25, 50, 100],
|
|
11512
|
+
showQuickJump: true,
|
|
11513
|
+
showPageInfo: true,
|
|
11514
|
+
showRefresh: true
|
|
11515
|
+
},
|
|
11516
|
+
search: {
|
|
11517
|
+
enabled: true,
|
|
11518
|
+
placeholder: 'Search menu items...',
|
|
11519
|
+
searchableColumns: ['syme_title', 'syme_desc', 'syme_path'],
|
|
11520
|
+
debounceMs: 300
|
|
11521
|
+
},
|
|
11522
|
+
loading: {
|
|
11523
|
+
useDefer: true,
|
|
11524
|
+
skeletonRows: 5,
|
|
11525
|
+
showOverlay: false
|
|
11526
|
+
},
|
|
11527
|
+
scroll: {
|
|
11528
|
+
enabled: true,
|
|
11529
|
+
maxHeight: '',
|
|
11530
|
+
minHeight: '',
|
|
11531
|
+
stickyHeader: true,
|
|
11532
|
+
virtualScroll: false,
|
|
11533
|
+
rowHeight: 50
|
|
11534
|
+
},
|
|
11535
|
+
dragDrop: {
|
|
11536
|
+
enabled: true,
|
|
11537
|
+
orderField: 'syme_order_by',
|
|
11538
|
+
dragClass: 'tw-opacity-50 tw-bg-blue-50',
|
|
11539
|
+
dropClass: 'tw-bg-green-50'
|
|
11540
|
+
},
|
|
11273
11541
|
responsive: true,
|
|
11274
11542
|
striped: false,
|
|
11275
11543
|
bordered: true,
|
|
11276
11544
|
compact: false,
|
|
11277
|
-
tableClass: '',
|
|
11278
|
-
|
|
11545
|
+
tableClass: 'tw-table-fixed tw-w-full tw-rounded-none',
|
|
11546
|
+
onRefresh: 'onMenuItemRefresh',
|
|
11547
|
+
onRowReorder: 'onRowReorder',
|
|
11548
|
+
tree: {
|
|
11549
|
+
enabled: true,
|
|
11550
|
+
primaryKey: '_id',
|
|
11551
|
+
foreignKey: 'syme_id_syme',
|
|
11552
|
+
childrenKey: 'children',
|
|
11553
|
+
levelKey: 'level',
|
|
11554
|
+
expandedKey: 'isExpanded',
|
|
11555
|
+
hasChildrenKey: 'hasChildren'
|
|
11556
|
+
}
|
|
11279
11557
|
}, ...(ngDevMode ? [{ debugName: "rolePermissionsGridConfig" }] : []));
|
|
11280
|
-
selectedRolePermissions = signal([], ...(ngDevMode ? [{ debugName: "selectedRolePermissions" }] : []));
|
|
11281
11558
|
selectedRoleId = signal(null, ...(ngDevMode ? [{ debugName: "selectedRoleId" }] : []));
|
|
11282
11559
|
selectedEntityIndex = signal(null, ...(ngDevMode ? [{ debugName: "selectedEntityIndex" }] : []));
|
|
11283
11560
|
// Template renderers for role permissions grid
|
|
@@ -11285,6 +11562,7 @@ class CideCoreUserCreateComponent {
|
|
|
11285
11562
|
permissionsCheckboxRendererTemplate = viewChild('permissionsCheckboxRendererTemplate', ...(ngDevMode ? [{ debugName: "permissionsCheckboxRendererTemplate" }] : []));
|
|
11286
11563
|
menuTypeRendererTemplate = viewChild('menuTypeRendererTemplate', ...(ngDevMode ? [{ debugName: "menuTypeRendererTemplate" }] : []));
|
|
11287
11564
|
menuRightsPermissionsRendererTemplate = viewChild('menuRightsPermissionsRendererTemplate', ...(ngDevMode ? [{ debugName: "menuRightsPermissionsRendererTemplate" }] : []));
|
|
11565
|
+
permissionsRendererTemplate = viewChild('permissionsRendererTemplate', ...(ngDevMode ? [{ debugName: "permissionsRendererTemplate" }] : []));
|
|
11288
11566
|
addressTypeOptions = signal([], ...(ngDevMode ? [{ debugName: "addressTypeOptions" }] : []));
|
|
11289
11567
|
// Document and Family dropdown options
|
|
11290
11568
|
documentTypeOptions = signal([], ...(ngDevMode ? [{ debugName: "documentTypeOptions" }] : []));
|
|
@@ -11327,12 +11605,25 @@ class CideCoreUserCreateComponent {
|
|
|
11327
11605
|
}
|
|
11328
11606
|
// Always load dropdown options
|
|
11329
11607
|
this.loadDropdownOptions();
|
|
11608
|
+
this.loadUserRightsTypeId(); // Load user rights type and permissions
|
|
11330
11609
|
this.setupFormSubscriptions();
|
|
11331
11610
|
this.setEntityIdFromAppState();
|
|
11611
|
+
// Set up floating uploader with current user ID
|
|
11612
|
+
this.setupFloatingUploader();
|
|
11332
11613
|
// Load initial users for family member selection
|
|
11333
11614
|
this.loadInitialUsers();
|
|
11334
11615
|
});
|
|
11335
11616
|
}
|
|
11617
|
+
/**
|
|
11618
|
+
* Setup floating uploader with current user ID
|
|
11619
|
+
*/
|
|
11620
|
+
setupFloatingUploader() {
|
|
11621
|
+
// Get current user ID from app state or use a default
|
|
11622
|
+
const currentUser = this.appState.getCurrentUser();
|
|
11623
|
+
const currentUserId = currentUser?._id || 'current-user';
|
|
11624
|
+
this.floatingUploadService.setCurrentUserId(currentUserId);
|
|
11625
|
+
console.log('🚀 [UserCreate] Floating uploader setup with user ID:', currentUserId);
|
|
11626
|
+
}
|
|
11336
11627
|
/**
|
|
11337
11628
|
* Setup form subscriptions
|
|
11338
11629
|
*/
|
|
@@ -11541,9 +11832,42 @@ class CideCoreUserCreateComponent {
|
|
|
11541
11832
|
mappingGroup.get('syenm_entity_id_syen')?.disable();
|
|
11542
11833
|
entityMappingFormArray.push(mappingGroup);
|
|
11543
11834
|
});
|
|
11835
|
+
// Load role permissions for each mapping that has a role selected
|
|
11836
|
+
data.core_entity_mapping.forEach((mapping, index) => {
|
|
11837
|
+
if (mapping.syenm_role_id_syusrol) {
|
|
11838
|
+
const roleId = typeof mapping.syenm_role_id_syusrol === 'object'
|
|
11839
|
+
? mapping.syenm_role_id_syusrol._id
|
|
11840
|
+
: mapping.syenm_role_id_syusrol;
|
|
11841
|
+
if (roleId) {
|
|
11842
|
+
console.log(`🎭 Loading role permissions for mapping ${index} with role ${roleId}`);
|
|
11843
|
+
this.loadRolePermissions(roleId, index);
|
|
11844
|
+
}
|
|
11845
|
+
}
|
|
11846
|
+
});
|
|
11544
11847
|
}
|
|
11545
|
-
|
|
11546
|
-
|
|
11848
|
+
// Handle existing role exceptions
|
|
11849
|
+
if (data.core_user_role_exceptions && Array.isArray(data.core_user_role_exceptions)) {
|
|
11850
|
+
console.log('🎭 Loading existing role exceptions:', data.core_user_role_exceptions);
|
|
11851
|
+
// Group exceptions by mapping index
|
|
11852
|
+
const exceptionsByMapping = {};
|
|
11853
|
+
data.core_user_role_exceptions.forEach((exception) => {
|
|
11854
|
+
// Find the mapping index for this exception
|
|
11855
|
+
const mappingIndex = this.findMappingIndexByEntityMappingId(exception.syusrex_user_entity_mapping_id_syenm || '');
|
|
11856
|
+
if (mappingIndex !== null) {
|
|
11857
|
+
if (!exceptionsByMapping[mappingIndex.toString()]) {
|
|
11858
|
+
exceptionsByMapping[mappingIndex.toString()] = [];
|
|
11859
|
+
}
|
|
11860
|
+
exceptionsByMapping[mappingIndex.toString()].push(exception);
|
|
11861
|
+
}
|
|
11862
|
+
});
|
|
11863
|
+
// Add exceptions to each mapping
|
|
11864
|
+
Object.keys(exceptionsByMapping).forEach(mappingIndexStr => {
|
|
11865
|
+
const mappingIndex = parseInt(mappingIndexStr);
|
|
11866
|
+
const mapping = this.entityMappings()[mappingIndex];
|
|
11867
|
+
if (mapping) {
|
|
11868
|
+
mapping.exceptions = exceptionsByMapping[mappingIndexStr];
|
|
11869
|
+
}
|
|
11870
|
+
});
|
|
11547
11871
|
}
|
|
11548
11872
|
if (data.core_user_contact_addresses) {
|
|
11549
11873
|
this.contactAddresses.set(data.core_user_contact_addresses);
|
|
@@ -11578,6 +11902,7 @@ class CideCoreUserCreateComponent {
|
|
|
11578
11902
|
const documentGroup = this.createDocumentFormGroup();
|
|
11579
11903
|
documentGroup.patchValue({
|
|
11580
11904
|
_id: document._id || '',
|
|
11905
|
+
syusd_user_id_user: this.appState.getUserId() || '',
|
|
11581
11906
|
syusd_document_type_id_sygms: document.syusd_document_type_id_sygms?._id || '',
|
|
11582
11907
|
syusd_doc_number: document.syusd_doc_number || '',
|
|
11583
11908
|
syusd_doc_name_as_per_doc: document.syusd_doc_name_as_per_doc || '',
|
|
@@ -11585,9 +11910,7 @@ class CideCoreUserCreateComponent {
|
|
|
11585
11910
|
syusd_doc_issue_date: document.syusd_doc_issue_date || '',
|
|
11586
11911
|
syusd_doc_expiry_date: document.syusd_doc_expiry_date || '',
|
|
11587
11912
|
syusd_doc_verification_status_id_sygms: document.syusd_doc_verification_status_id_sygms?._id || '',
|
|
11588
|
-
|
|
11589
|
-
syusd_document_file_id_cyfm: document.syusd_document_file_id_cyfm || '',
|
|
11590
|
-
syusd_document_remarks: document.syusd_document_remarks || '',
|
|
11913
|
+
syusd_doc_kyc_status_id_sygms: document.syusd_doc_kyc_status_id_sygms?._id || '',
|
|
11591
11914
|
syusd_isactive: document.syusd_isactive ?? true
|
|
11592
11915
|
});
|
|
11593
11916
|
this.documentsFormArray.push(documentGroup);
|
|
@@ -11643,25 +11966,8 @@ class CideCoreUserCreateComponent {
|
|
|
11643
11966
|
this.loadDocumentKycStatus();
|
|
11644
11967
|
this.loadBloodGroups();
|
|
11645
11968
|
this.loadRelationshipOptions();
|
|
11646
|
-
// Load menu options
|
|
11647
|
-
this.
|
|
11648
|
-
{ value: 'user-management', label: 'User Management', menu_code: 'USRMGT' },
|
|
11649
|
-
{ value: 'entity-management', label: 'Entity Management', menu_code: 'ENTMGT' },
|
|
11650
|
-
{ value: 'role-management', label: 'Role Management', menu_code: 'ROLMGT' },
|
|
11651
|
-
{ value: 'reports', label: 'Reports', menu_code: 'RPTS' },
|
|
11652
|
-
{ value: 'settings', label: 'Settings', menu_code: 'STGS' },
|
|
11653
|
-
{ value: 'dashboard', label: 'Dashboard', menu_code: 'DASH' },
|
|
11654
|
-
{ value: 'file-manager', label: 'File Manager', menu_code: 'FMGR' }
|
|
11655
|
-
]);
|
|
11656
|
-
// Load permission options (simulated data)
|
|
11657
|
-
this.permissionOptions.set([
|
|
11658
|
-
{ value: 'create', label: 'Create' },
|
|
11659
|
-
{ value: 'read', label: 'Read' },
|
|
11660
|
-
{ value: 'update', label: 'Update' },
|
|
11661
|
-
{ value: 'delete', label: 'Delete' },
|
|
11662
|
-
{ value: 'approve', label: 'Approve' },
|
|
11663
|
-
{ value: 'reject', label: 'Reject' }
|
|
11664
|
-
]);
|
|
11969
|
+
// Load menu options from API
|
|
11970
|
+
this.loadMenuOptions();
|
|
11665
11971
|
}
|
|
11666
11972
|
relationshipOptions() {
|
|
11667
11973
|
return this.relationshipOptionsData();
|
|
@@ -11727,6 +12033,12 @@ class CideCoreUserCreateComponent {
|
|
|
11727
12033
|
}
|
|
11728
12034
|
// Trigger change detection to update other entity dropdowns
|
|
11729
12035
|
this.triggerEntityDropdownUpdate();
|
|
12036
|
+
// Automatically load menu rights when both entity and role are selected
|
|
12037
|
+
const mapping = this.entityMappings()[mappingIndex];
|
|
12038
|
+
if (mapping?.syenm_entity_id_syen && mapping?.syenm_role_id_syusrol) {
|
|
12039
|
+
console.log(`🚀 Auto-loading menu rights for mapping ${mappingIndex}`);
|
|
12040
|
+
this.loadMenuRights(mappingIndex);
|
|
12041
|
+
}
|
|
11730
12042
|
// For now, we'll use all available roles
|
|
11731
12043
|
// In a real implementation, you'd filter roles based on the entity
|
|
11732
12044
|
}
|
|
@@ -11981,10 +12293,9 @@ class CideCoreUserCreateComponent {
|
|
|
11981
12293
|
*/
|
|
11982
12294
|
initializeRolePermissionsGrid() {
|
|
11983
12295
|
this.rolePermissionsGridConfig.set({
|
|
11984
|
-
id: '
|
|
11985
|
-
title: '
|
|
11986
|
-
subtitle: '
|
|
11987
|
-
fullHeight: true,
|
|
12296
|
+
id: 'menu-list-grid',
|
|
12297
|
+
title: '',
|
|
12298
|
+
subtitle: '',
|
|
11988
12299
|
columns: [
|
|
11989
12300
|
{
|
|
11990
12301
|
key: 'details',
|
|
@@ -12004,14 +12315,46 @@ class CideCoreUserCreateComponent {
|
|
|
12004
12315
|
align: 'center',
|
|
12005
12316
|
renderer: 'menuTypeRenderer'
|
|
12006
12317
|
},
|
|
12318
|
+
{
|
|
12319
|
+
key: 'syme_path',
|
|
12320
|
+
header: 'Path',
|
|
12321
|
+
type: 'text',
|
|
12322
|
+
width: '200px',
|
|
12323
|
+
truncate: true,
|
|
12324
|
+
align: 'left'
|
|
12325
|
+
},
|
|
12326
|
+
{
|
|
12327
|
+
key: 'syme_isactive',
|
|
12328
|
+
header: 'Status',
|
|
12329
|
+
type: 'status',
|
|
12330
|
+
width: '100px',
|
|
12331
|
+
truncate: false,
|
|
12332
|
+
align: 'center',
|
|
12333
|
+
statusConfig: {
|
|
12334
|
+
activeValue: true,
|
|
12335
|
+
activeLabel: 'Active',
|
|
12336
|
+
inactiveLabel: 'Inactive',
|
|
12337
|
+
activeClass: 'tw-bg-green-100 tw-text-green-800',
|
|
12338
|
+
inactiveClass: 'tw-bg-red-100 tw-text-red-800'
|
|
12339
|
+
}
|
|
12340
|
+
},
|
|
12007
12341
|
{
|
|
12008
12342
|
key: 'syme_permissions_id_sygms',
|
|
12009
|
-
header: '
|
|
12343
|
+
header: 'Permissions',
|
|
12010
12344
|
type: 'custom',
|
|
12011
|
-
width: '
|
|
12012
|
-
truncate:
|
|
12345
|
+
width: '200px',
|
|
12346
|
+
truncate: true,
|
|
12013
12347
|
align: 'left',
|
|
12014
|
-
renderer: '
|
|
12348
|
+
renderer: 'permissionsRenderer'
|
|
12349
|
+
},
|
|
12350
|
+
{
|
|
12351
|
+
key: 'actions',
|
|
12352
|
+
header: '',
|
|
12353
|
+
type: 'custom',
|
|
12354
|
+
width: '60px',
|
|
12355
|
+
truncate: false,
|
|
12356
|
+
align: 'center',
|
|
12357
|
+
renderer: 'actionsDropdownRenderer'
|
|
12015
12358
|
}
|
|
12016
12359
|
],
|
|
12017
12360
|
data: [],
|
|
@@ -12031,20 +12374,20 @@ class CideCoreUserCreateComponent {
|
|
|
12031
12374
|
debounceMs: 300
|
|
12032
12375
|
},
|
|
12033
12376
|
loading: {
|
|
12034
|
-
useDefer:
|
|
12377
|
+
useDefer: true,
|
|
12035
12378
|
skeletonRows: 5,
|
|
12036
12379
|
showOverlay: false
|
|
12037
12380
|
},
|
|
12038
12381
|
scroll: {
|
|
12039
12382
|
enabled: true,
|
|
12040
|
-
maxHeight: '
|
|
12041
|
-
minHeight: '
|
|
12383
|
+
maxHeight: '',
|
|
12384
|
+
minHeight: '',
|
|
12042
12385
|
stickyHeader: true,
|
|
12043
12386
|
virtualScroll: false,
|
|
12044
|
-
rowHeight:
|
|
12387
|
+
rowHeight: 50
|
|
12045
12388
|
},
|
|
12046
12389
|
dragDrop: {
|
|
12047
|
-
enabled:
|
|
12390
|
+
enabled: true,
|
|
12048
12391
|
orderField: 'syme_order_by',
|
|
12049
12392
|
dragClass: 'tw-opacity-50 tw-bg-blue-50',
|
|
12050
12393
|
dropClass: 'tw-bg-green-50'
|
|
@@ -12054,10 +12397,16 @@ class CideCoreUserCreateComponent {
|
|
|
12054
12397
|
bordered: true,
|
|
12055
12398
|
compact: false,
|
|
12056
12399
|
tableClass: 'tw-table-fixed tw-w-full tw-rounded-none',
|
|
12400
|
+
onRefresh: 'onMenuItemRefresh',
|
|
12401
|
+
onRowReorder: 'onRowReorder',
|
|
12057
12402
|
tree: {
|
|
12058
12403
|
enabled: true,
|
|
12059
12404
|
primaryKey: '_id',
|
|
12060
|
-
foreignKey: '
|
|
12405
|
+
foreignKey: 'syme_id_syme',
|
|
12406
|
+
childrenKey: 'children',
|
|
12407
|
+
levelKey: 'level',
|
|
12408
|
+
expandedKey: 'isExpanded',
|
|
12409
|
+
hasChildrenKey: 'hasChildren'
|
|
12061
12410
|
}
|
|
12062
12411
|
});
|
|
12063
12412
|
}
|
|
@@ -12073,12 +12422,22 @@ class CideCoreUserCreateComponent {
|
|
|
12073
12422
|
this.selectedEntityIndex.set(mappingIndex);
|
|
12074
12423
|
this.selectedRoleId.set(roleId);
|
|
12075
12424
|
// Load role details and permissions
|
|
12076
|
-
this.loadRolePermissions(roleId);
|
|
12425
|
+
this.loadRolePermissions(roleId, mappingIndex);
|
|
12426
|
+
// Automatically load menu rights when both entity and role are selected
|
|
12427
|
+
const mapping = this.entityMappings()[mappingIndex];
|
|
12428
|
+
if (mapping?.syenm_entity_id_syen && mapping?.syenm_role_id_syusrol) {
|
|
12429
|
+
console.log(`🚀 Auto-loading menu rights for mapping ${mappingIndex}`);
|
|
12430
|
+
this.loadMenuRights(mappingIndex);
|
|
12431
|
+
// Force refresh the grid to show updated permission states
|
|
12432
|
+
setTimeout(() => {
|
|
12433
|
+
this.cdr.detectChanges();
|
|
12434
|
+
}, 100);
|
|
12435
|
+
}
|
|
12077
12436
|
}
|
|
12078
12437
|
/**
|
|
12079
12438
|
* Load role permissions from API
|
|
12080
12439
|
*/
|
|
12081
|
-
loadRolePermissions(roleId) {
|
|
12440
|
+
loadRolePermissions(roleId, mappingIndex) {
|
|
12082
12441
|
console.log(`🎭 Loading permissions for role:`, roleId);
|
|
12083
12442
|
this.loading.set(true);
|
|
12084
12443
|
// Load role details by ID
|
|
@@ -12086,8 +12445,8 @@ class CideCoreUserCreateComponent {
|
|
|
12086
12445
|
next: (response) => {
|
|
12087
12446
|
if (response?.success && response.data) {
|
|
12088
12447
|
console.log(`🎭 Role details loaded:`, response.data);
|
|
12089
|
-
//
|
|
12090
|
-
this.
|
|
12448
|
+
// Store role permissions for simple lookup
|
|
12449
|
+
this.storeRolePermissions(response.data, mappingIndex);
|
|
12091
12450
|
}
|
|
12092
12451
|
else {
|
|
12093
12452
|
console.error(`❌ Failed to load role details:`, response);
|
|
@@ -12103,119 +12462,109 @@ class CideCoreUserCreateComponent {
|
|
|
12103
12462
|
});
|
|
12104
12463
|
}
|
|
12105
12464
|
/**
|
|
12106
|
-
*
|
|
12107
|
-
*/
|
|
12108
|
-
loadMenusAndPermissionsForRole(roleData) {
|
|
12109
|
-
console.log(`🎭 Loading menus and permissions for role:`, roleData);
|
|
12110
|
-
// Load menus from API
|
|
12111
|
-
this.loadMenusFromAPI().then(() => {
|
|
12112
|
-
// Load permissions from general master
|
|
12113
|
-
this.loadPermissionsFromAPI().then(() => {
|
|
12114
|
-
// Build the tree structure with role permissions
|
|
12115
|
-
this.buildRolePermissionsTree(roleData);
|
|
12116
|
-
});
|
|
12117
|
-
});
|
|
12118
|
-
}
|
|
12119
|
-
/**
|
|
12120
|
-
* Load menus from API
|
|
12465
|
+
* Update permission values for a specific menu row
|
|
12121
12466
|
*/
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
else {
|
|
12141
|
-
console.error(`❌ Failed to load menus:`, response);
|
|
12142
|
-
reject('Failed to load menus');
|
|
12467
|
+
updateMenuPermissionValues(mappingIndex, menuId) {
|
|
12468
|
+
this.menuRightsMap.update(map => {
|
|
12469
|
+
const newMap = { ...map };
|
|
12470
|
+
const menuRights = newMap[mappingIndex.toString()] || [];
|
|
12471
|
+
const updatedMenuRights = menuRights.map(menu => {
|
|
12472
|
+
if (menu._id === menuId) {
|
|
12473
|
+
// Re-compute permission values for this menu
|
|
12474
|
+
const permissionValues = {};
|
|
12475
|
+
if (menu.syme_permissions_id_sygms) {
|
|
12476
|
+
menu.syme_permissions_id_sygms.forEach(permissionId => {
|
|
12477
|
+
const permission = this.getPermissionById(permissionId);
|
|
12478
|
+
if (permission) {
|
|
12479
|
+
permissionValues[permissionId] = {
|
|
12480
|
+
checked: this.getFormControlValue(menu, permissionId),
|
|
12481
|
+
permission: permission
|
|
12482
|
+
};
|
|
12483
|
+
}
|
|
12484
|
+
});
|
|
12143
12485
|
}
|
|
12144
|
-
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12486
|
+
return {
|
|
12487
|
+
...menu,
|
|
12488
|
+
_permissionValues: permissionValues
|
|
12489
|
+
};
|
|
12148
12490
|
}
|
|
12491
|
+
return menu;
|
|
12149
12492
|
});
|
|
12493
|
+
newMap[mappingIndex.toString()] = updatedMenuRights;
|
|
12494
|
+
return newMap;
|
|
12150
12495
|
});
|
|
12151
12496
|
}
|
|
12152
12497
|
/**
|
|
12153
|
-
*
|
|
12498
|
+
* Store role permissions for simple lookup
|
|
12154
12499
|
*/
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
|
|
12163
|
-
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12500
|
+
storeRolePermissions(roleData, mappingIndex) {
|
|
12501
|
+
console.log(`🎭 Storing role permissions for mapping ${mappingIndex}:`, roleData);
|
|
12502
|
+
// Extract role permissions from the role data
|
|
12503
|
+
const roleRights = roleData.core_user_role_rights;
|
|
12504
|
+
if (roleRights && Array.isArray(roleRights)) {
|
|
12505
|
+
// Store role permissions as objects with ID and title
|
|
12506
|
+
const rolePermissionObjects = roleRights.map((right) => {
|
|
12507
|
+
const permission = right.syusrgt_role_permissions_id_sygms;
|
|
12508
|
+
return {
|
|
12509
|
+
_id: permission?._id,
|
|
12510
|
+
sygms_title: permission?.sygms_title,
|
|
12511
|
+
menu_id: right.syusrgt_menu_id_syme?._id
|
|
12512
|
+
};
|
|
12513
|
+
}).filter((permission) => permission._id && permission.sygms_title);
|
|
12514
|
+
// Update menuRightsMap with role permissions for each menu
|
|
12515
|
+
this.menuRightsMap.update(menuMap => {
|
|
12516
|
+
const newMenuMap = { ...menuMap };
|
|
12517
|
+
const currentMenuRights = newMenuMap[mappingIndex.toString()] || [];
|
|
12518
|
+
// Update each menu with its role permissions
|
|
12519
|
+
const updatedMenuRights = currentMenuRights.map(menu => {
|
|
12520
|
+
if (menu._id) {
|
|
12521
|
+
const menuSpecificPermissions = rolePermissionObjects
|
|
12522
|
+
.filter(permission =>
|
|
12523
|
+
// Permission must be in the menu's allowed permissions list
|
|
12524
|
+
menu.syme_permissions_id_sygms?.includes(permission._id) &&
|
|
12525
|
+
// AND must be assigned to this menu in the role data
|
|
12526
|
+
permission.menu_id === menu._id);
|
|
12527
|
+
return {
|
|
12528
|
+
...menu,
|
|
12529
|
+
_rolePermissions: menuSpecificPermissions
|
|
12530
|
+
};
|
|
12168
12531
|
}
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12532
|
+
return menu;
|
|
12533
|
+
});
|
|
12534
|
+
newMenuMap[mappingIndex.toString()] = updatedMenuRights;
|
|
12535
|
+
return newMenuMap;
|
|
12536
|
+
});
|
|
12537
|
+
// Update permission values for all menus in this mapping
|
|
12538
|
+
const menuRights = this.menuRightsMap()[mappingIndex.toString()] || [];
|
|
12539
|
+
menuRights.forEach(menu => {
|
|
12540
|
+
if (menu._id) {
|
|
12541
|
+
this.updateMenuPermissionValues(mappingIndex, menu._id);
|
|
12173
12542
|
}
|
|
12174
12543
|
});
|
|
12175
|
-
|
|
12544
|
+
console.log(`🎭 Stored role permission objects for mapping ${mappingIndex}:`, rolePermissionObjects);
|
|
12545
|
+
}
|
|
12546
|
+
else {
|
|
12547
|
+
console.log(`🎭 No role permissions found in role data`);
|
|
12548
|
+
}
|
|
12176
12549
|
}
|
|
12177
12550
|
/**
|
|
12178
|
-
*
|
|
12179
|
-
*/
|
|
12180
|
-
buildRolePermissionsTree(roleData) {
|
|
12181
|
-
console.log(`🎭 Building permissions tree for role:`, roleData);
|
|
12182
|
-
const menus = this.menuOptions();
|
|
12183
|
-
const permissions = this.permissionOptions();
|
|
12184
|
-
// Create a map of role permissions for quick lookup
|
|
12185
|
-
const rolePermissionsMap = new Map();
|
|
12186
|
-
if (roleData.roleRights && Array.isArray(roleData.roleRights)) {
|
|
12187
|
-
roleData.roleRights.forEach((right) => {
|
|
12188
|
-
const key = `${right.syusrgt_menu_id_syme}_${right.syusrgt_role_permissions_id_sygms}`;
|
|
12189
|
-
rolePermissionsMap.set(key, right);
|
|
12190
|
-
});
|
|
12191
|
-
}
|
|
12192
|
-
// Build tree structure with permissions
|
|
12193
|
-
const treeData = menus.map(menu => ({
|
|
12194
|
-
...menu,
|
|
12195
|
-
permissions: permissions.map(permission => ({
|
|
12196
|
-
...permission,
|
|
12197
|
-
isSelected: rolePermissionsMap.has(`${menu._id}_${permission._id}`)
|
|
12198
|
-
}))
|
|
12199
|
-
}));
|
|
12200
|
-
console.log(`🎭 Tree data built:`, treeData);
|
|
12201
|
-
this.selectedRolePermissions.set(treeData);
|
|
12202
|
-
// Update grid data
|
|
12203
|
-
this.rolePermissionsGridConfig.update(config => ({
|
|
12204
|
-
...config,
|
|
12205
|
-
data: treeData
|
|
12206
|
-
}));
|
|
12207
|
-
}
|
|
12208
|
-
/**
|
|
12209
|
-
* Clear role permissions
|
|
12551
|
+
* Clear role permissions
|
|
12210
12552
|
*/
|
|
12211
12553
|
clearRolePermissions() {
|
|
12212
|
-
this.selectedRolePermissions.set([]);
|
|
12213
12554
|
this.selectedRoleId.set(null);
|
|
12214
12555
|
this.selectedEntityIndex.set(null);
|
|
12215
|
-
|
|
12216
|
-
|
|
12217
|
-
|
|
12218
|
-
|
|
12556
|
+
}
|
|
12557
|
+
/**
|
|
12558
|
+
* Find mapping index by entity mapping ID
|
|
12559
|
+
*/
|
|
12560
|
+
findMappingIndexByEntityMappingId(entityMappingId) {
|
|
12561
|
+
const mappings = this.entityMappings();
|
|
12562
|
+
for (let i = 0; i < mappings.length; i++) {
|
|
12563
|
+
if (mappings[i]._id === entityMappingId) {
|
|
12564
|
+
return i;
|
|
12565
|
+
}
|
|
12566
|
+
}
|
|
12567
|
+
return null;
|
|
12219
12568
|
}
|
|
12220
12569
|
/**
|
|
12221
12570
|
* Handle grid events for role permissions
|
|
@@ -12247,20 +12596,272 @@ class CideCoreUserCreateComponent {
|
|
|
12247
12596
|
* Get permission by ID
|
|
12248
12597
|
*/
|
|
12249
12598
|
getPermissionById(permissionId) {
|
|
12250
|
-
return this.
|
|
12599
|
+
return this.permissions().find(permission => permission._id === permissionId);
|
|
12251
12600
|
}
|
|
12252
12601
|
/**
|
|
12253
|
-
* Check if permission is selected for a menu
|
|
12602
|
+
* Check if permission is available in the selected role for a specific menu
|
|
12254
12603
|
*/
|
|
12255
|
-
|
|
12256
|
-
const
|
|
12257
|
-
const
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12604
|
+
isPermissionInRole(permissionId, mappingIndex, menuId) {
|
|
12605
|
+
const mapping = this.entityMappings()[mappingIndex];
|
|
12606
|
+
const roleId = mapping?.syenm_role_id_syusrol;
|
|
12607
|
+
console.log(`🎭 Checking permission ${permissionId} for role:`, roleId, 'menu:', menuId);
|
|
12608
|
+
if (!roleId || !menuId) {
|
|
12609
|
+
console.log(`🎭 No role ID or menu ID found for mapping ${mappingIndex}`);
|
|
12610
|
+
return false;
|
|
12261
12611
|
}
|
|
12612
|
+
// Get role permissions from the menu objects in menuRightsMap
|
|
12613
|
+
const menuRights = this.menuRightsMap()[mappingIndex.toString()] || [];
|
|
12614
|
+
const menu = menuRights.find(m => m._id === menuId);
|
|
12615
|
+
if (menu && menu._rolePermissions) {
|
|
12616
|
+
const rolePermissions = menu._rolePermissions;
|
|
12617
|
+
const isInRole = rolePermissions.some((permission) => permission._id === permissionId && permission.menu_id === menuId);
|
|
12618
|
+
console.log(`🎭 Permission ${permissionId} in role for menu ${menuId}: ${isInRole}`);
|
|
12619
|
+
return isInRole;
|
|
12620
|
+
}
|
|
12621
|
+
console.log(`🎭 No role permissions found for mapping ${mappingIndex}, menu ${menuId}`);
|
|
12262
12622
|
return false;
|
|
12263
12623
|
}
|
|
12624
|
+
/**
|
|
12625
|
+
* Get form control value for a permission
|
|
12626
|
+
*/
|
|
12627
|
+
getFormControlValue(row, permissionId) {
|
|
12628
|
+
console.log(`🎭 Getting form control value for permission: ${permissionId} for menu: ${row.syme_title}`, row);
|
|
12629
|
+
const permission = this.getPermissionById(permissionId);
|
|
12630
|
+
if (!permission) {
|
|
12631
|
+
console.log(`🎭 Permission not found for ID: ${permissionId}`);
|
|
12632
|
+
return false;
|
|
12633
|
+
}
|
|
12634
|
+
// Find the current mapping index
|
|
12635
|
+
const mappingIndex = this.getCurrentMappingIndex();
|
|
12636
|
+
if (mappingIndex === null) {
|
|
12637
|
+
console.log(`🎭 No current mapping index found`);
|
|
12638
|
+
return false;
|
|
12639
|
+
}
|
|
12640
|
+
// Check if permission is available in the role for this specific menu
|
|
12641
|
+
const isRolePermission = this.isPermissionInRole(permissionId, mappingIndex, row._id);
|
|
12642
|
+
console.log(`🎭 Permission ${permission.sygms_title} for menu ${row.syme_title}: isRolePermission = ${isRolePermission}`);
|
|
12643
|
+
if (isRolePermission) {
|
|
12644
|
+
// If permission is in role, it should be checked by default
|
|
12645
|
+
console.log(`🎭 Returning true for role permission: ${permission.sygms_title}`);
|
|
12646
|
+
return true;
|
|
12647
|
+
}
|
|
12648
|
+
else {
|
|
12649
|
+
// If permission is not in role, check if it's added as exception
|
|
12650
|
+
const mapping = this.entityMappings()[mappingIndex];
|
|
12651
|
+
const exceptions = mapping.exceptions || [];
|
|
12652
|
+
const isException = exceptions.some((exception) => exception.syusrex_menu_id_syme === row._id &&
|
|
12653
|
+
exception.syusrex_role_permissions_id_sygms === permissionId);
|
|
12654
|
+
console.log(`🎭 Permission ${permission.sygms_title} is exception: ${isException}`);
|
|
12655
|
+
return isException;
|
|
12656
|
+
}
|
|
12657
|
+
}
|
|
12658
|
+
/**
|
|
12659
|
+
* Handle permission change with type safety
|
|
12660
|
+
*/
|
|
12661
|
+
onPermissionChangeSafe(checked, row, permissionId) {
|
|
12662
|
+
this.onPermissionChange(Boolean(checked), row, permissionId);
|
|
12663
|
+
}
|
|
12664
|
+
/**
|
|
12665
|
+
* Handle permission change
|
|
12666
|
+
*/
|
|
12667
|
+
onPermissionChange(checked, row, permissionId) {
|
|
12668
|
+
const permission = this.getPermissionById(permissionId);
|
|
12669
|
+
if (!permission)
|
|
12670
|
+
return;
|
|
12671
|
+
// Find the current mapping index
|
|
12672
|
+
const mappingIndex = this.getCurrentMappingIndex();
|
|
12673
|
+
if (mappingIndex === null)
|
|
12674
|
+
return;
|
|
12675
|
+
// Check if permission is in role for this specific menu
|
|
12676
|
+
const isRolePermission = this.isPermissionInRole(permissionId, mappingIndex, row._id);
|
|
12677
|
+
if (isRolePermission) {
|
|
12678
|
+
// Role permissions are handled by the role itself, no form controls needed
|
|
12679
|
+
console.log('🎭 Role permission (handled by role):', {
|
|
12680
|
+
menu: row.syme_title,
|
|
12681
|
+
permission: permission.sygms_title,
|
|
12682
|
+
checked: checked
|
|
12683
|
+
});
|
|
12684
|
+
}
|
|
12685
|
+
else {
|
|
12686
|
+
// Handle exception permission
|
|
12687
|
+
if (checked) {
|
|
12688
|
+
// Add exception
|
|
12689
|
+
this.addRoleException(mappingIndex, row._id || '', permissionId);
|
|
12690
|
+
}
|
|
12691
|
+
else {
|
|
12692
|
+
// Remove exception
|
|
12693
|
+
this.removeRoleException(mappingIndex, row._id || '', permissionId);
|
|
12694
|
+
}
|
|
12695
|
+
console.log('🎭 Exception permission changed:', {
|
|
12696
|
+
menu: row.syme_title,
|
|
12697
|
+
permission: permission.sygms_title,
|
|
12698
|
+
checked: checked
|
|
12699
|
+
});
|
|
12700
|
+
}
|
|
12701
|
+
// Update the pre-computed permission values for this menu
|
|
12702
|
+
this.updateMenuPermissionValues(mappingIndex, row._id || '');
|
|
12703
|
+
}
|
|
12704
|
+
/**
|
|
12705
|
+
* Handle permission change for specific mapping
|
|
12706
|
+
*/
|
|
12707
|
+
onPermissionChangeForMapping(checked, row, permissionId, mappingIndex) {
|
|
12708
|
+
const permission = this.getPermissionById(permissionId);
|
|
12709
|
+
if (!permission)
|
|
12710
|
+
return;
|
|
12711
|
+
const controlName = `core_entity_mapping.${mappingIndex}.menu_rights.${row._id}.${permission.sygms_title}`;
|
|
12712
|
+
this.userMasterForm.get(controlName)?.setValue(checked);
|
|
12713
|
+
console.log('🎭 Permission changed for mapping:', {
|
|
12714
|
+
mappingIndex,
|
|
12715
|
+
menu: row.syme_title,
|
|
12716
|
+
permission: permission.sygms_title,
|
|
12717
|
+
checked: checked,
|
|
12718
|
+
controlName
|
|
12719
|
+
});
|
|
12720
|
+
}
|
|
12721
|
+
/**
|
|
12722
|
+
* Get current mapping index (helper method)
|
|
12723
|
+
*/
|
|
12724
|
+
getCurrentMappingIndex() {
|
|
12725
|
+
// Find the mapping index that has both entity and role selected
|
|
12726
|
+
const entityMappings = this.entityMappings();
|
|
12727
|
+
for (let i = 0; i < entityMappings.length; i++) {
|
|
12728
|
+
const entityId = this.userMasterForm.get(`core_entity_mapping.${i}.syenm_entity_id_syen`)?.value;
|
|
12729
|
+
const roleId = this.userMasterForm.get(`core_entity_mapping.${i}.syenm_role_id_syusrol`)?.value;
|
|
12730
|
+
if (entityId && roleId) {
|
|
12731
|
+
return i;
|
|
12732
|
+
}
|
|
12733
|
+
}
|
|
12734
|
+
return null;
|
|
12735
|
+
}
|
|
12736
|
+
/**
|
|
12737
|
+
* Add role exception
|
|
12738
|
+
*/
|
|
12739
|
+
addRoleException(mappingIndex, menuId, permissionId) {
|
|
12740
|
+
const mapping = this.entityMappings()[mappingIndex];
|
|
12741
|
+
const permission = this.getPermissionById(permissionId);
|
|
12742
|
+
if (!mapping || !permission)
|
|
12743
|
+
return;
|
|
12744
|
+
// Get the role ID directly (not as object)
|
|
12745
|
+
const roleId = typeof mapping.syenm_role_id_syusrol === 'object'
|
|
12746
|
+
? mapping.syenm_role_id_syusrol?._id ?? ''
|
|
12747
|
+
: mapping.syenm_role_id_syusrol ?? '';
|
|
12748
|
+
// Create exception object with change tracking
|
|
12749
|
+
const exception = {
|
|
12750
|
+
syusrex_user_entity_mapping_id_syenm: mapping._id || '',
|
|
12751
|
+
syusrex_role_id_syusrol: roleId, // Direct ID string
|
|
12752
|
+
syusrex_role_permissions_id_sygms: permissionId,
|
|
12753
|
+
syusrex_menu_id_syme: menuId,
|
|
12754
|
+
syusrex_isactive: true,
|
|
12755
|
+
_isUserAdded: true, // Mark as explicitly added by user
|
|
12756
|
+
_changeType: 'added' // Track the change type
|
|
12757
|
+
};
|
|
12758
|
+
// Add to entity mapping exceptions (check for duplicates first)
|
|
12759
|
+
this.entityMappings.update(mappings => {
|
|
12760
|
+
const updatedMappings = [...mappings];
|
|
12761
|
+
const mappingWithExceptions = updatedMappings[mappingIndex];
|
|
12762
|
+
if (!mappingWithExceptions.exceptions) {
|
|
12763
|
+
mappingWithExceptions.exceptions = [];
|
|
12764
|
+
}
|
|
12765
|
+
// Check if exception already exists to prevent duplicates
|
|
12766
|
+
const existingException = mappingWithExceptions.exceptions.find(ex => ex.syusrex_menu_id_syme === menuId &&
|
|
12767
|
+
ex.syusrex_role_permissions_id_sygms === permissionId);
|
|
12768
|
+
if (!existingException) {
|
|
12769
|
+
mappingWithExceptions.exceptions.push(exception);
|
|
12770
|
+
console.log('🎭 Role exception added (new):', exception);
|
|
12771
|
+
}
|
|
12772
|
+
else {
|
|
12773
|
+
// If exception exists but was removed, mark it as added again
|
|
12774
|
+
if (existingException._isUserRemoved) {
|
|
12775
|
+
existingException._isUserRemoved = false;
|
|
12776
|
+
existingException._isUserAdded = true;
|
|
12777
|
+
existingException._changeType = 'added';
|
|
12778
|
+
existingException.syusrex_isactive = true;
|
|
12779
|
+
console.log('🎭 Role exception reactivated:', existingException);
|
|
12780
|
+
}
|
|
12781
|
+
else {
|
|
12782
|
+
console.log('🎭 Role exception already exists, skipping duplicate:', existingException);
|
|
12783
|
+
}
|
|
12784
|
+
}
|
|
12785
|
+
return updatedMappings;
|
|
12786
|
+
});
|
|
12787
|
+
console.log('🎭 Role exception added:', exception);
|
|
12788
|
+
}
|
|
12789
|
+
/**
|
|
12790
|
+
* Remove role exception
|
|
12791
|
+
*/
|
|
12792
|
+
removeRoleException(mappingIndex, menuId, permissionId) {
|
|
12793
|
+
this.entityMappings.update(mappings => {
|
|
12794
|
+
const updatedMappings = [...mappings];
|
|
12795
|
+
const mapping = updatedMappings[mappingIndex];
|
|
12796
|
+
if (mapping.exceptions) {
|
|
12797
|
+
// Instead of removing, mark as removed for tracking
|
|
12798
|
+
mapping.exceptions = mapping.exceptions.map((exception) => {
|
|
12799
|
+
if (exception.syusrex_menu_id_syme === menuId && exception.syusrex_role_permissions_id_sygms === permissionId) {
|
|
12800
|
+
return {
|
|
12801
|
+
...exception,
|
|
12802
|
+
_isUserRemoved: true,
|
|
12803
|
+
_changeType: 'removed',
|
|
12804
|
+
syusrex_isactive: false
|
|
12805
|
+
};
|
|
12806
|
+
}
|
|
12807
|
+
return exception;
|
|
12808
|
+
});
|
|
12809
|
+
}
|
|
12810
|
+
return updatedMappings;
|
|
12811
|
+
});
|
|
12812
|
+
console.log('🎭 Role exception marked as removed:', { mappingIndex, menuId, permissionId });
|
|
12813
|
+
}
|
|
12814
|
+
/**
|
|
12815
|
+
* Collect only changed role exceptions from entity mappings
|
|
12816
|
+
*/
|
|
12817
|
+
collectRoleExceptions() {
|
|
12818
|
+
const exceptions = [];
|
|
12819
|
+
const entityMappings = this.entityMappings();
|
|
12820
|
+
entityMappings.forEach((mapping, mappingIndex) => {
|
|
12821
|
+
// Get exceptions from the mapping
|
|
12822
|
+
const mappingWithExceptions = mapping;
|
|
12823
|
+
const mappingExceptions = mappingWithExceptions.exceptions || [];
|
|
12824
|
+
// Only include exceptions that have been explicitly changed by the user
|
|
12825
|
+
mappingExceptions.forEach((exception) => {
|
|
12826
|
+
// Check if this exception was explicitly added or removed by the user
|
|
12827
|
+
if (exception._isUserAdded || exception._isUserRemoved) {
|
|
12828
|
+
// Ensure role ID is direct string, not object
|
|
12829
|
+
const roleId = mapping.syenm_role_id_syusrol?._id ?? '';
|
|
12830
|
+
// Create a unique key for this exception to prevent duplicates
|
|
12831
|
+
const exceptionKey = `${mapping._id || `temp_${mappingIndex}`}_${roleId}_${exception.syusrex_role_permissions_id_sygms}_${exception.syusrex_menu_id_syme}`;
|
|
12832
|
+
// Check if this exception already exists in the collection
|
|
12833
|
+
const existingException = exceptions.find(ex => ex.syusrex_user_entity_mapping_id_syenm === (mapping._id || `temp_${mappingIndex}`) &&
|
|
12834
|
+
ex.syusrex_role_id_syusrol === roleId &&
|
|
12835
|
+
ex.syusrex_role_permissions_id_sygms === exception.syusrex_role_permissions_id_sygms &&
|
|
12836
|
+
ex.syusrex_menu_id_syme === exception.syusrex_menu_id_syme);
|
|
12837
|
+
if (!existingException) {
|
|
12838
|
+
exceptions.push({
|
|
12839
|
+
syusrex_user_entity_mapping_id_syenm: mapping._id || `temp_${mappingIndex}`,
|
|
12840
|
+
syusrex_role_id_syusrol: roleId,
|
|
12841
|
+
syusrex_role_permissions_id_sygms: exception.syusrex_role_permissions_id_sygms || '',
|
|
12842
|
+
syusrex_menu_id_syme: exception.syusrex_menu_id_syme || '',
|
|
12843
|
+
syusrex_isactive: exception.syusrex_isactive || false,
|
|
12844
|
+
_changeType: exception._changeType || 'unknown'
|
|
12845
|
+
});
|
|
12846
|
+
}
|
|
12847
|
+
else {
|
|
12848
|
+
console.log('🎭 Duplicate exception prevented:', exceptionKey);
|
|
12849
|
+
}
|
|
12850
|
+
}
|
|
12851
|
+
});
|
|
12852
|
+
});
|
|
12853
|
+
console.log('🎭 Collected changed role exceptions:', exceptions);
|
|
12854
|
+
return exceptions;
|
|
12855
|
+
}
|
|
12856
|
+
/**
|
|
12857
|
+
* Check if permission is selected for a menu
|
|
12858
|
+
*/
|
|
12859
|
+
isPermissionSelected(menuId, permissionId) {
|
|
12860
|
+
const mappingIndex = this.getCurrentMappingIndex();
|
|
12861
|
+
if (mappingIndex === null)
|
|
12862
|
+
return false;
|
|
12863
|
+
return this.isPermissionInRole(permissionId, mappingIndex, menuId);
|
|
12864
|
+
}
|
|
12264
12865
|
/**
|
|
12265
12866
|
* Handle permission checkbox change (read-only in this context)
|
|
12266
12867
|
*/
|
|
@@ -12272,14 +12873,21 @@ class CideCoreUserCreateComponent {
|
|
|
12272
12873
|
* Check if a menu has child menus with permissions
|
|
12273
12874
|
*/
|
|
12274
12875
|
hasChildMenusWithPermissions(menuId) {
|
|
12275
|
-
|
|
12276
|
-
|
|
12277
|
-
return
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12876
|
+
// For simplified approach, we don't need to check child menus
|
|
12877
|
+
// Just return false as we're not using hierarchical permission checking
|
|
12878
|
+
return false;
|
|
12879
|
+
}
|
|
12880
|
+
/**
|
|
12881
|
+
* Update menu rights grid data to force refresh
|
|
12882
|
+
*/
|
|
12883
|
+
updateMenuRightsGridData(mappingIndex) {
|
|
12884
|
+
const menuRights = this.getMenuRightsForMapping(mappingIndex);
|
|
12885
|
+
console.log('🔄 Updating menu rights grid data:', menuRights);
|
|
12886
|
+
// Force update the grid configuration
|
|
12887
|
+
this.menuRightsMap.update(map => {
|
|
12888
|
+
const newMap = { ...map };
|
|
12889
|
+
newMap[mappingIndex.toString()] = menuRights;
|
|
12890
|
+
return newMap;
|
|
12283
12891
|
});
|
|
12284
12892
|
}
|
|
12285
12893
|
/**
|
|
@@ -12287,11 +12895,13 @@ class CideCoreUserCreateComponent {
|
|
|
12287
12895
|
*/
|
|
12288
12896
|
getMenuRightsGridConfig(mappingIndex) {
|
|
12289
12897
|
const menuRights = this.getMenuRightsForMapping(mappingIndex);
|
|
12898
|
+
console.log(`🔍 Grid config for mapping ${mappingIndex}:`);
|
|
12899
|
+
console.log(`📊 Menu rights count:`, menuRights.length);
|
|
12900
|
+
console.log(`📋 Menu rights data:`, menuRights);
|
|
12290
12901
|
return {
|
|
12291
12902
|
id: `menu-rights-grid-${mappingIndex}`,
|
|
12292
|
-
title: '
|
|
12293
|
-
subtitle: '
|
|
12294
|
-
fullHeight: true,
|
|
12903
|
+
title: '',
|
|
12904
|
+
subtitle: '',
|
|
12295
12905
|
columns: [
|
|
12296
12906
|
{
|
|
12297
12907
|
key: 'details',
|
|
@@ -12312,17 +12922,40 @@ class CideCoreUserCreateComponent {
|
|
|
12312
12922
|
renderer: 'menuTypeRenderer'
|
|
12313
12923
|
},
|
|
12314
12924
|
{
|
|
12315
|
-
key: '
|
|
12925
|
+
key: 'syme_path',
|
|
12926
|
+
header: 'Path',
|
|
12927
|
+
type: 'text',
|
|
12928
|
+
width: '200px',
|
|
12929
|
+
truncate: true,
|
|
12930
|
+
align: 'left'
|
|
12931
|
+
},
|
|
12932
|
+
{
|
|
12933
|
+
key: 'syme_isactive',
|
|
12934
|
+
header: 'Status',
|
|
12935
|
+
type: 'status',
|
|
12936
|
+
width: '100px',
|
|
12937
|
+
truncate: false,
|
|
12938
|
+
align: 'center',
|
|
12939
|
+
statusConfig: {
|
|
12940
|
+
activeValue: true,
|
|
12941
|
+
activeLabel: 'Active',
|
|
12942
|
+
inactiveLabel: 'Inactive',
|
|
12943
|
+
activeClass: 'tw-bg-green-100 tw-text-green-800',
|
|
12944
|
+
inactiveClass: 'tw-bg-red-100 tw-text-red-800'
|
|
12945
|
+
}
|
|
12946
|
+
},
|
|
12947
|
+
{
|
|
12948
|
+
key: 'syme_permissions_id_sygms',
|
|
12316
12949
|
header: 'Permissions',
|
|
12317
12950
|
type: 'custom',
|
|
12318
|
-
width: '
|
|
12319
|
-
truncate:
|
|
12951
|
+
width: '200px',
|
|
12952
|
+
truncate: true,
|
|
12320
12953
|
align: 'left',
|
|
12321
12954
|
renderer: 'permissionsRenderer'
|
|
12322
12955
|
}
|
|
12323
12956
|
],
|
|
12324
12957
|
data: menuRights,
|
|
12325
|
-
trackBy: '
|
|
12958
|
+
trackBy: '_id',
|
|
12326
12959
|
pagination: {
|
|
12327
12960
|
enabled: false,
|
|
12328
12961
|
pageSize: 10,
|
|
@@ -12334,37 +12967,43 @@ class CideCoreUserCreateComponent {
|
|
|
12334
12967
|
search: {
|
|
12335
12968
|
enabled: true,
|
|
12336
12969
|
placeholder: 'Search menu items...',
|
|
12337
|
-
searchableColumns: ['
|
|
12970
|
+
searchableColumns: ['syme_title', 'syme_desc', 'syme_path'],
|
|
12338
12971
|
debounceMs: 300
|
|
12339
12972
|
},
|
|
12340
12973
|
loading: {
|
|
12341
|
-
useDefer:
|
|
12974
|
+
useDefer: true,
|
|
12342
12975
|
skeletonRows: 5,
|
|
12343
12976
|
showOverlay: false
|
|
12344
12977
|
},
|
|
12345
12978
|
scroll: {
|
|
12346
12979
|
enabled: true,
|
|
12347
|
-
maxHeight: '
|
|
12348
|
-
minHeight: '
|
|
12980
|
+
maxHeight: '',
|
|
12981
|
+
minHeight: '',
|
|
12349
12982
|
stickyHeader: true,
|
|
12350
12983
|
virtualScroll: false,
|
|
12351
|
-
rowHeight:
|
|
12984
|
+
rowHeight: 50
|
|
12352
12985
|
},
|
|
12353
12986
|
dragDrop: {
|
|
12354
|
-
enabled:
|
|
12355
|
-
orderField: '',
|
|
12356
|
-
dragClass: '',
|
|
12357
|
-
dropClass: ''
|
|
12987
|
+
enabled: true,
|
|
12988
|
+
orderField: 'syme_order_by',
|
|
12989
|
+
dragClass: 'tw-opacity-50 tw-bg-blue-50',
|
|
12990
|
+
dropClass: 'tw-bg-green-50'
|
|
12358
12991
|
},
|
|
12359
12992
|
responsive: true,
|
|
12360
12993
|
striped: false,
|
|
12361
12994
|
bordered: true,
|
|
12362
12995
|
compact: false,
|
|
12363
12996
|
tableClass: 'tw-table-fixed tw-w-full tw-rounded-none',
|
|
12997
|
+
onRefresh: 'onMenuItemRefresh',
|
|
12998
|
+
onRowReorder: 'onRowReorder',
|
|
12364
12999
|
tree: {
|
|
12365
13000
|
enabled: true,
|
|
12366
|
-
primaryKey: '
|
|
12367
|
-
foreignKey: '
|
|
13001
|
+
primaryKey: '_id',
|
|
13002
|
+
foreignKey: 'syme_id_syme',
|
|
13003
|
+
childrenKey: 'children',
|
|
13004
|
+
levelKey: 'level',
|
|
13005
|
+
expandedKey: 'isExpanded',
|
|
13006
|
+
hasChildrenKey: 'hasChildren'
|
|
12368
13007
|
}
|
|
12369
13008
|
};
|
|
12370
13009
|
}
|
|
@@ -12375,7 +13014,7 @@ class CideCoreUserCreateComponent {
|
|
|
12375
13014
|
return {
|
|
12376
13015
|
menuDetailsRenderer: this.menuDetailsRendererTemplate(),
|
|
12377
13016
|
menuTypeRenderer: this.menuTypeRendererTemplate(),
|
|
12378
|
-
permissionsRenderer: this.
|
|
13017
|
+
permissionsRenderer: this.permissionsRendererTemplate()
|
|
12379
13018
|
};
|
|
12380
13019
|
}
|
|
12381
13020
|
/**
|
|
@@ -12448,71 +13087,99 @@ class CideCoreUserCreateComponent {
|
|
|
12448
13087
|
console.warn('Entity and Role must be selected before loading menu rights');
|
|
12449
13088
|
return;
|
|
12450
13089
|
}
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12464
|
-
|
|
12465
|
-
|
|
12466
|
-
|
|
12467
|
-
|
|
12468
|
-
|
|
12469
|
-
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
13090
|
+
console.log('🚀 Loading menu rights for mapping:', mappingIndex);
|
|
13091
|
+
this.loading.set(true);
|
|
13092
|
+
this.error.set(null);
|
|
13093
|
+
// Use actual API call to get menu list
|
|
13094
|
+
const requestBody = {
|
|
13095
|
+
pageIndex: 1,
|
|
13096
|
+
pageSize: 1000, // Get all menu items - increased to ensure we get all records
|
|
13097
|
+
total: 1000, // Set total to match pageSize to get all records
|
|
13098
|
+
sort: { order: 'asc', key: 'syme_order_by' }
|
|
13099
|
+
};
|
|
13100
|
+
console.log('📤 Request body for menu list:', requestBody);
|
|
13101
|
+
this.menuService.getMenuList(requestBody)
|
|
13102
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
13103
|
+
.subscribe({
|
|
13104
|
+
next: (response) => {
|
|
13105
|
+
console.log('✅ Menu list loaded successfully:', response);
|
|
13106
|
+
console.log('📊 Total menu items received:', response?.data?.length || 0);
|
|
13107
|
+
console.log('📋 Menu items data:', response?.data);
|
|
13108
|
+
if (response?.success && response?.data) {
|
|
13109
|
+
// Use menu data directly without transformation
|
|
13110
|
+
const menuRights = response.data.map((menu) => {
|
|
13111
|
+
// Get only the permissions that are mapped to this menu
|
|
13112
|
+
const mappedPermissions = this.permissions().filter(permission => menu.syme_permissions_id_sygms?.includes(permission._id || ''));
|
|
13113
|
+
// Pre-compute permission values for template performance
|
|
13114
|
+
const permissionValues = {};
|
|
13115
|
+
if (menu.syme_permissions_id_sygms) {
|
|
13116
|
+
menu.syme_permissions_id_sygms.forEach(permissionId => {
|
|
13117
|
+
const permission = this.getPermissionById(permissionId);
|
|
13118
|
+
if (permission) {
|
|
13119
|
+
permissionValues[permissionId] = {
|
|
13120
|
+
checked: this.getFormControlValue(menu, permissionId),
|
|
13121
|
+
permission: permission
|
|
13122
|
+
};
|
|
13123
|
+
}
|
|
13124
|
+
});
|
|
13125
|
+
}
|
|
13126
|
+
return {
|
|
13127
|
+
...menu,
|
|
13128
|
+
role_rights: mappedPermissions, // Use only mapped permissions
|
|
13129
|
+
exceptions: [],
|
|
13130
|
+
_permissionValues: permissionValues // Pre-computed values
|
|
13131
|
+
};
|
|
13132
|
+
});
|
|
13133
|
+
// Update menu rights map
|
|
13134
|
+
this.menuRightsMap.update(map => {
|
|
13135
|
+
const newMap = {
|
|
13136
|
+
...map,
|
|
13137
|
+
[mappingIndex.toString()]: menuRights
|
|
13138
|
+
};
|
|
13139
|
+
console.log('🗺️ Updated menu rights map:', newMap);
|
|
13140
|
+
return newMap;
|
|
13141
|
+
});
|
|
13142
|
+
console.log('📊 Processed menu rights count:', menuRights.length);
|
|
13143
|
+
console.log('📋 Menu rights data:', menuRights);
|
|
13144
|
+
// Initialize entity mapping exceptions array if not exists
|
|
13145
|
+
this.entityMappings.update(mappings => {
|
|
13146
|
+
const updatedMappings = [...mappings];
|
|
13147
|
+
if (!updatedMappings[mappingIndex].exceptions) {
|
|
13148
|
+
updatedMappings[mappingIndex].exceptions = [];
|
|
13149
|
+
}
|
|
13150
|
+
return updatedMappings;
|
|
13151
|
+
});
|
|
13152
|
+
console.log('✅ Menu rights loaded for mapping', mappingIndex);
|
|
13153
|
+
// Force refresh the grid to show updated permission states
|
|
13154
|
+
setTimeout(() => {
|
|
13155
|
+
this.cdr.detectChanges();
|
|
13156
|
+
// Also update the grid configuration to ensure data refresh
|
|
13157
|
+
this.updateMenuRightsGridData(mappingIndex);
|
|
13158
|
+
}, 100);
|
|
13159
|
+
}
|
|
13160
|
+
else {
|
|
13161
|
+
console.warn('⚠️ No menu data received from API');
|
|
13162
|
+
this.error.set('No menu data received from server');
|
|
13163
|
+
}
|
|
13164
|
+
this.loading.set(false);
|
|
12481
13165
|
},
|
|
12482
|
-
{
|
|
12483
|
-
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
role_rights: ['read'],
|
|
12487
|
-
exceptions: []
|
|
13166
|
+
error: (error) => {
|
|
13167
|
+
console.error('❌ Error loading menu rights:', error);
|
|
13168
|
+
this.error.set('Failed to load menu rights');
|
|
13169
|
+
this.loading.set(false);
|
|
12488
13170
|
}
|
|
12489
|
-
];
|
|
12490
|
-
// Update menu rights map
|
|
12491
|
-
this.menuRightsMap.update(map => ({
|
|
12492
|
-
...map,
|
|
12493
|
-
[mappingIndex.toString()]: simulatedMenuRights
|
|
12494
|
-
}));
|
|
12495
|
-
// Add form controls for menu rights
|
|
12496
|
-
simulatedMenuRights.forEach((menuRight, j) => {
|
|
12497
|
-
this.userMasterForm.addControl(`core_entity_mapping.${mappingIndex}.menu_rights.${j}.create`, this.fb.control(menuRight.role_rights.includes('create')));
|
|
12498
|
-
this.userMasterForm.addControl(`core_entity_mapping.${mappingIndex}.menu_rights.${j}.read`, this.fb.control(menuRight.role_rights.includes('read')));
|
|
12499
|
-
this.userMasterForm.addControl(`core_entity_mapping.${mappingIndex}.menu_rights.${j}.update`, this.fb.control(menuRight.role_rights.includes('update')));
|
|
12500
|
-
this.userMasterForm.addControl(`core_entity_mapping.${mappingIndex}.menu_rights.${j}.delete`, this.fb.control(menuRight.role_rights.includes('delete')));
|
|
12501
13171
|
});
|
|
12502
|
-
console.log('Menu rights loaded for mapping', mappingIndex);
|
|
12503
13172
|
}
|
|
12504
13173
|
refreshMenuRights(mappingIndex) {
|
|
12505
13174
|
this.clearMenuRightsForMapping(mappingIndex);
|
|
12506
13175
|
this.loadMenuRights(mappingIndex);
|
|
12507
13176
|
}
|
|
12508
13177
|
clearMenuRightsForMapping(mappingIndex) {
|
|
12509
|
-
|
|
12510
|
-
|
|
12511
|
-
|
|
12512
|
-
|
|
12513
|
-
|
|
12514
|
-
this.userMasterForm.removeControl(`core_entity_mapping.${mappingIndex}.menu_rights.${j}.update`);
|
|
12515
|
-
this.userMasterForm.removeControl(`core_entity_mapping.${mappingIndex}.menu_rights.${j}.delete`);
|
|
13178
|
+
// Clear exceptions from entity mapping
|
|
13179
|
+
this.entityMappings.update(mappings => {
|
|
13180
|
+
const updatedMappings = [...mappings];
|
|
13181
|
+
updatedMappings[mappingIndex].exceptions = [];
|
|
13182
|
+
return updatedMappings;
|
|
12516
13183
|
});
|
|
12517
13184
|
// Clear from menu rights map
|
|
12518
13185
|
this.menuRightsMap.update(map => {
|
|
@@ -12521,6 +13188,63 @@ class CideCoreUserCreateComponent {
|
|
|
12521
13188
|
return updatedMap;
|
|
12522
13189
|
});
|
|
12523
13190
|
}
|
|
13191
|
+
/**
|
|
13192
|
+
* Load user rights type ID from general master types
|
|
13193
|
+
*/
|
|
13194
|
+
loadUserRightsTypeId() {
|
|
13195
|
+
this.generalMasterTypeService.getTypeList({
|
|
13196
|
+
sygmt_code: "user_rights"
|
|
13197
|
+
})
|
|
13198
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
13199
|
+
.subscribe({
|
|
13200
|
+
next: (response) => {
|
|
13201
|
+
if (response?.success && response.data) {
|
|
13202
|
+
const userRightsType = response.data.find(type => type.sygmt_code === 'user_rights' || type.sygmt_title?.toLowerCase().includes('user_rights'));
|
|
13203
|
+
if (userRightsType) {
|
|
13204
|
+
this.userRightsTypeId.set(userRightsType._id || null);
|
|
13205
|
+
this.loadPermissions();
|
|
13206
|
+
}
|
|
13207
|
+
else {
|
|
13208
|
+
this.error.set('User rights type not found in general master types');
|
|
13209
|
+
}
|
|
13210
|
+
}
|
|
13211
|
+
},
|
|
13212
|
+
error: (err) => {
|
|
13213
|
+
this.error.set('Failed to load user rights type');
|
|
13214
|
+
}
|
|
13215
|
+
});
|
|
13216
|
+
}
|
|
13217
|
+
/**
|
|
13218
|
+
* Load permissions from general master
|
|
13219
|
+
*/
|
|
13220
|
+
loadPermissions() {
|
|
13221
|
+
const typeId = this.userRightsTypeId();
|
|
13222
|
+
if (!typeId) {
|
|
13223
|
+
this.error.set('User rights type not found. Please ensure the "user_rights" type exists in general master types.');
|
|
13224
|
+
return;
|
|
13225
|
+
}
|
|
13226
|
+
const payload = { sygms_id_sygmt: typeId };
|
|
13227
|
+
this.CideCoreGeneralMasterService.getMasterList(payload)
|
|
13228
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
13229
|
+
.subscribe({
|
|
13230
|
+
next: (response) => {
|
|
13231
|
+
if (response?.success && response.data) {
|
|
13232
|
+
this.permissions.set(response.data);
|
|
13233
|
+
if (this.error()?.includes('permissions')) {
|
|
13234
|
+
this.error.set(null);
|
|
13235
|
+
}
|
|
13236
|
+
}
|
|
13237
|
+
else {
|
|
13238
|
+
this.permissions.set([]);
|
|
13239
|
+
this.error.set('No permissions found. Please ensure permissions are configured in general master.');
|
|
13240
|
+
}
|
|
13241
|
+
},
|
|
13242
|
+
error: (err) => {
|
|
13243
|
+
this.permissions.set([]);
|
|
13244
|
+
this.error.set('Failed to load permissions from general master. Please check your configuration.');
|
|
13245
|
+
}
|
|
13246
|
+
});
|
|
13247
|
+
}
|
|
12524
13248
|
hasRoleRight(menuRight, permission) {
|
|
12525
13249
|
return menuRight.role_rights.includes(permission);
|
|
12526
13250
|
}
|
|
@@ -12658,6 +13382,59 @@ class CideCoreUserCreateComponent {
|
|
|
12658
13382
|
uploadType: 'user_profile_photo',
|
|
12659
13383
|
};
|
|
12660
13384
|
}
|
|
13385
|
+
/**
|
|
13386
|
+
* Get upload data for document files with group ID
|
|
13387
|
+
*/
|
|
13388
|
+
getDocumentUploadData(documentIndex) {
|
|
13389
|
+
const documentFormGroup = this.documentsFormArray.at(documentIndex);
|
|
13390
|
+
const photoGroupId = documentFormGroup?.get('syusd_photo_group_id_cyfm')?.value;
|
|
13391
|
+
const documentType = documentFormGroup?.get('syusd_document_type_id_sygms')?.value;
|
|
13392
|
+
const documentNumber = documentFormGroup?.get('syusd_doc_number')?.value;
|
|
13393
|
+
// Get document type name for better tagging
|
|
13394
|
+
const documentTypeName = this.documentTypeOptions().find(opt => opt._id === documentType)?.sygms_title || 'Document';
|
|
13395
|
+
return {
|
|
13396
|
+
altText: `${documentTypeName} - ${documentNumber || 'Document'}`,
|
|
13397
|
+
userId: this.appState.getCurrentUser()?._id || '',
|
|
13398
|
+
groupId: photoGroupId, // Use photo group ID or generate one
|
|
13399
|
+
permissions: ['read', 'write'],
|
|
13400
|
+
tags: ['user', 'document', documentTypeName.toLowerCase(), 'file'],
|
|
13401
|
+
uploadType: 'user_document',
|
|
13402
|
+
documentIndex: documentIndex,
|
|
13403
|
+
documentType: documentType,
|
|
13404
|
+
documentNumber: documentNumber
|
|
13405
|
+
};
|
|
13406
|
+
}
|
|
13407
|
+
/**
|
|
13408
|
+
* Handle document upload success
|
|
13409
|
+
* For multiple file upload, uploadResponse is the group ID
|
|
13410
|
+
*/
|
|
13411
|
+
onDocumentUploadSuccess(groupId, documentIndex) {
|
|
13412
|
+
console.log(`📎 Document upload success for document ${documentIndex} with group ID:`, groupId);
|
|
13413
|
+
// Update the photo group ID in the form
|
|
13414
|
+
const documentFormGroup = this.documentsFormArray.at(documentIndex);
|
|
13415
|
+
if (documentFormGroup && groupId) {
|
|
13416
|
+
documentFormGroup.get('syusd_photo_group_id_cyfm')?.setValue(groupId);
|
|
13417
|
+
console.log(`📎 Updated photo group ID for document ${documentIndex}:`, groupId);
|
|
13418
|
+
}
|
|
13419
|
+
// For multiple file upload, we don't track individual files here
|
|
13420
|
+
// The files are managed by the group ID on the server
|
|
13421
|
+
// Clear any existing file tracking since we now use group ID
|
|
13422
|
+
documentFormGroup._uploadedFiles = [];
|
|
13423
|
+
}
|
|
13424
|
+
/**
|
|
13425
|
+
* Handle document upload error
|
|
13426
|
+
*/
|
|
13427
|
+
onDocumentUploadError(error, documentIndex) {
|
|
13428
|
+
console.error(`❌ Document upload error for document ${documentIndex}:`, error);
|
|
13429
|
+
this.error.set(`Failed to upload document file: ${error?.message || 'Unknown error'}`);
|
|
13430
|
+
}
|
|
13431
|
+
/**
|
|
13432
|
+
* Handle document upload progress
|
|
13433
|
+
*/
|
|
13434
|
+
onDocumentUploadProgress(progress, documentIndex) {
|
|
13435
|
+
console.log(`📊 Document upload progress for document ${documentIndex}: ${progress}%`);
|
|
13436
|
+
// You can add progress indication here if needed
|
|
13437
|
+
}
|
|
12661
13438
|
/**
|
|
12662
13439
|
* Load profile photo preview for existing photos
|
|
12663
13440
|
*/
|
|
@@ -12751,6 +13528,11 @@ class CideCoreUserCreateComponent {
|
|
|
12751
13528
|
this.documents.update(docs => [...docs, newDocumentGroup.value]);
|
|
12752
13529
|
}
|
|
12753
13530
|
removeDocument(index) {
|
|
13531
|
+
// Clean up uploaded files for this document
|
|
13532
|
+
const documentFormGroup = this.documentsFormArray.at(index);
|
|
13533
|
+
if (documentFormGroup) {
|
|
13534
|
+
documentFormGroup._uploadedFiles = [];
|
|
13535
|
+
}
|
|
12754
13536
|
// Remove the document from the FormArray
|
|
12755
13537
|
this.documentsFormArray.removeAt(index);
|
|
12756
13538
|
// Update the documents signal to keep UI in sync
|
|
@@ -12797,12 +13579,14 @@ class CideCoreUserCreateComponent {
|
|
|
12797
13579
|
}
|
|
12798
13580
|
if (this.userMasterForm.valid) {
|
|
12799
13581
|
this.loading.set(true);
|
|
12800
|
-
// Prepare form data with entity mappings and
|
|
12801
|
-
const { core_entity_mapping,
|
|
13582
|
+
// Prepare form data with entity mappings and exceptions
|
|
13583
|
+
const { core_entity_mapping, core_user_contact_addresses, core_user_documents, core_user_family_details, ...auth_user_mst } = this.userMasterForm.value;
|
|
13584
|
+
// Collect exceptions from all entity mappings
|
|
13585
|
+
const core_user_role_exceptions = this.collectRoleExceptions();
|
|
12802
13586
|
const formData = {
|
|
12803
13587
|
auth_user_mst: auth_user_mst,
|
|
12804
13588
|
core_entity_mapping: core_entity_mapping || [],
|
|
12805
|
-
|
|
13589
|
+
core_user_role_exceptions: core_user_role_exceptions,
|
|
12806
13590
|
core_user_contact_addresses: core_user_contact_addresses || [],
|
|
12807
13591
|
core_user_documents: core_user_documents || [],
|
|
12808
13592
|
core_user_family_details: core_user_family_details || [],
|
|
@@ -12826,7 +13610,7 @@ class CideCoreUserCreateComponent {
|
|
|
12826
13610
|
console.log('🔐 Encrypting password for edit mode...');
|
|
12827
13611
|
const originalPassword = dataWithPassword.user_password;
|
|
12828
13612
|
dataWithPassword.user_password = customEncrypt(dataWithPassword.user_password);
|
|
12829
|
-
console.log('✅ Password encrypted for edit mode:', { originalLength: originalPassword
|
|
13613
|
+
console.log('✅ Password encrypted for edit mode:', { originalLength: originalPassword, encryptedLength: customDecrypt(dataWithPassword.user_password), dataWithPassword: dataWithPassword.user_password });
|
|
12830
13614
|
}
|
|
12831
13615
|
formData.auth_user_mst = dataWithPassword;
|
|
12832
13616
|
}
|
|
@@ -12838,15 +13622,12 @@ class CideCoreUserCreateComponent {
|
|
|
12838
13622
|
console.log('🔐 Encrypting password for create mode...');
|
|
12839
13623
|
const originalPassword = dataWithPassword.user_password;
|
|
12840
13624
|
dataWithPassword.user_password = customEncrypt(dataWithPassword.user_password);
|
|
12841
|
-
console.log('✅ Password encrypted for create mode:', { originalLength: originalPassword
|
|
13625
|
+
console.log('✅ Password encrypted for create mode:', { originalLength: originalPassword, encryptedLength: dataWithPassword.user_password.length });
|
|
12842
13626
|
}
|
|
12843
13627
|
formData.auth_user_mst = dataWithPassword;
|
|
12844
13628
|
}
|
|
12845
13629
|
// Log final form data being sent (without password for security)
|
|
12846
13630
|
const logData = { ...formData };
|
|
12847
|
-
if (logData.auth_user_mst.user_password) {
|
|
12848
|
-
logData.auth_user_mst.user_password = '***ENCRYPTED***';
|
|
12849
|
-
}
|
|
12850
13631
|
console.log('📤 Sending form data to server:', logData);
|
|
12851
13632
|
// Use the service to save user master
|
|
12852
13633
|
this.userMasterService.saveUpdateUserMaster(logData)
|
|
@@ -12854,14 +13635,19 @@ class CideCoreUserCreateComponent {
|
|
|
12854
13635
|
next: (response) => {
|
|
12855
13636
|
console.log('✅ User master saved successfully:', response);
|
|
12856
13637
|
this.loading.set(false);
|
|
13638
|
+
this.error.set(null); // Clear any previous errors
|
|
12857
13639
|
if (this.isEditMode()) {
|
|
12858
|
-
// In edit mode, show success message
|
|
13640
|
+
// In edit mode, show success message
|
|
13641
|
+
this.success.set('User updated successfully! All changes have been saved.');
|
|
12859
13642
|
console.log('User updated successfully');
|
|
12860
|
-
//
|
|
12861
|
-
|
|
13643
|
+
// Auto-hide success message after 5 seconds
|
|
13644
|
+
setTimeout(() => this.success.set(null), 5000);
|
|
12862
13645
|
}
|
|
12863
13646
|
else {
|
|
12864
|
-
// In create mode, reset form for new user
|
|
13647
|
+
// In create mode, show success message and reset form for new user
|
|
13648
|
+
this.success.set('User created successfully! You can now create another user.');
|
|
13649
|
+
// Auto-hide success message after 5 seconds
|
|
13650
|
+
setTimeout(() => this.success.set(null), 5000);
|
|
12865
13651
|
this.resetForm();
|
|
12866
13652
|
}
|
|
12867
13653
|
},
|
|
@@ -13326,6 +14112,37 @@ class CideCoreUserCreateComponent {
|
|
|
13326
14112
|
}
|
|
13327
14113
|
});
|
|
13328
14114
|
}
|
|
14115
|
+
/**
|
|
14116
|
+
* Load menu options from API
|
|
14117
|
+
*/
|
|
14118
|
+
loadMenuOptions() {
|
|
14119
|
+
const requestBody = {
|
|
14120
|
+
pageIndex: 0,
|
|
14121
|
+
pageSize: 1000, // Load all menus
|
|
14122
|
+
total: 0,
|
|
14123
|
+
query: '',
|
|
14124
|
+
sort: {
|
|
14125
|
+
order: 'asc',
|
|
14126
|
+
key: 'syme_order_by'
|
|
14127
|
+
}
|
|
14128
|
+
};
|
|
14129
|
+
this.menuService.getMenuList(requestBody).subscribe({
|
|
14130
|
+
next: (response) => {
|
|
14131
|
+
if (response?.success) {
|
|
14132
|
+
console.log('🎭 Menu options loaded:', response.data);
|
|
14133
|
+
this.menuOptions.set(response.data || []);
|
|
14134
|
+
}
|
|
14135
|
+
else {
|
|
14136
|
+
console.error('❌ Failed to load menu options:', response);
|
|
14137
|
+
this.menuOptions.set([]);
|
|
14138
|
+
}
|
|
14139
|
+
},
|
|
14140
|
+
error: (error) => {
|
|
14141
|
+
console.error('❌ Error loading menu options:', error);
|
|
14142
|
+
this.menuOptions.set([]);
|
|
14143
|
+
}
|
|
14144
|
+
});
|
|
14145
|
+
}
|
|
13329
14146
|
/**
|
|
13330
14147
|
* Load dropdown data for existing addresses in edit mode
|
|
13331
14148
|
*/
|
|
@@ -13343,7 +14160,7 @@ class CideCoreUserCreateComponent {
|
|
|
13343
14160
|
});
|
|
13344
14161
|
}
|
|
13345
14162
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideCoreUserCreateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13346
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideCoreUserCreateComponent, isStandalone: true, selector: "cide-core-user-create", viewQueries: [{ propertyName: "menuDetailsRendererTemplate", first: true, predicate: ["menuDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "permissionsCheckboxRendererTemplate", first: true, predicate: ["permissionsCheckboxRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "menuTypeRendererTemplate", first: true, predicate: ["menuTypeRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "menuRightsPermissionsRendererTemplate", first: true, predicate: ["menuRightsPermissionsRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- \n ENTERPRISE USER MASTER FORM\n \n Enterprise-Level Styling with Tailwind CSS\n Features: Responsive grids, proper typography, enhanced user experience\n-->\n\n<div class=\"tw-w-full tw-h-full tw-p-3\">\n <form class=\"tw-max-w-7xl tw-mx-auto tw-bg-transparent\" [formGroup]=\"userMasterForm\" [class.tw-opacity-60]=\"loading()\"\n (ngSubmit)=\"onSubmit()\">\n\n <!-- User Context Header -->\n <div\n class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-indigo-50 tw-border tw-border-blue-200 tw-rounded-md tw-p-2 tw-mb-3 tw-shadow-sm\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-flex-wrap tw-gap-2\">\n <!-- User Basic Info Display -->\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-flex-wrap\">\n <!-- Profile Photo Preview -->\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div\n class=\"tw-w-8 tw-h-8 tw-rounded-full tw-bg-blue-100 tw-border tw-border-blue-200 tw-flex tw-items-center tw-justify-center tw-overflow-hidden\">\n @if (userMasterForm.get('user_photo_id_cyfm')?.value) {\n <img \n cideEleFileImage \n [fileId]=\"userMasterForm.get('user_photo_id_cyfm')?.value\" \n [altText]=\"'Profile Photo'\"\n class=\"tw-w-full tw-h-full tw-object-cover\">\n } @else {\n <cide-ele-icon \n name=\"person\" \n class=\"tw-w-5 tw-h-5 tw-text-blue-600\">\n </cide-ele-icon>\n }\n </div>\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-xs tw-font-medium tw-text-blue-900\">\n {{ getUserFullName() || 'New User' }}\n </span>\n <span class=\"tw-text-xs tw-text-blue-600\">\n {{ getUserUsername() || 'Username not set' }}\n </span>\n </div>\n </div>\n\n <!-- Contact Info -->\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-700\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">email</cide-ele-icon>\n <span>{{ getUserEmail() || 'Email not set' }}</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-700\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">phone</cide-ele-icon>\n <span>{{ getUserMobile() || 'Mobile not set' }}</span>\n </div>\n </div>\n\n <!-- Active Status -->\n <div class=\"tw-flex tw-items-center tw-gap-1\">\n @if (getUserActiveStatus()) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-700\">\n <cide-ele-icon variant=\"green\" size=\"xs\" class=\"tw-mr-1\">check_circle</cide-ele-icon>\n Active\n </span>\n } @else {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-700\">\n <cide-ele-icon variant=\"red\" size=\"xs\" class=\"tw-mr-1\">cancel</cide-ele-icon>\n Inactive\n </span>\n }\n </div>\n </div>\n\n <!-- Entity Info -->\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n @if (hasDefaultEntity()) {\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-blue-700\">\n <cide-ele-icon variant=\"blue\" size=\"xs\">business</cide-ele-icon>\n <span class=\"tw-font-medium\">{{ getDefaultEntityName() }}</span>\n </div>\n } @else {\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-500\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">business</cide-ele-icon>\n <span class=\"tw-italic\">No entity</span>\n </div>\n }\n\n <span class=\"tw-text-xs tw-text-gray-600 tw-px-2 tw-py-1 tw-bg-gray-100 tw-rounded\">\n {{ getEntityMappingCount() }} mapping(s)\n </span>\n </div>\n </div>\n </div>\n\n <!-- Tab Navigation -->\n <div class=\"tw-p-0 tw-mb-2 tw-border-b tw-border-gray-200\">\n <cide-ele-tab [tabs]=\"userTabs()\" [activeTabId]=\"activeTab()\" size=\"md\" variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n @switch (activeTab()) {\n\n @case ('basic') {\n <!-- User Basic Information Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n\n <!-- Top Section: Form Fields on Left, Profile Photo on Right -->\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-[1fr_200px] tw-gap-6 tw-mb-6\">\n <!-- Left Side: Form Fields -->\n <div class=\"tw-space-y-6\">\n <!-- Name Fields - All in One Row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4\">\n <cide-ele-input id=\"user_firstname\" label=\"First Name *\" formControlName=\"user_firstname\"\n placeholder=\"Enter first name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_middlename\" label=\"Middle Name\" formControlName=\"user_middlename\"\n placeholder=\"Enter middle name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_lastname\" label=\"Last Name *\" formControlName=\"user_lastname\"\n placeholder=\"Enter last name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_fullname\" label=\"Full Name * (Auto-generated)\" formControlName=\"user_fullname\"\n placeholder=\"Auto-generated from name fields or enter manually\" [maxlength]=\"62\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Contact Information - All in One Row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-3 tw-gap-4\">\n <cide-ele-input id=\"user_username\" label=\"Username *\" formControlName=\"user_username\"\n placeholder=\"Enter unique username\" [maxlength]=\"20\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_emailid\" label=\"Email ID *\" formControlName=\"user_emailid\" type=\"email\"\n placeholder=\"Enter valid email address\" [maxlength]=\"320\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_mobileno\" label=\"Mobile Number *\" formControlName=\"user_mobileno\" type=\"tel\"\n placeholder=\"Enter mobile number\" [maxlength]=\"15\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Right Side: Profile Photo Upload -->\n <div class=\"tw-flex tw-items-start tw-justify-center tw-p-0\">\n <cide-ele-file-input \n id=\"user_photo_id_cyfm\" \n formControlName=\"user_photo_id_cyfm\"\n accept=\"image/*\"\n [showPreview]=\"true\"\n [previewBoxMode]=\"true\"\n [showFileName]=\"false\"\n previewWidth=\"180px\"\n previewHeight=\"120px\"\n placeholderText=\"Upload Photo\"\n placeholderIcon=\"cloud_upload\"\n [autoUpload]=\"true\"\n [uploadData]=\"getProfilePhotoUploadData()\"\n (uploadSuccess)=\"onProfilePhotoUploadSuccess($event)\"\n (uploadError)=\"onProfilePhotoUploadError($event)\"\n (uploadProgressChange)=\"onProfilePhotoUploadProgress($event)\">\n </cide-ele-file-input>\n </div>\n </div>\n\n\n\n <!-- Status Control -->\n <div class=\"tw-grid tw-grid-cols-1 tw-mb-4\">\n <div class=\"tw-p-4 tw-bg-blue-50 tw-border tw-border-blue-100 tw-rounded-lg\">\n <label\n class=\"tw-flex tw-flex-col tw-cursor-pointer tw-py-2 tw-bg-transparent tw-border-none tw-rounded-none tw-transition-all tw-duration-200 hover:tw-bg-blue-75\">\n <cide-ele-input type=\"checkbox\" label=\"Active User Status\" formControlName=\"user_isactive\"\n class=\"tw-h-5 tw-accent-blue-500 tw-rounded tw-mb-1\" />\n <span class=\"tw-font-semibold tw-text-gray-700 tw-text-base\"></span>\n <span class=\"tw-text-sm tw-text-gray-600 tw-mt-1 tw-leading-relaxed\">Enable this user account for system\n access and operations</span>\n </label>\n </div>\n </div>\n </div>\n }\n\n @case ('auth') {\n <!-- Authentication Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n <!-- Password Fields -->\n @if (shouldShowPasswordFields()) {\n <div class=\"tw-mb-6\">\n <!-- Password Fields Header for Edit Mode -->\n @if (isEditMode()) {\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800\">Update Password</h6>\n <button type=\"button\"\n class=\"tw-px-3 tw-py-1 tw-bg-gray-100 tw-text-gray-600 tw-border tw-border-gray-300 tw-rounded-md tw-text-xs tw-font-medium hover:tw-bg-gray-200 tw-transition-colors\"\n (click)=\"cancelPasswordUpdate()\">\n Cancel Password Update\n </button>\n </div>\n }\n\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 md:tw-grid-cols-1 tw-gap-6\">\n <cide-ele-input id=\"user_password\" [label]=\"getPasswordFieldLabel()\" formControlName=\"user_password\"\n type=\"password\" placeholder=\"Enter secure password (min 8 characters)\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_confirm_password\" [label]=\"getPasswordConfirmLabel()\"\n formControlName=\"user_confirm_password\" type=\"password\" placeholder=\"Confirm your password\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Password Update Option for Edit Mode -->\n @if (isEditMode() && !shouldShowPasswordFields()) {\n <div class=\"tw-mb-6\">\n <div class=\"tw-p-4 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-blue-800 tw-mb-2\">Password Update</h6>\n <p class=\"tw-text-sm tw-text-blue-600 tw-mb-3\">Current password will be kept. Click below to change\n password.</p>\n\n @if (hasPasswordInput()) {\n <div\n class=\"tw-mb-3 tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded tw-text-sm tw-text-yellow-700\">\n <cide-ele-icon variant=\"yellow\" size=\"xs\" class=\"tw-mr-1\">warning</cide-ele-icon>\n Password fields contain text. Click \"Change Password\" to manage existing input.\n </div>\n }\n\n <button type=\"button\"\n class=\"tw-px-4 tw-py-2 tw-bg-blue-100 tw-text-blue-700 tw-border tw-border-blue-300 tw-rounded-md tw-text-sm tw-font-medium hover:tw-bg-blue-200 tw-transition-colors\"\n (click)=\"triggerPasswordUpdate()\">\n @if (hasPasswordInput()) {\n Manage Password Fields\n } @else {\n Change Password\n }\n </button>\n </div>\n </div>\n }\n\n <!-- Password Options -->\n <div class=\"tw-grid tw-grid-cols-1 tw-gap-6 tw-mb-6\">\n <div class=\"tw-p-4 tw-bg-yellow-50 tw-border tw-border-yellow-100 tw-rounded-lg\">\n <label\n class=\"tw-flex tw-flex-col tw-gap-2 tw-cursor-pointer tw-py-2 tw-bg-transparent tw-border-none tw-rounded-none tw-transition-all tw-duration-200\">\n <cide-ele-input type=\"checkbox\" label=\"Force Password Change on Login\"\n formControlName=\"user_passwordchangeonlogin\" class=\"tw-h-5 tw-accent-yellow-500 tw-rounded tw-mb-1\" />\n <span class=\"tw-text-sm tw-text-gray-600 tw-mt-1 tw-leading-relaxed\">User will be required to change\n password on next login</span>\n </label>\n </div>\n </div>\n\n </div>\n }\n\n @case ('roles') {\n <!-- Entity, Roles & Permissions Mapping Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n\n\n\n <!-- Important Note -->\n <div class=\"tw-bg-amber-50 tw-border tw-border-amber-200 tw-rounded-lg tw-p-4 tw-mb-6\">\n <div class=\"tw-flex tw-items-start tw-gap-3\">\n <cide-ele-icon variant=\"amber\" size=\"lg\">info</cide-ele-icon>\n <div class=\"tw-flex-1\">\n <h4 class=\"tw-text-sm tw-font-semibold tw-text-amber-800 tw-mb-1\">Entity-Role Based Access</h4>\n <p class=\"tw-text-sm tw-text-amber-700 tw-mb-2\">User access is completely managed through entity-role\n mappings below. At least one entity mapping is required for user access.</p>\n @if (hasDefaultEntity()) {\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mt-2 tw-p-2 tw-bg-amber-100 tw-rounded\">\n <cide-ele-icon variant=\"amber\" size=\"sm\">star</cide-ele-icon>\n <span class=\"tw-text-sm tw-text-amber-800\">\n <strong>Default Entity:</strong> {{ getDefaultEntityName() }}\n </span>\n </div>\n } @else {\n <div class=\"tw-text-sm tw-text-amber-600 tw-mt-2 tw-italic\">\n \u26A0\uFE0F No default entity selected. Please set one entity as default.\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Entity-Role Mapping Section -->\n <div class=\"tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg tw-p-6 tw-mb-6\">\n <div class=\"tw-flex tw-text-center tw-justify-between tw-items-center tw-mb-4\">\n <div>\n <h4 class=\"tw-text-sm tw-text-left tw-font-semibold tw-text-blue-900 tw-mb-1\">Entity-Role Mapping</h4>\n <p class=\"tw-text-sm tw-text-blue-700\">Map user to entities with specific roles and permissions</p>\n </div>\n <div class=\"tw-flex tw-flex-col tw-items-end\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addEntityMapping()\" leftIcon=\"add\"\n [disabled]=\"isAllEntitiesMapped()\">\n Add Entity Mapping\n </button>\n \n @if (isAllEntitiesMapped()) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-md tw-max-w-xs\">\n <p class=\"tw-text-xs tw-text-blue-700\">\n <cide-ele-icon variant=\"info\" size=\"xs\" class=\"tw-mr-1\">info</cide-ele-icon>\n All available entities are already mapped.\n </p>\n </div>\n }\n </div>\n </div>\n\n <div formArrayName=\"core_entity_mapping\">\n @for (mapping of entityMappings(); track $index; let i = $index) {\n <div class=\"tw-bg-white tw-border tw-border-blue-200 tw-rounded-xl tw-mb-6 tw-overflow-hidden tw-shadow-sm\"\n [formGroupName]=\"i\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-blue-100 tw-px-6 tw-py-3 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <h5 class=\"tw-m-0 tw-text-blue-800 tw-text-sm tw-font-semibold\">Entity Mapping {{ i + 1 }}</h5>\n @if (mapping.syenm_isdefault) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n <cide-ele-icon variant=\"green\" size=\"xs\" class=\"tw-mr-1\">star</cide-ele-icon>\n Default\n </span>\n }\n </div>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeEntityMapping(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n\n <div class=\"tw-p-6\">\n <!-- Entity and Role Selection -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <div>\n <cide-ele-select label=\"Entity *\" [options]=\"getFilteredEntityOptions(i)\" formControlName=\"syenm_entity_id_syen\"\n valueKey=\"_id\" labelKey=\"syen_name\" placeholder=\"Select entity\" size=\"md\"\n (change)=\"onEntityChange(i, $event)\">\n </cide-ele-select>\n \n @if (isAllEntitiesSelected(i)) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded-md\">\n <p class=\"tw-text-xs tw-text-yellow-700\">\n <cide-ele-icon variant=\"warning\" size=\"xs\" class=\"tw-mr-1\">info</cide-ele-icon>\n All entities are already mapped. Remove another mapping to add this one.\n </p>\n </div>\n }\n </div>\n <cide-ele-select label=\"Role for this Entity\" [options]=\"getRoleOptionsForEntity(i)\"\n formControlName=\"syenm_role_id_syusrol\" valueKey=\"_id\" labelKey=\"syusrol_role_name\" placeholder=\"Select role for this entity\" size=\"md\"\n (change)=\"onRoleChange(i, $event)\">\n </cide-ele-select>\n </div>\n\n <!-- Role Permissions Grid -->\n @if (selectedEntityIndex() === i && selectedRoleId()) {\n <div class=\"tw-mb-6 tw-border tw-border-gray-200 tw-rounded-lg tw-bg-gray-50\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-white tw-rounded-t-lg\">\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">security</cide-ele-icon>\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800 tw-m-0\">Role Permissions Preview</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">(Read-only view of selected role permissions)</span>\n </div>\n </div>\n \n <div class=\"tw-p-4\">\n @if (loading()) {\n <div class=\"tw-flex tw-items-center tw-justify-center tw-py-8\">\n <div class=\"tw-animate-spin tw-rounded-full tw-h-8 tw-w-8 tw-border-b-2 tw-border-blue-600\"></div>\n <span class=\"tw-ml-2 tw-text-gray-600\">Loading role permissions...</span>\n </div>\n } @else if (error()) {\n <div class=\"tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\n <div class=\"tw-flex tw-items-start\">\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\n <div class=\"tw-ml-3\">\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\n </div>\n </div>\n </div>\n } @else {\n <cide-ele-data-grid \n [config]=\"rolePermissionsGridConfig()\" \n [templateRenderers]=\"templateRenderers\"\n (gridEvent)=\"onRolePermissionsGridEvent($event)\"\n class=\"tw-h-96 tw-w-full\">\n </cide-ele-data-grid>\n }\n </div>\n </div>\n }\n\n <!-- Entity-Specific Details -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Department for this Entity\" [options]=\"getDepartmentOptionsForEntity(i)\"\n formControlName=\"syenm_department_id_sydept\" (change)=\"onDepartmentChange($event)\" valueKey=\"_id\" labelKey=\"sydept_name\" placeholder=\"Select department\" size=\"md\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Designation for this Entity\" [options]=\"getDesignationOptionsForEntity(i)\" valueKey=\"_id\" labelKey=\"sydsg_name\"\n formControlName=\"syenm_designation_id_sydsg\" placeholder=\"Select designation\" size=\"md\">\n </cide-ele-select>\n </div>\n\n <!-- Active Period for Entity Mapping -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Active From *\" [id]=\"'syenm_activefrom['+i+']'\"\n formControlName=\"syenm_activefrom\" type=\"date\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Active Until\" [id]=\"'syenm_activeupto['+i+']'\"\n formControlName=\"syenm_activeupto\" type=\"date\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Mapping Settings -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-6 tw-mb-6\">\n <div class=\"tw-p-3 tw-bg-green-50 tw-border tw-border-green-200 tw-rounded-lg\">\n <cide-ele-input type=\"checkbox\" label=\"Default Entity\" formControlName=\"syenm_isdefault\"\n (change)=\"onDefaultEntityChange(i, $event)\" class=\"tw-h-5 tw-accent-green-500\" />\n <span class=\"tw-text-xs tw-text-green-600 tw-block tw-mt-1\">Set as user's default entity (only one\n allowed)</span>\n </div>\n\n <div class=\"tw-p-3 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg\">\n <cide-ele-input type=\"checkbox\" label=\"Active Mapping\" formControlName=\"syenm_isactive\"\n class=\"tw-h-5 tw-accent-blue-500\" />\n <span class=\"tw-text-xs tw-text-blue-600 tw-block tw-mt-1\">Enable this entity mapping</span>\n </div>\n </div>\n\n <!-- Menu Rights Grid for this Entity-Role -->\n <div class=\"tw-border-t tw-border-gray-200 tw-pt-4\">\n <div class=\"tw-flex tw-justify-between tw-items-center tw-mb-4\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800\">Menu Rights & Permissions</h6>\n <div class=\"tw-flex tw-gap-2\">\n <button cideEleButton variant=\"secondary\" size=\"sm\" type=\"button\" (click)=\"refreshMenuRights(i)\"\n leftIcon=\"refresh\">\n Refresh Rights\n </button>\n </div>\n </div>\n\n @if (getMenuRightsForMapping(i).length > 0) {\n <!-- Menu Rights Tree Grid -->\n <div class=\"tw-border tw-border-gray-200 tw-rounded-lg tw-bg-white\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-rounded-t-lg\">\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">security</cide-ele-icon>\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800 tw-m-0\">Menu Rights & Permissions</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">(Editable permissions for this entity-role mapping)</span>\n </div>\n </div>\n \n <div class=\"tw-p-4\">\n <cide-ele-data-grid \n [config]=\"getMenuRightsGridConfig(i)\" \n [templateRenderers]=\"getMenuRightsTemplateRenderers(i)\"\n (gridEvent)=\"onMenuRightsGridEvent($event, i)\"\n class=\"tw-h-96 tw-w-full\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-bg-gray-50 tw-border tw-border-gray-200 tw-rounded-lg\">\n <div class=\"tw-text-gray-400 tw-mb-3\">\n <cide-ele-icon variant=\"gray\" size=\"lg\">menu</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-600 tw-mb-2\">No Menu Rights Available</h6>\n <p class=\"tw-text-xs tw-text-gray-500 tw-mb-3 tw-text-center\">Select both entity and role to load\n menu rights for this mapping.</p>\n @if (mapping.syenm_entity_id_syen?._id && mapping.syenm_role_id_syusrol) {\n <button cideEleButton variant=\"primary\" size=\"sm\" type=\"button\" (click)=\"loadMenuRights(i)\"\n leftIcon=\"refresh\">\n Load Menu Rights\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (entityMappings().length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-bg-white tw-border tw-border-blue-200 tw-rounded-lg\">\n <div class=\"tw-text-blue-400 tw-mb-3\">\n <cide-ele-icon variant=\"blue\" size=\"lg\">business</cide-ele-icon>\n </div>\n <h4 class=\"tw-text-sm tw-font-medium tw-text-blue-800 tw-mb-2\">No Entity Mappings</h4>\n <p class=\"tw-text-blue-600 tw-mb-4 tw-text-center\">Add entity mappings to assign specific roles and\n permissions for different entities.</p>\n <button class=\"tw-mx-auto\" cideEleButton variant=\"primary\" size=\"md\" type=\"button\"\n (click)=\"addEntityMapping()\" leftIcon=\"add\">\n Add First Entity Mapping\n </button>\n </div>\n }\n </div>\n\n\n </div>\n }\n\n @case ('addresses') {\n <!-- Contact Addresses Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n <div class=\"tw-flex tw-justify-end\">\n <div class=\"tw-flex tw-justify-between tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addContactAddress()\"\n leftIcon=\"add\">\n Add New Address\n </button>\n </div>\n </div>\n\n <div formArrayName=\"core_user_contact_addresses\">\n @for (address of contactAddresses(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-6 tw-py-1 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">Address {{ i + 1 }}</h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeContactAddress(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-6\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Address Type\" [options]=\"addressTypeOptions()\" id=\"sycad_address_type_id_sygms\"\n formControlName=\"sycad_address_type_id_sygms\" placeholder=\"Select address type\" size=\"md\"\n valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Contact Person Name\" formControlName=\"sycad_contact_person_name\"\n placeholder=\"Enter contact person name\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 tw-mb-6\">\n <cide-ele-textarea label=\"Complete Address\" formControlName=\"sycad_contact_address\"\n placeholder=\"Enter complete address with area, city, and landmarks\" [rows]=\"3\" size=\"md\">\n </cide-ele-textarea>\n </div>\n\n <!-- Postal Code & City -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select \n label=\"Postal Code\"\n [options]=\"addressPostalCodes()[i] || []\" \n formControlName=\"sycad_contact_pin_sypin\"\n placeholder=\"Select postal code\"\n [searchable]=\"true\"\n [loading]=\"addressPostalCodesLoading()[i] || false\"\n (searchChange)=\"onPostalCodeSearch($event, i)\"\n (change)=\"onPostalCodeSelection($event, i)\"\n size=\"md\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"City\" \n formControlName=\"sycad_contact_city_sypin\"\n placeholder=\"Enter city\"\n size=\"md\">\n </cide-ele-input>\n </div>\n \n <!-- State & Country -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input \n label=\"State\" \n formControlName=\"sycad_contact_state_sypin\"\n placeholder=\"Enter state\"\n size=\"md\">\n </cide-ele-input>\n\n <cide-ele-select \n label=\"Country\" \n [options]=\"addressCountries()[i] || []\" \n formControlName=\"sycad_contact_country_syctr\"\n placeholder=\"Select country\"\n valueKey=\"_id\"\n labelKey=\"syctr_country_iso_name\"\n [searchable]=\"true\"\n (searchChange)=\"onCountrySearch($event, i)\"\n [loading]=\"addressCountriesLoading()[i] || false\"\n size=\"md\">\n </cide-ele-select>\n </div>\n\n <!-- Phone Numbers -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input \n label=\"Primary Phone\" \n formControlName=\"sycad_contact_phone\"\n type=\"tel\"\n placeholder=\"Enter primary phone number\"\n size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Alternate Phone\" \n formControlName=\"sycad_contact_phone_alt\"\n type=\"tel\"\n placeholder=\"Enter alternate phone number\"\n size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Fax & Email -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input \n label=\"Fax Number\" \n formControlName=\"sycad_contact_fax\"\n placeholder=\"Enter fax number\"\n size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Primary Email\" \n formControlName=\"sycad_contact_email\"\n type=\"email\"\n placeholder=\"Enter primary email address\"\n size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Alternate Email -->\n <div class=\"tw-grid tw-grid-cols-1 tw-mb-6\">\n <cide-ele-input \n label=\"Alternate Email\" \n formControlName=\"sycad_contact_email_alt\"\n type=\"email\"\n placeholder=\"Enter alternate email address\"\n size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @case ('documents') {\n <!-- Documents Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n <div class=\"tw-flex tw-justify-end tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addDocument()\" leftIcon=\"add\">\n Add Document\n </button>\n </div>\n\n <div formArrayName=\"core_user_documents\">\n @for (doc of documents(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-6 tw-py-1 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">Document {{ i + 1 }}</h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeDocument(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-6\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Document Type\" [options]=\"documentTypeOptions()\"\n formControlName=\"syusd_document_type_id_sygms\"\n placeholder=\"Select document type\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Document Number\" formControlName=\"syusd_doc_number\"\n placeholder=\"Enter document number\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Name as per Document\"\n formControlName=\"syusd_doc_name_as_per_doc\"\n placeholder=\"Enter name exactly as shown on document\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-select label=\"Photo Group\" [options]=\"photoGroupOptions()\"\n formControlName=\"syusd_photo_group_id_cyfm\"\n placeholder=\"Select photo group\" size=\"md\" valueKey=\"_id\" labelKey=\"cyfm_name\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Issue Date\" formControlName=\"syusd_doc_issue_date\"\n [id]=\"'syusd_doc_issue_date['+i+']'\" type=\"date\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Expiry Date\" formControlName=\"syusd_doc_expiry_date\"\n [id]=\"'syusd_doc_expiry_date['+i+']'\" type=\"date\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\n <cide-ele-select label=\"Document Verification Status\" [options]=\"documentVerificationStatusOptions()\"\n formControlName=\"syusd_doc_verification_status_id_sygms\"\n placeholder=\"Select verification status\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Document KYC Status\" [options]=\"documentKycStatusOptions()\"\n formControlName=\"syusd_doc_kyc_status_id_sygms\"\n placeholder=\"Select KYC status\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @case ('family') {\n <!-- Family Details Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n <div class=\"tw-flex tw-justify-end tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addFamilyDetail()\" leftIcon=\"add\">\n Add Family Member\n </button>\n </div>\n\n <div formArrayName=\"core_user_family_details\">\n @for (family of familyDetails(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-6 tw-py-1 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">Family Member {{ i + 1 }}\n </h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeFamilyDetail(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-6\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Family Member Name\"\n formControlName=\"syfdl_family_member_name\"\n placeholder=\"Enter family member full name\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-select \n label=\"Family Member User\"\n [options]=\"userOptions(i)\"\n formControlName=\"syfdl_family_member_id_user\"\n placeholder=\"Select family member user\" \n size=\"md\" \n valueKey=\"_id\" \n labelKey=\"user_fullname\"\n [searchable]=\"true\"\n [loading]=\"userSearchLoading()[i] || false\"\n (searchChange)=\"onUserSearchChange($event, i)\"\n (change)=\"onUserSelectionChange($event, i)\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Relationship\" [options]=\"relationshipOptions()\"\n formControlName=\"syfdl_relationship_id_sygms\"\n placeholder=\"Select relationship\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Blood Group\" [options]=\"bloodGroupOptions()\"\n formControlName=\"syfdl_blood_group_sygms\"\n placeholder=\"Select blood group\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Date of Birth\"\n formControlName=\"syfdl_family_member_dob\" type=\"date\" size=\"md\"\n [id]=\"'syfdl_family_member_dob['+i+']'\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Contact Phone\"\n formControlName=\"syfdl_contact_phone\"\n type=\"tel\" placeholder=\"Enter contact phone\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Contact Email\" formControlName=\"syfdl_contact_email\"\n type=\"email\" placeholder=\"Enter contact email\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Contact Email ID\" formControlName=\"syfdl_contact_email_id\"\n type=\"email\" placeholder=\"Enter contact email ID\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\n <cide-ele-input label=\"Contact Number\" formControlName=\"syfdl_contact_number\"\n type=\"tel\" placeholder=\"Enter contact number\" size=\"md\">\n </cide-ele-input>\n\n <div class=\"tw-flex tw-items-center tw-pt-6\">\n <cide-ele-input \n formControlName=\"syfdl_isactive\"\n type=\"checkbox\"\n label=\"Active\"\n size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Form Actions -->\n <div\n class=\"tw-flex tw-justify-end tw-gap-4 tw-py-2 tw-bg-white tw-border-t tw-border-gray-200 tw-sticky tw-bottom-0 tw-z-10\">\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n\n <button cideEleButton type=\"submit\" variant=\"primary\" [disabled]=\"loading() || userMasterForm.invalid\"\n [loading]=\"loading()\" leftIcon=\"save\">\n Save User Master\n </button>\n </div>\n </form>\n</div>\n\n<!-- Template Renderers for Role Permissions Grid -->\n<ng-template #menuDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-items-center tw-space-x-3 tw-min-w-0\">\n <!-- Menu Icon -->\n <div class=\"tw-flex-shrink-0\">\n @if (row.syme_type === 'module') {\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">folder</cide-ele-icon>\n } @else if (row.syme_type === 'section') {\n <cide-ele-icon class=\"tw-text-green-600 tw-w-4 tw-h-4\">folder_open</cide-ele-icon>\n } @else if (row.syme_type === 'menu') {\n <cide-ele-icon class=\"tw-text-purple-600 tw-w-4 tw-h-4\">menu</cide-ele-icon>\n } @else {\n <cide-ele-icon class=\"tw-text-gray-600 tw-w-4 tw-h-4\">description</cide-ele-icon>\n }\n </div>\n \n <!-- Menu Details -->\n <div class=\"tw-ml-3 tw-min-w-0 tw-flex-1\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-text-xs tw-font-medium tw-text-gray-900 tw-truncate\" \n [title]=\"row.syme_title\">\n {{ row.syme_title || row.menu?.syme_title || row.menu?.syme_menu_name || 'Untitled' }}\n </div>\n <!-- Green pill indicator for parent menus with child permissions -->\n @if (row.syme_type === 'module' || row.syme_type === 'section') {\n @if (hasChildMenusWithPermissions(row._id)) {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800 tw-whitespace-nowrap\">\n Assigned\n </span>\n }\n }\n </div>\n @if (row.permission?.sygms_name) {\n <div class=\"tw-text-xs tw-text-blue-500 tw-truncate\" \n [title]=\"row.permission?.sygms_name\">\n {{ row.permission?.sygms_name }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<!-- Menu Type Renderer Template -->\n<ng-template #menuTypeRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-items-center tw-justify-center\">\n @if (row.syme_type === 'module') {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-blue-100 tw-text-blue-800\">\n Module\n </span>\n } @else if (row.syme_type === 'section') {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n Section\n </span>\n } @else if (row.syme_type === 'menu') {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-purple-100 tw-text-purple-800\">\n Menu\n </span>\n } @else {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-gray-100 tw-text-gray-800\">\n {{ row.syme_type || 'Unknown' }}\n </span>\n }\n </div>\n</ng-template>\n\n<!-- Permissions Checkbox Renderer Template -->\n<ng-template #permissionsCheckboxRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n @if (row.syme_type === 'menu' && row?.syme_permissions_id_sygms && row?.syme_permissions_id_sygms.length > 0) {\n @for (permissionId of row?.syme_permissions_id_sygms || []; track permissionId) {\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"isPermissionSelected(row._id, permissionId)\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-blue-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">\n {{ getPermissionById(permissionId)?.sygms_name || 'Unknown' }}\n </label>\n </div>\n </div>\n }\n } @else {\n <!-- Show green checkmark for parent menus with child permissions -->\n @if (row.syme_type === 'module' || row.syme_type === 'section' || row.syme_type === 'title') {\n @if (hasChildMenusWithPermissions(row._id)) {\n <div class=\"tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-bg-green-100 tw-rounded-full\">\n <cide-ele-icon \n class=\"tw-text-green-600\" \n size=\"xs\">\n check\n </cide-ele-icon>\n </div>\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">N/A</span>\n }\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">N/A</span>\n }\n }\n </div>\n</ng-template>\n\n<!-- Menu Rights Permissions Renderer Template -->\n<ng-template #menuRightsPermissionsRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n <!-- Role Rights Display -->\n @if (row.role_rights && row.role_rights.length > 0) {\n <div class=\"tw-mb-2\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Role Rights:</div>\n <div class=\"tw-flex tw-flex-wrap tw-gap-1\">\n @for (right of row.role_rights; track $index) {\n <span class=\"tw-inline-block tw-px-2 tw-py-1 tw-text-xs tw-bg-blue-100 tw-text-blue-800 tw-rounded\">\n {{ right }}\n </span>\n }\n </div>\n </div>\n }\n \n <!-- Individual Permission Controls -->\n <div class=\"tw-grid tw-grid-cols-2 tw-gap-2 tw-w-full\">\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"row.create\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-green-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-green-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">Create</label>\n </div>\n \n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"row.read\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-blue-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">Read</label>\n </div>\n \n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"row.update\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-yellow-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-yellow-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">Update</label>\n </div>\n \n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"row.delete\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-red-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-red-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">Delete</label>\n </div>\n </div>\n \n <!-- Exception Indicator -->\n @if (row.hasException) {\n <div class=\"tw-mt-2\">\n <span class=\"tw-inline-block tw-px-2 tw-py-1 tw-text-xs tw-bg-yellow-100 tw-text-yellow-800 tw-rounded\">\n Override\n </span>\n </div>\n } @else {\n <div class=\"tw-mt-2\">\n <span class=\"tw-text-xs tw-text-gray-400\">Default</span>\n </div>\n }\n </div>\n</ng-template>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: FormsModule }, { 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", "valueKey", "labelKey"], 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: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton]", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleTabComponent, selector: "cide-ele-tab", inputs: ["tabs", "activeTabId", "size", "variant", "fullWidth", "disabled"], outputs: ["tabChange"] }, { kind: "component", type: CideEleFileInputComponent, selector: "cide-ele-file-input", inputs: ["label", "accept", "multiple", "disabled", "required", "helperText", "errorText", "showPreview", "previewWidth", "previewHeight", "previewBoxMode", "showFileName", "placeholderText", "placeholderIcon", "autoUpload", "uploadData"], outputs: ["fileChange", "uploadSuccess", "uploadError", "uploadProgressChange"] }, { kind: "directive", type: CideEleFileImageDirective, selector: "[cideEleFileImage]", inputs: ["fileId", "altText"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }] });
|
|
14163
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideCoreUserCreateComponent, isStandalone: true, selector: "cide-core-user-create", viewQueries: [{ propertyName: "menuDetailsRendererTemplate", first: true, predicate: ["menuDetailsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "permissionsCheckboxRendererTemplate", first: true, predicate: ["permissionsCheckboxRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "menuTypeRendererTemplate", first: true, predicate: ["menuTypeRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "menuRightsPermissionsRendererTemplate", first: true, predicate: ["menuRightsPermissionsRendererTemplate"], descendants: true, isSignal: true }, { propertyName: "permissionsRendererTemplate", first: true, predicate: ["permissionsRendererTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- \n ENTERPRISE USER MASTER FORM\n \n Enterprise-Level Styling with Tailwind CSS\n Features: Responsive grids, proper typography, enhanced user experience\n-->\n\n<div class=\"tw-w-full tw-h-full tw-p-1 tw-pt-2\">\n <form class=\"tw-max-w-7xl tw-mx-auto tw-bg-transparent\" [formGroup]=\"userMasterForm\" [class.tw-opacity-60]=\"loading()\"\n (ngSubmit)=\"onSubmit()\">\n\n <!-- Success/Error Messages -->\n @if (success()) {\n <div class=\"tw-mb-4 tw-p-4 tw-bg-green-50 tw-border tw-border-green-200 tw-rounded-md tw-shadow-sm\">\n <div class=\"tw-flex tw-items-start\">\n <cide-ele-icon name=\"check_circle\" class=\"tw-text-green-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\n <div class=\"tw-ml-3\">\n <h3 class=\"tw-text-sm tw-font-medium tw-text-green-800 tw-m-0\">Success</h3>\n <p class=\"tw-text-sm tw-text-green-700 tw-mt-1 tw-m-0\">{{ success() }}</p>\n </div>\n <button type=\"button\" (click)=\"success.set(null)\" class=\"tw-ml-auto tw-text-green-400 hover:tw-text-green-600\">\n <cide-ele-icon name=\"close\" class=\"tw-w-4 tw-h-4\"></cide-ele-icon>\n </button>\n </div>\n </div>\n }\n @if (error()) {\n <div class=\"tw-mb-4 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md tw-shadow-sm\">\n <div class=\"tw-flex tw-items-start\">\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\n <div class=\"tw-ml-3\">\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\n </div>\n <button type=\"button\" (click)=\"error.set(null)\" class=\"tw-ml-auto tw-text-red-400 hover:tw-text-red-600\">\n <cide-ele-icon name=\"close\" class=\"tw-w-4 tw-h-4\"></cide-ele-icon>\n </button>\n </div>\n </div>\n }\n\n <!-- User Context Header -->\n <div\n class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-indigo-50 tw-border tw-border-blue-200 tw-rounded-md tw-p-1 tw-mb-2 tw-shadow-sm\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-flex-wrap tw-gap-2\">\n <!-- User Basic Info Display -->\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-flex-wrap\">\n <!-- Profile Photo Preview -->\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div\n class=\"tw-w-8 tw-h-8 tw-rounded-full tw-bg-blue-100 tw-border tw-border-blue-200 tw-flex tw-items-center tw-justify-center tw-overflow-hidden\">\n @if (userMasterForm.get('user_photo_id_cyfm')?.value) {\n <img cideEleFileImage [fileId]=\"userMasterForm.get('user_photo_id_cyfm')?.value\"\n [altText]=\"'Profile Photo'\" class=\"tw-w-full tw-h-full tw-object-cover\">\n } @else {\n <cide-ele-icon name=\"person\" class=\"tw-w-5 tw-h-5 tw-text-blue-600\">\n </cide-ele-icon>\n }\n </div>\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-xs tw-font-medium tw-text-blue-900\">\n {{ getUserFullName() || 'New User' }}\n </span>\n <span class=\"tw-text-xs tw-text-blue-600\">\n {{ getUserUsername() || 'Username not set' }}\n </span>\n </div>\n </div>\n\n <!-- Contact Info -->\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-700\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">email</cide-ele-icon>\n <span>{{ getUserEmail() || 'Email not set' }}</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-700\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">phone</cide-ele-icon>\n <span>{{ getUserMobile() || 'Mobile not set' }}</span>\n </div>\n </div>\n\n <!-- Active Status -->\n <div class=\"tw-flex tw-items-center tw-gap-1\">\n @if (getUserActiveStatus()) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-700\">\n <cide-ele-icon variant=\"green\" size=\"xs\" class=\"tw-mr-1\">check_circle</cide-ele-icon>\n Active\n </span>\n } @else {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-700\">\n <cide-ele-icon variant=\"red\" size=\"xs\" class=\"tw-mr-1\">cancel</cide-ele-icon>\n Inactive\n </span>\n }\n </div>\n </div>\n\n <!-- Entity Info -->\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n @if (hasDefaultEntity()) {\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-blue-700\">\n <cide-ele-icon variant=\"blue\" size=\"xs\">business</cide-ele-icon>\n <span class=\"tw-font-medium\">{{ getDefaultEntityName() }}</span>\n </div>\n } @else {\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-500\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">business</cide-ele-icon>\n <span class=\"tw-italic\">No entity</span>\n </div>\n }\n\n <span class=\"tw-text-xs tw-text-gray-600 tw-px-2 tw-py-1 tw-bg-gray-100 tw-rounded\">\n {{ getEntityMappingCount() }} mapping(s)\n </span>\n </div>\n </div>\n </div>\n\n <!-- Tab Navigation -->\n <div class=\"tw-p-0 tw-mb-2 tw-border-b tw-border-gray-200\">\n <cide-ele-tab [tabs]=\"userTabs()\" [activeTabId]=\"activeTab()\" size=\"md\" variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n @switch (activeTab()) {\n\n @case ('basic') {\n <!-- User Basic Information Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n\n <!-- Top Section: Form Fields on Left, Profile Photo on Right -->\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-[1fr_200px] tw-gap-4 tw-mb-4\">\n <!-- Left Side: Form Fields -->\n <div class=\"tw-space-y-4\">\n <!-- Name Fields - All in One Row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4\">\n <cide-ele-input id=\"user_firstname\" label=\"First Name *\" formControlName=\"user_firstname\"\n placeholder=\"Enter first name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_middlename\" label=\"Middle Name\" formControlName=\"user_middlename\"\n placeholder=\"Enter middle name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_lastname\" label=\"Last Name *\" formControlName=\"user_lastname\"\n placeholder=\"Enter last name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_fullname\" label=\"Full Name * (Auto-generated)\" formControlName=\"user_fullname\"\n placeholder=\"Auto-generated from name fields or enter manually\" [maxlength]=\"62\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Contact Information - All in One Row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-3 tw-gap-4\">\n <cide-ele-input id=\"user_username\" label=\"Username *\" formControlName=\"user_username\"\n placeholder=\"Enter unique username\" [maxlength]=\"20\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_emailid\" label=\"Email ID *\" formControlName=\"user_emailid\" type=\"email\"\n placeholder=\"Enter valid email address\" [maxlength]=\"320\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_mobileno\" label=\"Mobile Number *\" formControlName=\"user_mobileno\" type=\"tel\"\n placeholder=\"Enter mobile number\" [maxlength]=\"15\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Right Side: Profile Photo Upload -->\n <div class=\"tw-flex tw-items-start tw-justify-center tw-p-0\">\n <cide-ele-file-input id=\"user_photo_id_cyfm\" formControlName=\"user_photo_id_cyfm\" accept=\"image/*\"\n [showPreview]=\"true\" [previewBoxMode]=\"true\" [showFileName]=\"false\" previewWidth=\"180px\"\n previewHeight=\"120px\" placeholderText=\"Upload Photo\" placeholderIcon=\"cloud_upload\" [autoUpload]=\"true\"\n [uploadData]=\"getProfilePhotoUploadData()\" (uploadSuccess)=\"onProfilePhotoUploadSuccess($event)\"\n (uploadError)=\"onProfilePhotoUploadError($event)\"\n (uploadProgressChange)=\"onProfilePhotoUploadProgress($event)\">\n </cide-ele-file-input>\n </div>\n </div>\n\n\n\n <!-- Status Control -->\n <div class=\"tw-grid tw-grid-cols-1 tw-mb-2\">\n <div class=\"tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-100 tw-rounded-lg\">\n <label\n class=\"tw-flex tw-flex-col tw-cursor-pointer tw-py-2 tw-bg-transparent tw-border-none tw-rounded-none tw-transition-all tw-duration-200 hover:tw-bg-blue-75\">\n <cide-ele-input type=\"checkbox\" label=\"Active User Status\" formControlName=\"user_isactive\"\n class=\"tw-h-5 tw-accent-blue-500 tw-rounded tw-mb-1\" />\n <span class=\"tw-font-semibold tw-text-gray-700 tw-text-base\"></span>\n <span class=\"tw-text-sm tw-text-gray-600 tw-mt-1 tw-leading-relaxed\">Enable this user account for system\n access and operations</span>\n </label>\n </div>\n </div>\n </div>\n }\n\n @case ('auth') {\n <!-- Authentication Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n <!-- Password Fields -->\n @if (shouldShowPasswordFields()) {\n <div class=\"tw-mb-4\">\n <!-- Password Fields Header for Edit Mode -->\n @if (isEditMode()) {\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800\">Update Password</h6>\n <button type=\"button\"\n class=\"tw-px-3 tw-py-1 tw-bg-gray-100 tw-text-gray-600 tw-border tw-border-gray-300 tw-rounded-md tw-text-xs tw-font-medium hover:tw-bg-gray-200 tw-transition-colors\"\n (click)=\"cancelPasswordUpdate()\">\n Cancel Password Update\n </button>\n </div>\n }\n\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 md:tw-grid-cols-1 tw-gap-6\">\n <cide-ele-input id=\"user_password\" [label]=\"getPasswordFieldLabel()\" formControlName=\"user_password\"\n type=\"password\" placeholder=\"Enter secure password (min 8 characters)\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_confirm_password\" [label]=\"getPasswordConfirmLabel()\"\n formControlName=\"user_confirm_password\" type=\"password\" placeholder=\"Confirm your password\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Password Update Option for Edit Mode -->\n @if (isEditMode() && !shouldShowPasswordFields()) {\n <div class=\"tw-mb-4\">\n <div class=\"tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-blue-800 tw-mb-2\">Password Update</h6>\n <p class=\"tw-text-sm tw-text-blue-600 tw-mb-3\">Current password will be kept. Click below to change\n password.</p>\n\n @if (hasPasswordInput()) {\n <div\n class=\"tw-mb-3 tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded tw-text-sm tw-text-yellow-700\">\n <cide-ele-icon variant=\"yellow\" size=\"xs\" class=\"tw-mr-1\">warning</cide-ele-icon>\n Password fields contain text. Click \"Change Password\" to manage existing input.\n </div>\n }\n\n <button type=\"button\"\n class=\"tw-px-4 tw-py-2 tw-bg-blue-100 tw-text-blue-700 tw-border tw-border-blue-300 tw-rounded-md tw-text-sm tw-font-medium hover:tw-bg-blue-200 tw-transition-colors\"\n (click)=\"triggerPasswordUpdate()\">\n @if (hasPasswordInput()) {\n Manage Password Fields\n } @else {\n Change Password\n }\n </button>\n </div>\n </div>\n }\n\n <!-- Password Options -->\n <div class=\"tw-grid tw-grid-cols-1 tw-gap-4 tw-mb-4\">\n <div class=\"tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-100 tw-rounded-lg\">\n <label\n class=\"tw-flex tw-flex-col tw-gap-2 tw-cursor-pointer tw-py-2 tw-bg-transparent tw-border-none tw-rounded-none tw-transition-all tw-duration-200\">\n <cide-ele-input type=\"checkbox\" label=\"Force Password Change on Login\"\n formControlName=\"user_passwordchangeonlogin\" class=\"tw-h-5 tw-accent-yellow-500 tw-rounded tw-mb-1\" />\n <span class=\"tw-text-sm tw-text-gray-600 tw-mt-1 tw-leading-relaxed\">User will be required to change\n password on next login</span>\n </label>\n </div>\n </div>\n\n </div>\n }\n\n @case ('roles') {\n <!-- Entity, Roles & Permissions Mapping Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n\n\n\n <!-- Important Note -->\n <div class=\"tw-bg-amber-50 tw-border tw-border-amber-200 tw-rounded-lg tw-p-2 tw-mb-4\">\n <div class=\"tw-flex tw-items-start tw-gap-3\">\n <cide-ele-icon variant=\"amber\" size=\"lg\">info</cide-ele-icon>\n <div class=\"tw-flex-1\">\n <h4 class=\"tw-text-sm tw-font-semibold tw-text-amber-800 tw-mb-1\">Entity-Role Based Access</h4>\n <p class=\"tw-text-sm tw-text-amber-700 tw-mb-2\">User access is completely managed through entity-role\n mappings below. At least one entity mapping is required for user access.</p>\n @if (hasDefaultEntity()) {\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mt-2 tw-p-2 tw-bg-amber-100 tw-rounded\">\n <cide-ele-icon variant=\"amber\" size=\"sm\">star</cide-ele-icon>\n <span class=\"tw-text-sm tw-text-amber-800\">\n <strong>Default Entity:</strong> {{ getDefaultEntityName() }}\n </span>\n </div>\n } @else {\n <div class=\"tw-text-sm tw-text-amber-600 tw-mt-2 tw-italic\">\n \u26A0\uFE0F No default entity selected. Please set one entity as default.\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Entity-Role Mapping Section -->\n <div class=\"tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg tw-p-3 tw-mb-4\">\n <div class=\"tw-flex tw-text-center tw-justify-between tw-items-center tw-mb-4\">\n <div>\n <h4 class=\"tw-text-sm tw-text-left tw-font-semibold tw-text-blue-900 tw-mb-1\">Entity-Role Mapping</h4>\n <p class=\"tw-text-sm tw-text-blue-700\">Map user to entities with specific roles and permissions</p>\n </div>\n <div class=\"tw-flex tw-flex-col tw-items-end\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addEntityMapping()\"\n leftIcon=\"add\" [disabled]=\"isAllEntitiesMapped()\">\n Add Entity Mapping\n </button>\n\n @if (isAllEntitiesMapped()) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-md tw-max-w-xs\">\n <p class=\"tw-text-xs tw-text-blue-700\">\n <cide-ele-icon variant=\"info\" size=\"xs\" class=\"tw-mr-1\">info</cide-ele-icon>\n All available entities are already mapped.\n </p>\n </div>\n }\n </div>\n </div>\n\n <div formArrayName=\"core_entity_mapping\">\n @for (mapping of entityMappings(); track $index; let i = $index) {\n <div class=\"tw-bg-white tw-border tw-border-blue-200 tw-rounded-xl tw-mb-6 tw-overflow-hidden tw-shadow-sm\"\n [formGroupName]=\"i\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-blue-100 tw-px-6 tw-py-3 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <h5 class=\"tw-m-0 tw-text-blue-800 tw-text-sm tw-font-semibold\">Entity Mapping {{ i + 1 }}</h5>\n @if (mapping.syenm_isdefault) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n <cide-ele-icon variant=\"green\" size=\"xs\" class=\"tw-mr-1\">star</cide-ele-icon>\n Default\n </span>\n }\n </div>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeEntityMapping(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n\n <div>\n <!-- Entity and Role Selection -->\n <div class=\"tw-grid tw-px-3 tw-py-1 tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4 tw-mb-4\">\n <div>\n <cide-ele-select label=\"Entity *\" [options]=\"getFilteredEntityOptions(i)\"\n formControlName=\"syenm_entity_id_syen\" valueKey=\"_id\" labelKey=\"syen_name\"\n placeholder=\"Select entity\" size=\"md\" (change)=\"onEntityChange(i, $event)\">\n </cide-ele-select>\n\n @if (isAllEntitiesSelected(i)) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded-md\">\n <p class=\"tw-text-xs tw-text-yellow-700\">\n <cide-ele-icon variant=\"warning\" size=\"xs\" class=\"tw-mr-1\">info</cide-ele-icon>\n All entities are already mapped. Remove another mapping to add this one.\n </p>\n </div>\n }\n </div>\n <cide-ele-select label=\"Role for this Entity\" [options]=\"getRoleOptionsForEntity(i)\"\n formControlName=\"syenm_role_id_syusrol\" valueKey=\"_id\" labelKey=\"syusrol_role_name\"\n placeholder=\"Select role for this entity\" size=\"md\" (change)=\"onRoleChange(i, $event)\">\n </cide-ele-select>\n </div>\n\n\n <!-- Entity-Specific Details and Active Period - All in One Row -->\n <div class=\"tw-grid tw-px-3 tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4 tw-mb-4\">\n <cide-ele-select label=\"Department for this Entity\" [options]=\"getDepartmentOptionsForEntity(i)\"\n formControlName=\"syenm_department_id_sydept\" (change)=\"onDepartmentChange($event)\" valueKey=\"_id\"\n labelKey=\"sydept_name\" placeholder=\"Select department\" size=\"md\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Designation for this Entity\" [options]=\"getDesignationOptionsForEntity(i)\"\n valueKey=\"_id\" labelKey=\"sydsg_name\" formControlName=\"syenm_designation_id_sydsg\"\n placeholder=\"Select designation\" size=\"md\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Active From *\" [id]=\"'syenm_activefrom['+i+']'\"\n formControlName=\"syenm_activefrom\" type=\"date\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Active Until\" [id]=\"'syenm_activeupto['+i+']'\"\n formControlName=\"syenm_activeupto\" type=\"date\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Mapping Settings -->\n <div class=\"tw-grid tw-px-3 tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-4 tw-mb-4\">\n <div class=\"tw-p-2 tw-bg-green-50 tw-border tw-border-green-200 tw-rounded-lg\">\n <cide-ele-input type=\"checkbox\" label=\"Default Entity\" formControlName=\"syenm_isdefault\"\n (change)=\"onDefaultEntityChange(i, $event)\" class=\"tw-h-5 tw-accent-green-500\" />\n <span class=\"tw-text-xs tw-text-green-600 tw-block tw-mt-1\">Set as user's default entity (only one\n allowed)</span>\n </div>\n\n <div class=\"tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg\">\n <cide-ele-input type=\"checkbox\" label=\"Active Mapping\" formControlName=\"syenm_isactive\"\n class=\"tw-h-5 tw-accent-blue-500\" />\n <span class=\"tw-text-xs tw-text-blue-600 tw-block tw-mt-1\">Enable this entity mapping</span>\n </div>\n </div>\n\n <!-- Menu Rights Grid for this Entity-Role -->\n <div class=\"tw-border-t tw-border-gray-200\">\n\n @if (getMenuRightsForMapping(i).length > 0) {\n <!-- Menu Rights Tree Grid -->\n\n <cide-ele-data-grid [config]=\"getMenuRightsGridConfig(i)\"\n [templateRenderers]=\"getMenuRightsTemplateRenderers(i)\"\n (gridEvent)=\"onMenuRightsGridEvent($event, i)\" class=\"tw-h-96 tw-w-full\">\n </cide-ele-data-grid>\n\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-bg-gray-50 tw-border tw-border-gray-200 tw-rounded-lg\">\n <div class=\"tw-text-gray-400 tw-mb-3\">\n <cide-ele-icon variant=\"gray\" size=\"lg\">menu</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-600 tw-mb-2\">No Menu Rights Available</h6>\n <p class=\"tw-text-xs tw-text-gray-500 tw-mb-3 tw-text-center\">Select both entity and role to\n automatically load\n menu rights for this mapping.</p>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (entityMappings().length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-bg-white tw-border tw-border-blue-200 tw-rounded-lg\">\n <div class=\"tw-text-blue-400 tw-mb-3\">\n <cide-ele-icon variant=\"blue\" size=\"lg\">business</cide-ele-icon>\n </div>\n <h4 class=\"tw-text-sm tw-font-medium tw-text-blue-800 tw-mb-2\">No Entity Mappings</h4>\n <p class=\"tw-text-blue-600 tw-mb-4 tw-text-center\">Add entity mappings to assign specific roles and\n permissions for different entities.</p>\n <button class=\"tw-mx-auto\" cideEleButton variant=\"primary\" size=\"md\" type=\"button\"\n (click)=\"addEntityMapping()\" leftIcon=\"add\">\n Add First Entity Mapping\n </button>\n </div>\n }\n </div>\n\n\n </div>\n }\n\n @case ('addresses') {\n <!-- Contact Addresses Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n <div class=\"tw-flex tw-justify-end\">\n <div class=\"tw-flex tw-justify-between tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addContactAddress()\"\n leftIcon=\"add\">\n Add New Address\n </button>\n </div>\n </div>\n\n <div formArrayName=\"core_user_contact_addresses\">\n @for (address of contactAddresses(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-4 tw-py-2 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <!-- Use address type as header instead of generic \"Address X\" -->\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">\n {{ getAddressTypeLabel(i) || ('Address ' + (i + 1)) }}\n </h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeContactAddress(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-4\">\n <!-- Main Layout: Inputs on Left, Address Textarea on Right -->\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-4 tw-gap-3 tw-mb-3\">\n \n <!-- Left Side: Input Fields (3/4 width) -->\n <div class=\"lg:tw-col-span-3\">\n <!-- Row 1: Address Type, Contact Person -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-mb-3\">\n <cide-ele-select label=\"Address Type\" [options]=\"addressTypeOptions()\" id=\"sycad_address_type_id_sygms\"\n formControlName=\"sycad_address_type_id_sygms\" placeholder=\"Select type\" size=\"sm\"\n valueKey=\"_id\" labelKey=\"sygms_title\" (change)=\"onAddressTypeChange(i)\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Contact Person\" formControlName=\"sycad_contact_person_name\"\n placeholder=\"Enter contact person\" size=\"sm\">\n </cide-ele-input>\n </div>\n\n <!-- Row 2: Postal Code, City, State, Country -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-4 tw-gap-3\">\n <cide-ele-select label=\"Postal Code\" [options]=\"addressPostalCodes()[i] || []\"\n formControlName=\"sycad_contact_pin_sypin\" placeholder=\"Select postal code\" [searchable]=\"true\"\n [loading]=\"addressPostalCodesLoading()[i] || false\" (searchChange)=\"onPostalCodeSearch($event, i)\"\n (change)=\"onPostalCodeSelection($event, i)\" size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-input label=\"City\" formControlName=\"sycad_contact_city_sypin\" placeholder=\"Enter city\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"State\" formControlName=\"sycad_contact_state_sypin\" placeholder=\"Enter state\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-select label=\"Country\" [options]=\"addressCountries()[i] || []\"\n formControlName=\"sycad_contact_country_syctr\" placeholder=\"Select country\" valueKey=\"_id\"\n labelKey=\"syctr_country_iso_name\" [searchable]=\"true\" (searchChange)=\"onCountrySearch($event, i)\"\n [loading]=\"addressCountriesLoading()[i] || false\" size=\"sm\">\n </cide-ele-select>\n </div>\n </div>\n\n <!-- Right Side: Address Textarea (1/4 width, spans 2 rows) -->\n <div class=\"lg:tw-col-span-1 lg:tw-row-span-2 tw-flex tw-flex-col\">\n <cide-ele-textarea label=\"Complete Address\" formControlName=\"sycad_contact_address\"\n placeholder=\"Enter complete address with area, city, and landmarks\" [rows]=\"4\" size=\"sm\"\n class=\"tw-h-full\">\n </cide-ele-textarea>\n </div>\n </div>\n\n <!-- Contact Details: Primary Phone, Alt Phone, Fax, Primary Email in 4 columns -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-4 tw-gap-3 tw-mb-3\">\n <cide-ele-input label=\"Primary Phone\" formControlName=\"sycad_contact_phone\" type=\"tel\"\n placeholder=\"Primary phone\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Alternate Phone\" formControlName=\"sycad_contact_phone_alt\" type=\"tel\"\n placeholder=\"Alternate phone\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Fax Number\" formControlName=\"sycad_contact_fax\" placeholder=\"Fax number\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Primary Email\" formControlName=\"sycad_contact_email\" type=\"email\"\n placeholder=\"Primary email\" size=\"sm\">\n </cide-ele-input>\n </div>\n\n <!-- Alternate Email in single row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input label=\"Alternate Email\" formControlName=\"sycad_contact_email_alt\" type=\"email\"\n placeholder=\"Alternate email address\" size=\"sm\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @case ('documents') {\n <!-- Documents Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n <div class=\"tw-flex tw-justify-end tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addDocument()\" leftIcon=\"add\">\n Add Document\n </button>\n </div>\n\n <div formArrayName=\"core_user_documents\">\n @for (doc of documents(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-4 tw-py-2 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">\n {{ getDocumentTypeLabel(i) || ('Document ' + (i + 1)) }}\n </h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeDocument(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-4\">\n <!-- Main Layout: Inputs on Left, File Upload on Right -->\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-3 tw-gap-4\">\n \n <!-- Left Side: Document Information (2/3 width) -->\n <div class=\"lg:tw-col-span-2\">\n <!-- Row 1: Document Type, Document Number, Name as per Document -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-3 tw-mb-3\">\n <cide-ele-select label=\"Document Type\" [options]=\"documentTypeOptions()\"\n formControlName=\"syusd_document_type_id_sygms\" placeholder=\"Select type\" size=\"sm\"\n valueKey=\"_id\" labelKey=\"sygms_title\" (change)=\"onDocumentTypeChange(i)\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Document Number\" formControlName=\"syusd_doc_number\"\n placeholder=\"Document number\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Name as per Document\" formControlName=\"syusd_doc_name_as_per_doc\"\n placeholder=\"Name on document\" size=\"sm\">\n </cide-ele-input>\n </div>\n\n <!-- Row 2: Issue Date, Expiry Date, Photo Group -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-3 tw-mb-3\">\n <cide-ele-input label=\"Issue Date\" formControlName=\"syusd_doc_issue_date\"\n [id]=\"'syusd_doc_issue_date['+i+']'\" type=\"date\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Expiry Date\" formControlName=\"syusd_doc_expiry_date\"\n [id]=\"'syusd_doc_expiry_date['+i+']'\" type=\"date\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-select label=\"Photo Group\" [options]=\"photoGroupOptions()\"\n formControlName=\"syusd_photo_group_id_cyfm\" placeholder=\"Select group\" size=\"sm\" valueKey=\"_id\"\n labelKey=\"cyfm_name\">\n </cide-ele-select>\n </div>\n\n <!-- Row 3: Verification Status, KYC Status -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-select label=\"Verification Status\" [options]=\"documentVerificationStatusOptions()\"\n formControlName=\"syusd_doc_verification_status_id_sygms\" placeholder=\"Select status\"\n size=\"sm\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-select label=\"KYC Status\" [options]=\"documentKycStatusOptions()\"\n formControlName=\"syusd_doc_kyc_status_id_sygms\" placeholder=\"Select KYC status\" size=\"sm\"\n valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n </div>\n </div>\n\n <!-- Right Side: File Upload (1/3 width) -->\n <div class=\"lg:tw-col-span-1\">\n <div class=\"tw-bg-gray-50 tw-border tw-border-gray-200 tw-rounded-lg tw-p-3 tw-h-full\">\n <h5 class=\"tw-text-sm tw-font-medium tw-text-gray-700 tw-mb-3 tw-m-0\">Document Files</h5>\n \n <!-- File Upload Input -->\n {{documentsFormArray.at(i).get('syusd_photo_group_id_cyfm')?.value}}\n <cide-ele-file-input\n [id]=\"'document-files-' + i\"\n [multiple]=\"true\"\n formControlName=\"syusd_photo_group_id_cyfm\"\n [accept]=\"'.pdf,.jpg,.jpeg,.png,.doc,.docx'\"\n [autoUpload]=\"true\"\n [uploadData]=\"getDocumentUploadData(i)\"\n (change)=\"onDocumentFilesSelected($event, i)\"\n (uploadSuccess)=\"onDocumentUploadSuccess($event, i)\"\n (uploadError)=\"onDocumentUploadError($event, i)\"\n (uploadProgressChange)=\"onDocumentUploadProgress($event, i)\"\n cideFloatingUploadTrigger\n class=\"tw-mb-3\"\n size=\"sm\">\n <div class=\"tw-text-center tw-py-4\">\n <cide-ele-icon name=\"cloud_upload\" class=\"tw-w-6 tw-h-6 tw-text-gray-400 tw-mx-auto tw-mb-2\"></cide-ele-icon>\n <p class=\"tw-text-xs tw-text-gray-600 tw-m-0\">Upload document files</p>\n <p class=\"tw-text-xs tw-text-gray-400 tw-m-0\">PDF, Images, Word docs</p>\n </div>\n </cide-ele-file-input>\n\n <!-- Upload Status -->\n @if (getDocumentGroupId(i)) {\n <div class=\"tw-space-y-2\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <h6 class=\"tw-text-xs tw-font-medium tw-text-gray-600 tw-m-0\">Upload Status:</h6>\n <span class=\"tw-text-xs tw-text-green-600 tw-font-medium\">\n \u2705 Files Uploaded\n </span>\n </div>\n <div class=\"tw-bg-green-50 tw-border tw-border-green-200 tw-rounded tw-p-2\">\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon name=\"cloud_done\" class=\"tw-w-4 tw-h-4 tw-text-green-500 tw-flex-shrink-0\"></cide-ele-icon>\n <div class=\"tw-flex tw-flex-col tw-flex-1 tw-min-w-0\">\n <span class=\"tw-text-xs tw-text-green-700 tw-font-medium\">Multiple files uploaded successfully</span>\n <span class=\"tw-text-xs tw-text-green-600 tw-font-mono tw-truncate\" [title]=\"'Group ID: ' + getDocumentGroupId(i)\">\n Group ID: {{ getDocumentGroupId(i).substring(0, 12) }}...\n </span>\n </div>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"tw-text-center tw-text-xs tw-text-gray-400 tw-py-2\">\n No files uploaded yet\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @case ('family') {\n <!-- Family Details Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n <div class=\"tw-flex tw-justify-end tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addFamilyDetail()\" leftIcon=\"add\">\n Add Family Member\n </button>\n </div>\n\n <div formArrayName=\"core_user_family_details\">\n @for (family of familyDetails(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-6 tw-py-1 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">Family Member {{ i + 1\n }}\n </h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeFamilyDetail(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-3\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Family Member Name\" formControlName=\"syfdl_family_member_name\"\n placeholder=\"Enter family member full name\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-select label=\"Family Member User\" [options]=\"userOptions(i)\"\n formControlName=\"syfdl_family_member_id_user\" placeholder=\"Select family member user\" size=\"md\"\n valueKey=\"_id\" labelKey=\"user_fullname\" [searchable]=\"true\"\n [loading]=\"userSearchLoading()[i] || false\" (searchChange)=\"onUserSearchChange($event, i)\"\n (change)=\"onUserSelectionChange($event, i)\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Relationship\" [options]=\"relationshipOptions()\"\n formControlName=\"syfdl_relationship_id_sygms\" placeholder=\"Select relationship\" size=\"md\"\n valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Blood Group\" [options]=\"bloodGroupOptions()\"\n formControlName=\"syfdl_blood_group_sygms\" placeholder=\"Select blood group\" size=\"md\" valueKey=\"_id\"\n labelKey=\"sygms_title\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Date of Birth\" formControlName=\"syfdl_family_member_dob\" type=\"date\" size=\"md\"\n [id]=\"'syfdl_family_member_dob['+i+']'\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Contact Phone\" formControlName=\"syfdl_contact_phone\" type=\"tel\"\n placeholder=\"Enter contact phone\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Contact Email\" formControlName=\"syfdl_contact_email\" type=\"email\"\n placeholder=\"Enter contact email\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Contact Email ID\" formControlName=\"syfdl_contact_email_id\" type=\"email\"\n placeholder=\"Enter contact email ID\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\n <cide-ele-input label=\"Contact Number\" formControlName=\"syfdl_contact_number\" type=\"tel\"\n placeholder=\"Enter contact number\" size=\"md\">\n </cide-ele-input>\n\n <div class=\"tw-flex tw-items-center tw-pt-6\">\n <cide-ele-input formControlName=\"syfdl_isactive\" type=\"checkbox\" label=\"Active\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Form Actions -->\n <div\n class=\"tw-flex tw-justify-end tw-gap-4 tw-py-2 tw-bg-white tw-border-t tw-border-gray-200 tw-sticky tw-bottom-0 tw-z-10\">\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n\n <button cideEleButton type=\"submit\" variant=\"primary\" [disabled]=\"loading() || userMasterForm.invalid\"\n [loading]=\"loading()\" leftIcon=\"save\">\n Save User Master\n </button>\n </div>\n </form>\n</div>\n\n<!-- Template Renderers for Role Permissions Grid -->\n<ng-template #menuDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-items-center tw-space-x-3 tw-min-w-0\">\n <!-- Menu Icon -->\n <div class=\"tw-flex-shrink-0\">\n @if (row.syme_type === 'module') {\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">folder</cide-ele-icon>\n } @else if (row.syme_type === 'section') {\n <cide-ele-icon class=\"tw-text-green-600 tw-w-4 tw-h-4\">folder_open</cide-ele-icon>\n } @else if (row.syme_type === 'menu') {\n <cide-ele-icon class=\"tw-text-purple-600 tw-w-4 tw-h-4\">menu</cide-ele-icon>\n } @else {\n <cide-ele-icon class=\"tw-text-gray-600 tw-w-4 tw-h-4\">description</cide-ele-icon>\n }\n </div>\n\n <!-- Menu Details -->\n <div class=\"tw-ml-3 tw-min-w-0 tw-flex-1\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-text-xs tw-font-medium tw-text-gray-900 tw-truncate\" [title]=\"row.syme_title\">\n {{ row.syme_title || row.menu?.syme_title || row.menu?.syme_menu_name || 'Untitled' }}\n </div>\n <!-- Green pill indicator for parent menus with child permissions -->\n @if (row.syme_type === 'module' || row.syme_type === 'section') {\n @if (hasChildMenusWithPermissions(row._id)) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800 tw-whitespace-nowrap\">\n Assigned\n </span>\n }\n }\n </div>\n @if (row.permission?.sygms_name) {\n <div class=\"tw-text-xs tw-text-blue-500 tw-truncate\" [title]=\"row.permission?.sygms_name\">\n {{ row.permission?.sygms_name }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<!-- Menu Type Renderer Template -->\n<ng-template #menuTypeRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-items-center tw-justify-center\">\n @if (row.syme_type === 'module') {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-blue-100 tw-text-blue-800\">\n Module\n </span>\n } @else if (row.syme_type === 'section') {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n Section\n </span>\n } @else if (row.syme_type === 'menu') {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-purple-100 tw-text-purple-800\">\n Menu\n </span>\n } @else {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-gray-100 tw-text-gray-800\">\n {{ row.syme_type || 'Unknown' }}\n </span>\n }\n </div>\n</ng-template>\n\n<!-- Permissions Checkbox Renderer Template -->\n<ng-template #permissionsCheckboxRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n @if (row.syme_type === 'menu' && row?.syme_permissions_id_sygms && row?.syme_permissions_id_sygms.length > 0) {\n @for (permissionId of row?.syme_permissions_id_sygms || []; track permissionId) {\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input type=\"checkbox\" [checked]=\"isPermissionSelected(row._id, permissionId)\" [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-blue-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">\n {{ getPermissionById(permissionId)?.sygms_name || 'Unknown' }}\n </label>\n </div>\n </div>\n }\n } @else {\n <!-- Show green checkmark for parent menus with child permissions -->\n @if (row.syme_type === 'module' || row.syme_type === 'section' || row.syme_type === 'title') {\n @if (hasChildMenusWithPermissions(row._id)) {\n <div class=\"tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-bg-green-100 tw-rounded-full\">\n <cide-ele-icon class=\"tw-text-green-600\" size=\"xs\">\n check\n </cide-ele-icon>\n </div>\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">N/A</span>\n }\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">N/A</span>\n }\n }\n </div>\n</ng-template>\n\n<!-- Menu Rights Permissions Renderer Template -->\n<ng-template #menuRightsPermissionsRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n <!-- Role Rights Display -->\n @if (row.role_rights && row.role_rights.length > 0) {\n <div class=\"tw-mb-2\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Role Rights:</div>\n <div class=\"tw-flex tw-flex-wrap tw-gap-1\">\n @for (right of row.role_rights; track $index) {\n <span class=\"tw-inline-block tw-px-2 tw-py-1 tw-text-xs tw-bg-blue-100 tw-text-blue-800 tw-rounded\">\n {{ right }}\n </span>\n }\n </div>\n </div>\n }\n\n\n <!-- Exception Indicator -->\n @if (row.hasException) {\n <div class=\"tw-mt-2\">\n <span class=\"tw-inline-block tw-px-2 tw-py-1 tw-text-xs tw-bg-yellow-100 tw-text-yellow-800 tw-rounded\">\n Override\n </span>\n </div>\n } @else {\n <div class=\"tw-mt-2\">\n <span class=\"tw-text-xs tw-text-gray-400\">Default</span>\n </div>\n }\n </div>\n</ng-template>\n\n<!-- Permissions Renderer Template -->\n<ng-template #permissionsRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n @if (row._permissionValues && Object.keys(row._permissionValues).length > 0) {\n @for (permissionId of Object.keys(row._permissionValues); track permissionId) {\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-input type=\"checkbox\" [ngModel]=\"row._permissionValues[permissionId].checked\"\n (ngModelChange)=\"onPermissionChangeSafe($event, row, permissionId)\"\n [id]=\"'permission-' + row._id + '-' + permissionId\" class=\"tw-h-4 tw-w-4\">\n </cide-ele-input>\n <label [for]=\"'permission-' + row._id + '-' + permissionId\" class=\"tw-text-xs tw-text-gray-700 tw-cursor-pointer\">\n {{ row._permissionValues[permissionId].permission?.sygms_title }}\n </label>\n </div>\n }\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">No permissions</span>\n }\n </div>\n</ng-template>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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", "valueKey", "labelKey"], 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: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton]", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleTabComponent, selector: "cide-ele-tab", inputs: ["tabs", "activeTabId", "size", "variant", "fullWidth", "disabled"], outputs: ["tabChange"] }, { kind: "component", type: CideEleFileInputComponent, selector: "cide-ele-file-input", inputs: ["label", "accept", "multiple", "disabled", "required", "helperText", "errorText", "showPreview", "previewWidth", "previewHeight", "previewBoxMode", "showFileName", "placeholderText", "placeholderIcon", "autoUpload", "uploadData"], outputs: ["fileChange", "uploadSuccess", "uploadError", "uploadProgressChange"] }, { kind: "directive", type: CideEleFileImageDirective, selector: "[cideEleFileImage]", inputs: ["fileId", "altText"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "directive", type: CideLytFloatingUploadTriggerDirective, selector: "[cideFloatingUploadTrigger]", inputs: ["userId"] }] });
|
|
13347
14164
|
}
|
|
13348
14165
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideCoreUserCreateComponent, decorators: [{
|
|
13349
14166
|
type: Component,
|
|
@@ -13359,8 +14176,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
13359
14176
|
CideEleFileInputComponent,
|
|
13360
14177
|
CideEleFileImageDirective,
|
|
13361
14178
|
CideIconComponent,
|
|
13362
|
-
CideEleDataGridComponent
|
|
13363
|
-
], template: "<!-- \n ENTERPRISE USER MASTER FORM\n \n Enterprise-Level Styling with Tailwind CSS\n Features: Responsive grids, proper typography, enhanced user experience\n-->\n\n<div class=\"tw-w-full tw-h-full tw-p-3\">\n <form class=\"tw-max-w-7xl tw-mx-auto tw-bg-transparent\" [formGroup]=\"userMasterForm\" [class.tw-opacity-60]=\"loading()\"\n (ngSubmit)=\"onSubmit()\">\n\n <!-- User Context Header -->\n <div\n class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-indigo-50 tw-border tw-border-blue-200 tw-rounded-md tw-p-2 tw-mb-3 tw-shadow-sm\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-flex-wrap tw-gap-2\">\n <!-- User Basic Info Display -->\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-flex-wrap\">\n <!-- Profile Photo Preview -->\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div\n class=\"tw-w-8 tw-h-8 tw-rounded-full tw-bg-blue-100 tw-border tw-border-blue-200 tw-flex tw-items-center tw-justify-center tw-overflow-hidden\">\n @if (userMasterForm.get('user_photo_id_cyfm')?.value) {\n <img \n cideEleFileImage \n [fileId]=\"userMasterForm.get('user_photo_id_cyfm')?.value\" \n [altText]=\"'Profile Photo'\"\n class=\"tw-w-full tw-h-full tw-object-cover\">\n } @else {\n <cide-ele-icon \n name=\"person\" \n class=\"tw-w-5 tw-h-5 tw-text-blue-600\">\n </cide-ele-icon>\n }\n </div>\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-xs tw-font-medium tw-text-blue-900\">\n {{ getUserFullName() || 'New User' }}\n </span>\n <span class=\"tw-text-xs tw-text-blue-600\">\n {{ getUserUsername() || 'Username not set' }}\n </span>\n </div>\n </div>\n\n <!-- Contact Info -->\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-700\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">email</cide-ele-icon>\n <span>{{ getUserEmail() || 'Email not set' }}</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-700\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">phone</cide-ele-icon>\n <span>{{ getUserMobile() || 'Mobile not set' }}</span>\n </div>\n </div>\n\n <!-- Active Status -->\n <div class=\"tw-flex tw-items-center tw-gap-1\">\n @if (getUserActiveStatus()) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-700\">\n <cide-ele-icon variant=\"green\" size=\"xs\" class=\"tw-mr-1\">check_circle</cide-ele-icon>\n Active\n </span>\n } @else {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-700\">\n <cide-ele-icon variant=\"red\" size=\"xs\" class=\"tw-mr-1\">cancel</cide-ele-icon>\n Inactive\n </span>\n }\n </div>\n </div>\n\n <!-- Entity Info -->\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n @if (hasDefaultEntity()) {\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-blue-700\">\n <cide-ele-icon variant=\"blue\" size=\"xs\">business</cide-ele-icon>\n <span class=\"tw-font-medium\">{{ getDefaultEntityName() }}</span>\n </div>\n } @else {\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-500\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">business</cide-ele-icon>\n <span class=\"tw-italic\">No entity</span>\n </div>\n }\n\n <span class=\"tw-text-xs tw-text-gray-600 tw-px-2 tw-py-1 tw-bg-gray-100 tw-rounded\">\n {{ getEntityMappingCount() }} mapping(s)\n </span>\n </div>\n </div>\n </div>\n\n <!-- Tab Navigation -->\n <div class=\"tw-p-0 tw-mb-2 tw-border-b tw-border-gray-200\">\n <cide-ele-tab [tabs]=\"userTabs()\" [activeTabId]=\"activeTab()\" size=\"md\" variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n @switch (activeTab()) {\n\n @case ('basic') {\n <!-- User Basic Information Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n\n <!-- Top Section: Form Fields on Left, Profile Photo on Right -->\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-[1fr_200px] tw-gap-6 tw-mb-6\">\n <!-- Left Side: Form Fields -->\n <div class=\"tw-space-y-6\">\n <!-- Name Fields - All in One Row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4\">\n <cide-ele-input id=\"user_firstname\" label=\"First Name *\" formControlName=\"user_firstname\"\n placeholder=\"Enter first name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_middlename\" label=\"Middle Name\" formControlName=\"user_middlename\"\n placeholder=\"Enter middle name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_lastname\" label=\"Last Name *\" formControlName=\"user_lastname\"\n placeholder=\"Enter last name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_fullname\" label=\"Full Name * (Auto-generated)\" formControlName=\"user_fullname\"\n placeholder=\"Auto-generated from name fields or enter manually\" [maxlength]=\"62\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Contact Information - All in One Row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-3 tw-gap-4\">\n <cide-ele-input id=\"user_username\" label=\"Username *\" formControlName=\"user_username\"\n placeholder=\"Enter unique username\" [maxlength]=\"20\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_emailid\" label=\"Email ID *\" formControlName=\"user_emailid\" type=\"email\"\n placeholder=\"Enter valid email address\" [maxlength]=\"320\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_mobileno\" label=\"Mobile Number *\" formControlName=\"user_mobileno\" type=\"tel\"\n placeholder=\"Enter mobile number\" [maxlength]=\"15\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Right Side: Profile Photo Upload -->\n <div class=\"tw-flex tw-items-start tw-justify-center tw-p-0\">\n <cide-ele-file-input \n id=\"user_photo_id_cyfm\" \n formControlName=\"user_photo_id_cyfm\"\n accept=\"image/*\"\n [showPreview]=\"true\"\n [previewBoxMode]=\"true\"\n [showFileName]=\"false\"\n previewWidth=\"180px\"\n previewHeight=\"120px\"\n placeholderText=\"Upload Photo\"\n placeholderIcon=\"cloud_upload\"\n [autoUpload]=\"true\"\n [uploadData]=\"getProfilePhotoUploadData()\"\n (uploadSuccess)=\"onProfilePhotoUploadSuccess($event)\"\n (uploadError)=\"onProfilePhotoUploadError($event)\"\n (uploadProgressChange)=\"onProfilePhotoUploadProgress($event)\">\n </cide-ele-file-input>\n </div>\n </div>\n\n\n\n <!-- Status Control -->\n <div class=\"tw-grid tw-grid-cols-1 tw-mb-4\">\n <div class=\"tw-p-4 tw-bg-blue-50 tw-border tw-border-blue-100 tw-rounded-lg\">\n <label\n class=\"tw-flex tw-flex-col tw-cursor-pointer tw-py-2 tw-bg-transparent tw-border-none tw-rounded-none tw-transition-all tw-duration-200 hover:tw-bg-blue-75\">\n <cide-ele-input type=\"checkbox\" label=\"Active User Status\" formControlName=\"user_isactive\"\n class=\"tw-h-5 tw-accent-blue-500 tw-rounded tw-mb-1\" />\n <span class=\"tw-font-semibold tw-text-gray-700 tw-text-base\"></span>\n <span class=\"tw-text-sm tw-text-gray-600 tw-mt-1 tw-leading-relaxed\">Enable this user account for system\n access and operations</span>\n </label>\n </div>\n </div>\n </div>\n }\n\n @case ('auth') {\n <!-- Authentication Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n <!-- Password Fields -->\n @if (shouldShowPasswordFields()) {\n <div class=\"tw-mb-6\">\n <!-- Password Fields Header for Edit Mode -->\n @if (isEditMode()) {\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800\">Update Password</h6>\n <button type=\"button\"\n class=\"tw-px-3 tw-py-1 tw-bg-gray-100 tw-text-gray-600 tw-border tw-border-gray-300 tw-rounded-md tw-text-xs tw-font-medium hover:tw-bg-gray-200 tw-transition-colors\"\n (click)=\"cancelPasswordUpdate()\">\n Cancel Password Update\n </button>\n </div>\n }\n\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 md:tw-grid-cols-1 tw-gap-6\">\n <cide-ele-input id=\"user_password\" [label]=\"getPasswordFieldLabel()\" formControlName=\"user_password\"\n type=\"password\" placeholder=\"Enter secure password (min 8 characters)\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_confirm_password\" [label]=\"getPasswordConfirmLabel()\"\n formControlName=\"user_confirm_password\" type=\"password\" placeholder=\"Confirm your password\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Password Update Option for Edit Mode -->\n @if (isEditMode() && !shouldShowPasswordFields()) {\n <div class=\"tw-mb-6\">\n <div class=\"tw-p-4 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-blue-800 tw-mb-2\">Password Update</h6>\n <p class=\"tw-text-sm tw-text-blue-600 tw-mb-3\">Current password will be kept. Click below to change\n password.</p>\n\n @if (hasPasswordInput()) {\n <div\n class=\"tw-mb-3 tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded tw-text-sm tw-text-yellow-700\">\n <cide-ele-icon variant=\"yellow\" size=\"xs\" class=\"tw-mr-1\">warning</cide-ele-icon>\n Password fields contain text. Click \"Change Password\" to manage existing input.\n </div>\n }\n\n <button type=\"button\"\n class=\"tw-px-4 tw-py-2 tw-bg-blue-100 tw-text-blue-700 tw-border tw-border-blue-300 tw-rounded-md tw-text-sm tw-font-medium hover:tw-bg-blue-200 tw-transition-colors\"\n (click)=\"triggerPasswordUpdate()\">\n @if (hasPasswordInput()) {\n Manage Password Fields\n } @else {\n Change Password\n }\n </button>\n </div>\n </div>\n }\n\n <!-- Password Options -->\n <div class=\"tw-grid tw-grid-cols-1 tw-gap-6 tw-mb-6\">\n <div class=\"tw-p-4 tw-bg-yellow-50 tw-border tw-border-yellow-100 tw-rounded-lg\">\n <label\n class=\"tw-flex tw-flex-col tw-gap-2 tw-cursor-pointer tw-py-2 tw-bg-transparent tw-border-none tw-rounded-none tw-transition-all tw-duration-200\">\n <cide-ele-input type=\"checkbox\" label=\"Force Password Change on Login\"\n formControlName=\"user_passwordchangeonlogin\" class=\"tw-h-5 tw-accent-yellow-500 tw-rounded tw-mb-1\" />\n <span class=\"tw-text-sm tw-text-gray-600 tw-mt-1 tw-leading-relaxed\">User will be required to change\n password on next login</span>\n </label>\n </div>\n </div>\n\n </div>\n }\n\n @case ('roles') {\n <!-- Entity, Roles & Permissions Mapping Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n\n\n\n <!-- Important Note -->\n <div class=\"tw-bg-amber-50 tw-border tw-border-amber-200 tw-rounded-lg tw-p-4 tw-mb-6\">\n <div class=\"tw-flex tw-items-start tw-gap-3\">\n <cide-ele-icon variant=\"amber\" size=\"lg\">info</cide-ele-icon>\n <div class=\"tw-flex-1\">\n <h4 class=\"tw-text-sm tw-font-semibold tw-text-amber-800 tw-mb-1\">Entity-Role Based Access</h4>\n <p class=\"tw-text-sm tw-text-amber-700 tw-mb-2\">User access is completely managed through entity-role\n mappings below. At least one entity mapping is required for user access.</p>\n @if (hasDefaultEntity()) {\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mt-2 tw-p-2 tw-bg-amber-100 tw-rounded\">\n <cide-ele-icon variant=\"amber\" size=\"sm\">star</cide-ele-icon>\n <span class=\"tw-text-sm tw-text-amber-800\">\n <strong>Default Entity:</strong> {{ getDefaultEntityName() }}\n </span>\n </div>\n } @else {\n <div class=\"tw-text-sm tw-text-amber-600 tw-mt-2 tw-italic\">\n \u26A0\uFE0F No default entity selected. Please set one entity as default.\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Entity-Role Mapping Section -->\n <div class=\"tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg tw-p-6 tw-mb-6\">\n <div class=\"tw-flex tw-text-center tw-justify-between tw-items-center tw-mb-4\">\n <div>\n <h4 class=\"tw-text-sm tw-text-left tw-font-semibold tw-text-blue-900 tw-mb-1\">Entity-Role Mapping</h4>\n <p class=\"tw-text-sm tw-text-blue-700\">Map user to entities with specific roles and permissions</p>\n </div>\n <div class=\"tw-flex tw-flex-col tw-items-end\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addEntityMapping()\" leftIcon=\"add\"\n [disabled]=\"isAllEntitiesMapped()\">\n Add Entity Mapping\n </button>\n \n @if (isAllEntitiesMapped()) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-md tw-max-w-xs\">\n <p class=\"tw-text-xs tw-text-blue-700\">\n <cide-ele-icon variant=\"info\" size=\"xs\" class=\"tw-mr-1\">info</cide-ele-icon>\n All available entities are already mapped.\n </p>\n </div>\n }\n </div>\n </div>\n\n <div formArrayName=\"core_entity_mapping\">\n @for (mapping of entityMappings(); track $index; let i = $index) {\n <div class=\"tw-bg-white tw-border tw-border-blue-200 tw-rounded-xl tw-mb-6 tw-overflow-hidden tw-shadow-sm\"\n [formGroupName]=\"i\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-blue-100 tw-px-6 tw-py-3 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <h5 class=\"tw-m-0 tw-text-blue-800 tw-text-sm tw-font-semibold\">Entity Mapping {{ i + 1 }}</h5>\n @if (mapping.syenm_isdefault) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n <cide-ele-icon variant=\"green\" size=\"xs\" class=\"tw-mr-1\">star</cide-ele-icon>\n Default\n </span>\n }\n </div>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeEntityMapping(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n\n <div class=\"tw-p-6\">\n <!-- Entity and Role Selection -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <div>\n <cide-ele-select label=\"Entity *\" [options]=\"getFilteredEntityOptions(i)\" formControlName=\"syenm_entity_id_syen\"\n valueKey=\"_id\" labelKey=\"syen_name\" placeholder=\"Select entity\" size=\"md\"\n (change)=\"onEntityChange(i, $event)\">\n </cide-ele-select>\n \n @if (isAllEntitiesSelected(i)) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded-md\">\n <p class=\"tw-text-xs tw-text-yellow-700\">\n <cide-ele-icon variant=\"warning\" size=\"xs\" class=\"tw-mr-1\">info</cide-ele-icon>\n All entities are already mapped. Remove another mapping to add this one.\n </p>\n </div>\n }\n </div>\n <cide-ele-select label=\"Role for this Entity\" [options]=\"getRoleOptionsForEntity(i)\"\n formControlName=\"syenm_role_id_syusrol\" valueKey=\"_id\" labelKey=\"syusrol_role_name\" placeholder=\"Select role for this entity\" size=\"md\"\n (change)=\"onRoleChange(i, $event)\">\n </cide-ele-select>\n </div>\n\n <!-- Role Permissions Grid -->\n @if (selectedEntityIndex() === i && selectedRoleId()) {\n <div class=\"tw-mb-6 tw-border tw-border-gray-200 tw-rounded-lg tw-bg-gray-50\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-white tw-rounded-t-lg\">\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">security</cide-ele-icon>\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800 tw-m-0\">Role Permissions Preview</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">(Read-only view of selected role permissions)</span>\n </div>\n </div>\n \n <div class=\"tw-p-4\">\n @if (loading()) {\n <div class=\"tw-flex tw-items-center tw-justify-center tw-py-8\">\n <div class=\"tw-animate-spin tw-rounded-full tw-h-8 tw-w-8 tw-border-b-2 tw-border-blue-600\"></div>\n <span class=\"tw-ml-2 tw-text-gray-600\">Loading role permissions...</span>\n </div>\n } @else if (error()) {\n <div class=\"tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md\">\n <div class=\"tw-flex tw-items-start\">\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\n <div class=\"tw-ml-3\">\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\n </div>\n </div>\n </div>\n } @else {\n <cide-ele-data-grid \n [config]=\"rolePermissionsGridConfig()\" \n [templateRenderers]=\"templateRenderers\"\n (gridEvent)=\"onRolePermissionsGridEvent($event)\"\n class=\"tw-h-96 tw-w-full\">\n </cide-ele-data-grid>\n }\n </div>\n </div>\n }\n\n <!-- Entity-Specific Details -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Department for this Entity\" [options]=\"getDepartmentOptionsForEntity(i)\"\n formControlName=\"syenm_department_id_sydept\" (change)=\"onDepartmentChange($event)\" valueKey=\"_id\" labelKey=\"sydept_name\" placeholder=\"Select department\" size=\"md\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Designation for this Entity\" [options]=\"getDesignationOptionsForEntity(i)\" valueKey=\"_id\" labelKey=\"sydsg_name\"\n formControlName=\"syenm_designation_id_sydsg\" placeholder=\"Select designation\" size=\"md\">\n </cide-ele-select>\n </div>\n\n <!-- Active Period for Entity Mapping -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Active From *\" [id]=\"'syenm_activefrom['+i+']'\"\n formControlName=\"syenm_activefrom\" type=\"date\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Active Until\" [id]=\"'syenm_activeupto['+i+']'\"\n formControlName=\"syenm_activeupto\" type=\"date\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Mapping Settings -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-6 tw-mb-6\">\n <div class=\"tw-p-3 tw-bg-green-50 tw-border tw-border-green-200 tw-rounded-lg\">\n <cide-ele-input type=\"checkbox\" label=\"Default Entity\" formControlName=\"syenm_isdefault\"\n (change)=\"onDefaultEntityChange(i, $event)\" class=\"tw-h-5 tw-accent-green-500\" />\n <span class=\"tw-text-xs tw-text-green-600 tw-block tw-mt-1\">Set as user's default entity (only one\n allowed)</span>\n </div>\n\n <div class=\"tw-p-3 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg\">\n <cide-ele-input type=\"checkbox\" label=\"Active Mapping\" formControlName=\"syenm_isactive\"\n class=\"tw-h-5 tw-accent-blue-500\" />\n <span class=\"tw-text-xs tw-text-blue-600 tw-block tw-mt-1\">Enable this entity mapping</span>\n </div>\n </div>\n\n <!-- Menu Rights Grid for this Entity-Role -->\n <div class=\"tw-border-t tw-border-gray-200 tw-pt-4\">\n <div class=\"tw-flex tw-justify-between tw-items-center tw-mb-4\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800\">Menu Rights & Permissions</h6>\n <div class=\"tw-flex tw-gap-2\">\n <button cideEleButton variant=\"secondary\" size=\"sm\" type=\"button\" (click)=\"refreshMenuRights(i)\"\n leftIcon=\"refresh\">\n Refresh Rights\n </button>\n </div>\n </div>\n\n @if (getMenuRightsForMapping(i).length > 0) {\n <!-- Menu Rights Tree Grid -->\n <div class=\"tw-border tw-border-gray-200 tw-rounded-lg tw-bg-white\">\n <div class=\"tw-px-4 tw-py-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-rounded-t-lg\">\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-5 tw-h-5\">security</cide-ele-icon>\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800 tw-m-0\">Menu Rights & Permissions</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">(Editable permissions for this entity-role mapping)</span>\n </div>\n </div>\n \n <div class=\"tw-p-4\">\n <cide-ele-data-grid \n [config]=\"getMenuRightsGridConfig(i)\" \n [templateRenderers]=\"getMenuRightsTemplateRenderers(i)\"\n (gridEvent)=\"onMenuRightsGridEvent($event, i)\"\n class=\"tw-h-96 tw-w-full\">\n </cide-ele-data-grid>\n </div>\n </div>\n\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-bg-gray-50 tw-border tw-border-gray-200 tw-rounded-lg\">\n <div class=\"tw-text-gray-400 tw-mb-3\">\n <cide-ele-icon variant=\"gray\" size=\"lg\">menu</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-600 tw-mb-2\">No Menu Rights Available</h6>\n <p class=\"tw-text-xs tw-text-gray-500 tw-mb-3 tw-text-center\">Select both entity and role to load\n menu rights for this mapping.</p>\n @if (mapping.syenm_entity_id_syen?._id && mapping.syenm_role_id_syusrol) {\n <button cideEleButton variant=\"primary\" size=\"sm\" type=\"button\" (click)=\"loadMenuRights(i)\"\n leftIcon=\"refresh\">\n Load Menu Rights\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (entityMappings().length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-bg-white tw-border tw-border-blue-200 tw-rounded-lg\">\n <div class=\"tw-text-blue-400 tw-mb-3\">\n <cide-ele-icon variant=\"blue\" size=\"lg\">business</cide-ele-icon>\n </div>\n <h4 class=\"tw-text-sm tw-font-medium tw-text-blue-800 tw-mb-2\">No Entity Mappings</h4>\n <p class=\"tw-text-blue-600 tw-mb-4 tw-text-center\">Add entity mappings to assign specific roles and\n permissions for different entities.</p>\n <button class=\"tw-mx-auto\" cideEleButton variant=\"primary\" size=\"md\" type=\"button\"\n (click)=\"addEntityMapping()\" leftIcon=\"add\">\n Add First Entity Mapping\n </button>\n </div>\n }\n </div>\n\n\n </div>\n }\n\n @case ('addresses') {\n <!-- Contact Addresses Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n <div class=\"tw-flex tw-justify-end\">\n <div class=\"tw-flex tw-justify-between tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addContactAddress()\"\n leftIcon=\"add\">\n Add New Address\n </button>\n </div>\n </div>\n\n <div formArrayName=\"core_user_contact_addresses\">\n @for (address of contactAddresses(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-6 tw-py-1 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">Address {{ i + 1 }}</h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeContactAddress(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-6\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Address Type\" [options]=\"addressTypeOptions()\" id=\"sycad_address_type_id_sygms\"\n formControlName=\"sycad_address_type_id_sygms\" placeholder=\"Select address type\" size=\"md\"\n valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Contact Person Name\" formControlName=\"sycad_contact_person_name\"\n placeholder=\"Enter contact person name\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 tw-mb-6\">\n <cide-ele-textarea label=\"Complete Address\" formControlName=\"sycad_contact_address\"\n placeholder=\"Enter complete address with area, city, and landmarks\" [rows]=\"3\" size=\"md\">\n </cide-ele-textarea>\n </div>\n\n <!-- Postal Code & City -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select \n label=\"Postal Code\"\n [options]=\"addressPostalCodes()[i] || []\" \n formControlName=\"sycad_contact_pin_sypin\"\n placeholder=\"Select postal code\"\n [searchable]=\"true\"\n [loading]=\"addressPostalCodesLoading()[i] || false\"\n (searchChange)=\"onPostalCodeSearch($event, i)\"\n (change)=\"onPostalCodeSelection($event, i)\"\n size=\"md\">\n </cide-ele-select>\n \n <cide-ele-input \n label=\"City\" \n formControlName=\"sycad_contact_city_sypin\"\n placeholder=\"Enter city\"\n size=\"md\">\n </cide-ele-input>\n </div>\n \n <!-- State & Country -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input \n label=\"State\" \n formControlName=\"sycad_contact_state_sypin\"\n placeholder=\"Enter state\"\n size=\"md\">\n </cide-ele-input>\n\n <cide-ele-select \n label=\"Country\" \n [options]=\"addressCountries()[i] || []\" \n formControlName=\"sycad_contact_country_syctr\"\n placeholder=\"Select country\"\n valueKey=\"_id\"\n labelKey=\"syctr_country_iso_name\"\n [searchable]=\"true\"\n (searchChange)=\"onCountrySearch($event, i)\"\n [loading]=\"addressCountriesLoading()[i] || false\"\n size=\"md\">\n </cide-ele-select>\n </div>\n\n <!-- Phone Numbers -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input \n label=\"Primary Phone\" \n formControlName=\"sycad_contact_phone\"\n type=\"tel\"\n placeholder=\"Enter primary phone number\"\n size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Alternate Phone\" \n formControlName=\"sycad_contact_phone_alt\"\n type=\"tel\"\n placeholder=\"Enter alternate phone number\"\n size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Fax & Email -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input \n label=\"Fax Number\" \n formControlName=\"sycad_contact_fax\"\n placeholder=\"Enter fax number\"\n size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input \n label=\"Primary Email\" \n formControlName=\"sycad_contact_email\"\n type=\"email\"\n placeholder=\"Enter primary email address\"\n size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Alternate Email -->\n <div class=\"tw-grid tw-grid-cols-1 tw-mb-6\">\n <cide-ele-input \n label=\"Alternate Email\" \n formControlName=\"sycad_contact_email_alt\"\n type=\"email\"\n placeholder=\"Enter alternate email address\"\n size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @case ('documents') {\n <!-- Documents Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n <div class=\"tw-flex tw-justify-end tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addDocument()\" leftIcon=\"add\">\n Add Document\n </button>\n </div>\n\n <div formArrayName=\"core_user_documents\">\n @for (doc of documents(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-6 tw-py-1 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">Document {{ i + 1 }}</h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeDocument(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-6\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Document Type\" [options]=\"documentTypeOptions()\"\n formControlName=\"syusd_document_type_id_sygms\"\n placeholder=\"Select document type\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Document Number\" formControlName=\"syusd_doc_number\"\n placeholder=\"Enter document number\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Name as per Document\"\n formControlName=\"syusd_doc_name_as_per_doc\"\n placeholder=\"Enter name exactly as shown on document\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-select label=\"Photo Group\" [options]=\"photoGroupOptions()\"\n formControlName=\"syusd_photo_group_id_cyfm\"\n placeholder=\"Select photo group\" size=\"md\" valueKey=\"_id\" labelKey=\"cyfm_name\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Issue Date\" formControlName=\"syusd_doc_issue_date\"\n [id]=\"'syusd_doc_issue_date['+i+']'\" type=\"date\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Expiry Date\" formControlName=\"syusd_doc_expiry_date\"\n [id]=\"'syusd_doc_expiry_date['+i+']'\" type=\"date\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\n <cide-ele-select label=\"Document Verification Status\" [options]=\"documentVerificationStatusOptions()\"\n formControlName=\"syusd_doc_verification_status_id_sygms\"\n placeholder=\"Select verification status\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Document KYC Status\" [options]=\"documentKycStatusOptions()\"\n formControlName=\"syusd_doc_kyc_status_id_sygms\"\n placeholder=\"Select KYC status\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @case ('family') {\n <!-- Family Details Section -->\n <div class=\"tw-py-2 tw-border-b-0 tw-mb-2\">\n <div class=\"tw-flex tw-justify-end tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addFamilyDetail()\" leftIcon=\"add\">\n Add Family Member\n </button>\n </div>\n\n <div formArrayName=\"core_user_family_details\">\n @for (family of familyDetails(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-6 tw-py-1 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">Family Member {{ i + 1 }}\n </h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeFamilyDetail(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-6\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Family Member Name\"\n formControlName=\"syfdl_family_member_name\"\n placeholder=\"Enter family member full name\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-select \n label=\"Family Member User\"\n [options]=\"userOptions(i)\"\n formControlName=\"syfdl_family_member_id_user\"\n placeholder=\"Select family member user\" \n size=\"md\" \n valueKey=\"_id\" \n labelKey=\"user_fullname\"\n [searchable]=\"true\"\n [loading]=\"userSearchLoading()[i] || false\"\n (searchChange)=\"onUserSearchChange($event, i)\"\n (change)=\"onUserSelectionChange($event, i)\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Relationship\" [options]=\"relationshipOptions()\"\n formControlName=\"syfdl_relationship_id_sygms\"\n placeholder=\"Select relationship\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Blood Group\" [options]=\"bloodGroupOptions()\"\n formControlName=\"syfdl_blood_group_sygms\"\n placeholder=\"Select blood group\" size=\"md\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Date of Birth\"\n formControlName=\"syfdl_family_member_dob\" type=\"date\" size=\"md\"\n [id]=\"'syfdl_family_member_dob['+i+']'\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Contact Phone\"\n formControlName=\"syfdl_contact_phone\"\n type=\"tel\" placeholder=\"Enter contact phone\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Contact Email\" formControlName=\"syfdl_contact_email\"\n type=\"email\" placeholder=\"Enter contact email\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Contact Email ID\" formControlName=\"syfdl_contact_email_id\"\n type=\"email\" placeholder=\"Enter contact email ID\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\n <cide-ele-input label=\"Contact Number\" formControlName=\"syfdl_contact_number\"\n type=\"tel\" placeholder=\"Enter contact number\" size=\"md\">\n </cide-ele-input>\n\n <div class=\"tw-flex tw-items-center tw-pt-6\">\n <cide-ele-input \n formControlName=\"syfdl_isactive\"\n type=\"checkbox\"\n label=\"Active\"\n size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Form Actions -->\n <div\n class=\"tw-flex tw-justify-end tw-gap-4 tw-py-2 tw-bg-white tw-border-t tw-border-gray-200 tw-sticky tw-bottom-0 tw-z-10\">\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n\n <button cideEleButton type=\"submit\" variant=\"primary\" [disabled]=\"loading() || userMasterForm.invalid\"\n [loading]=\"loading()\" leftIcon=\"save\">\n Save User Master\n </button>\n </div>\n </form>\n</div>\n\n<!-- Template Renderers for Role Permissions Grid -->\n<ng-template #menuDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-items-center tw-space-x-3 tw-min-w-0\">\n <!-- Menu Icon -->\n <div class=\"tw-flex-shrink-0\">\n @if (row.syme_type === 'module') {\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">folder</cide-ele-icon>\n } @else if (row.syme_type === 'section') {\n <cide-ele-icon class=\"tw-text-green-600 tw-w-4 tw-h-4\">folder_open</cide-ele-icon>\n } @else if (row.syme_type === 'menu') {\n <cide-ele-icon class=\"tw-text-purple-600 tw-w-4 tw-h-4\">menu</cide-ele-icon>\n } @else {\n <cide-ele-icon class=\"tw-text-gray-600 tw-w-4 tw-h-4\">description</cide-ele-icon>\n }\n </div>\n \n <!-- Menu Details -->\n <div class=\"tw-ml-3 tw-min-w-0 tw-flex-1\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-text-xs tw-font-medium tw-text-gray-900 tw-truncate\" \n [title]=\"row.syme_title\">\n {{ row.syme_title || row.menu?.syme_title || row.menu?.syme_menu_name || 'Untitled' }}\n </div>\n <!-- Green pill indicator for parent menus with child permissions -->\n @if (row.syme_type === 'module' || row.syme_type === 'section') {\n @if (hasChildMenusWithPermissions(row._id)) {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800 tw-whitespace-nowrap\">\n Assigned\n </span>\n }\n }\n </div>\n @if (row.permission?.sygms_name) {\n <div class=\"tw-text-xs tw-text-blue-500 tw-truncate\" \n [title]=\"row.permission?.sygms_name\">\n {{ row.permission?.sygms_name }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<!-- Menu Type Renderer Template -->\n<ng-template #menuTypeRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-items-center tw-justify-center\">\n @if (row.syme_type === 'module') {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-blue-100 tw-text-blue-800\">\n Module\n </span>\n } @else if (row.syme_type === 'section') {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n Section\n </span>\n } @else if (row.syme_type === 'menu') {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-purple-100 tw-text-purple-800\">\n Menu\n </span>\n } @else {\n <span class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-gray-100 tw-text-gray-800\">\n {{ row.syme_type || 'Unknown' }}\n </span>\n }\n </div>\n</ng-template>\n\n<!-- Permissions Checkbox Renderer Template -->\n<ng-template #permissionsCheckboxRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n @if (row.syme_type === 'menu' && row?.syme_permissions_id_sygms && row?.syme_permissions_id_sygms.length > 0) {\n @for (permissionId of row?.syme_permissions_id_sygms || []; track permissionId) {\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"isPermissionSelected(row._id, permissionId)\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-blue-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">\n {{ getPermissionById(permissionId)?.sygms_name || 'Unknown' }}\n </label>\n </div>\n </div>\n }\n } @else {\n <!-- Show green checkmark for parent menus with child permissions -->\n @if (row.syme_type === 'module' || row.syme_type === 'section' || row.syme_type === 'title') {\n @if (hasChildMenusWithPermissions(row._id)) {\n <div class=\"tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-bg-green-100 tw-rounded-full\">\n <cide-ele-icon \n class=\"tw-text-green-600\" \n size=\"xs\">\n check\n </cide-ele-icon>\n </div>\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">N/A</span>\n }\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">N/A</span>\n }\n }\n </div>\n</ng-template>\n\n<!-- Menu Rights Permissions Renderer Template -->\n<ng-template #menuRightsPermissionsRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n <!-- Role Rights Display -->\n @if (row.role_rights && row.role_rights.length > 0) {\n <div class=\"tw-mb-2\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Role Rights:</div>\n <div class=\"tw-flex tw-flex-wrap tw-gap-1\">\n @for (right of row.role_rights; track $index) {\n <span class=\"tw-inline-block tw-px-2 tw-py-1 tw-text-xs tw-bg-blue-100 tw-text-blue-800 tw-rounded\">\n {{ right }}\n </span>\n }\n </div>\n </div>\n }\n \n <!-- Individual Permission Controls -->\n <div class=\"tw-grid tw-grid-cols-2 tw-gap-2 tw-w-full\">\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"row.create\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-green-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-green-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">Create</label>\n </div>\n \n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"row.read\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-blue-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">Read</label>\n </div>\n \n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"row.update\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-yellow-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-yellow-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">Update</label>\n </div>\n \n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input \n type=\"checkbox\"\n [checked]=\"row.delete\"\n [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-red-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-red-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">Delete</label>\n </div>\n </div>\n \n <!-- Exception Indicator -->\n @if (row.hasException) {\n <div class=\"tw-mt-2\">\n <span class=\"tw-inline-block tw-px-2 tw-py-1 tw-text-xs tw-bg-yellow-100 tw-text-yellow-800 tw-rounded\">\n Override\n </span>\n </div>\n } @else {\n <div class=\"tw-mt-2\">\n <span class=\"tw-text-xs tw-text-gray-400\">Default</span>\n </div>\n }\n </div>\n</ng-template>" }]
|
|
14179
|
+
CideEleDataGridComponent,
|
|
14180
|
+
CideLytFloatingUploadTriggerDirective
|
|
14181
|
+
], template: "<!-- \n ENTERPRISE USER MASTER FORM\n \n Enterprise-Level Styling with Tailwind CSS\n Features: Responsive grids, proper typography, enhanced user experience\n-->\n\n<div class=\"tw-w-full tw-h-full tw-p-1 tw-pt-2\">\n <form class=\"tw-max-w-7xl tw-mx-auto tw-bg-transparent\" [formGroup]=\"userMasterForm\" [class.tw-opacity-60]=\"loading()\"\n (ngSubmit)=\"onSubmit()\">\n\n <!-- Success/Error Messages -->\n @if (success()) {\n <div class=\"tw-mb-4 tw-p-4 tw-bg-green-50 tw-border tw-border-green-200 tw-rounded-md tw-shadow-sm\">\n <div class=\"tw-flex tw-items-start\">\n <cide-ele-icon name=\"check_circle\" class=\"tw-text-green-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\n <div class=\"tw-ml-3\">\n <h3 class=\"tw-text-sm tw-font-medium tw-text-green-800 tw-m-0\">Success</h3>\n <p class=\"tw-text-sm tw-text-green-700 tw-mt-1 tw-m-0\">{{ success() }}</p>\n </div>\n <button type=\"button\" (click)=\"success.set(null)\" class=\"tw-ml-auto tw-text-green-400 hover:tw-text-green-600\">\n <cide-ele-icon name=\"close\" class=\"tw-w-4 tw-h-4\"></cide-ele-icon>\n </button>\n </div>\n </div>\n }\n @if (error()) {\n <div class=\"tw-mb-4 tw-p-4 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-md tw-shadow-sm\">\n <div class=\"tw-flex tw-items-start\">\n <cide-ele-icon name=\"error\" class=\"tw-text-red-400 tw-w-5 tw-h-5 tw-mt-0.5 tw-flex-shrink-0\"></cide-ele-icon>\n <div class=\"tw-ml-3\">\n <h3 class=\"tw-text-sm tw-font-medium tw-text-red-800 tw-m-0\">Error</h3>\n <p class=\"tw-text-sm tw-text-red-700 tw-mt-1 tw-m-0\">{{ error() }}</p>\n </div>\n <button type=\"button\" (click)=\"error.set(null)\" class=\"tw-ml-auto tw-text-red-400 hover:tw-text-red-600\">\n <cide-ele-icon name=\"close\" class=\"tw-w-4 tw-h-4\"></cide-ele-icon>\n </button>\n </div>\n </div>\n }\n\n <!-- User Context Header -->\n <div\n class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-indigo-50 tw-border tw-border-blue-200 tw-rounded-md tw-p-1 tw-mb-2 tw-shadow-sm\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-flex-wrap tw-gap-2\">\n <!-- User Basic Info Display -->\n <div class=\"tw-flex tw-items-center tw-gap-3 tw-flex-wrap\">\n <!-- Profile Photo Preview -->\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div\n class=\"tw-w-8 tw-h-8 tw-rounded-full tw-bg-blue-100 tw-border tw-border-blue-200 tw-flex tw-items-center tw-justify-center tw-overflow-hidden\">\n @if (userMasterForm.get('user_photo_id_cyfm')?.value) {\n <img cideEleFileImage [fileId]=\"userMasterForm.get('user_photo_id_cyfm')?.value\"\n [altText]=\"'Profile Photo'\" class=\"tw-w-full tw-h-full tw-object-cover\">\n } @else {\n <cide-ele-icon name=\"person\" class=\"tw-w-5 tw-h-5 tw-text-blue-600\">\n </cide-ele-icon>\n }\n </div>\n <div class=\"tw-flex tw-flex-col\">\n <span class=\"tw-text-xs tw-font-medium tw-text-blue-900\">\n {{ getUserFullName() || 'New User' }}\n </span>\n <span class=\"tw-text-xs tw-text-blue-600\">\n {{ getUserUsername() || 'Username not set' }}\n </span>\n </div>\n </div>\n\n <!-- Contact Info -->\n <div class=\"tw-flex tw-items-center tw-gap-3\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-700\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">email</cide-ele-icon>\n <span>{{ getUserEmail() || 'Email not set' }}</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-700\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">phone</cide-ele-icon>\n <span>{{ getUserMobile() || 'Mobile not set' }}</span>\n </div>\n </div>\n\n <!-- Active Status -->\n <div class=\"tw-flex tw-items-center tw-gap-1\">\n @if (getUserActiveStatus()) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-700\">\n <cide-ele-icon variant=\"green\" size=\"xs\" class=\"tw-mr-1\">check_circle</cide-ele-icon>\n Active\n </span>\n } @else {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-700\">\n <cide-ele-icon variant=\"red\" size=\"xs\" class=\"tw-mr-1\">cancel</cide-ele-icon>\n Inactive\n </span>\n }\n </div>\n </div>\n\n <!-- Entity Info -->\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n @if (hasDefaultEntity()) {\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-blue-700\">\n <cide-ele-icon variant=\"blue\" size=\"xs\">business</cide-ele-icon>\n <span class=\"tw-font-medium\">{{ getDefaultEntityName() }}</span>\n </div>\n } @else {\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-xs tw-text-gray-500\">\n <cide-ele-icon variant=\"gray\" size=\"xs\">business</cide-ele-icon>\n <span class=\"tw-italic\">No entity</span>\n </div>\n }\n\n <span class=\"tw-text-xs tw-text-gray-600 tw-px-2 tw-py-1 tw-bg-gray-100 tw-rounded\">\n {{ getEntityMappingCount() }} mapping(s)\n </span>\n </div>\n </div>\n </div>\n\n <!-- Tab Navigation -->\n <div class=\"tw-p-0 tw-mb-2 tw-border-b tw-border-gray-200\">\n <cide-ele-tab [tabs]=\"userTabs()\" [activeTabId]=\"activeTab()\" size=\"md\" variant=\"default\"\n (tabChange)=\"onTabChange($event)\">\n </cide-ele-tab>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tw-transition-opacity tw-duration-300\" [class.tw-opacity-60]=\"loading()\">\n @switch (activeTab()) {\n\n @case ('basic') {\n <!-- User Basic Information Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n\n <!-- Top Section: Form Fields on Left, Profile Photo on Right -->\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-[1fr_200px] tw-gap-4 tw-mb-4\">\n <!-- Left Side: Form Fields -->\n <div class=\"tw-space-y-4\">\n <!-- Name Fields - All in One Row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4\">\n <cide-ele-input id=\"user_firstname\" label=\"First Name *\" formControlName=\"user_firstname\"\n placeholder=\"Enter first name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_middlename\" label=\"Middle Name\" formControlName=\"user_middlename\"\n placeholder=\"Enter middle name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_lastname\" label=\"Last Name *\" formControlName=\"user_lastname\"\n placeholder=\"Enter last name\" [maxlength]=\"20\" size=\"md\" (ngModelChange)=\"onNameFieldChange()\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_fullname\" label=\"Full Name * (Auto-generated)\" formControlName=\"user_fullname\"\n placeholder=\"Auto-generated from name fields or enter manually\" [maxlength]=\"62\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Contact Information - All in One Row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-3 tw-gap-4\">\n <cide-ele-input id=\"user_username\" label=\"Username *\" formControlName=\"user_username\"\n placeholder=\"Enter unique username\" [maxlength]=\"20\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_emailid\" label=\"Email ID *\" formControlName=\"user_emailid\" type=\"email\"\n placeholder=\"Enter valid email address\" [maxlength]=\"320\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_mobileno\" label=\"Mobile Number *\" formControlName=\"user_mobileno\" type=\"tel\"\n placeholder=\"Enter mobile number\" [maxlength]=\"15\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n\n <!-- Right Side: Profile Photo Upload -->\n <div class=\"tw-flex tw-items-start tw-justify-center tw-p-0\">\n <cide-ele-file-input id=\"user_photo_id_cyfm\" formControlName=\"user_photo_id_cyfm\" accept=\"image/*\"\n [showPreview]=\"true\" [previewBoxMode]=\"true\" [showFileName]=\"false\" previewWidth=\"180px\"\n previewHeight=\"120px\" placeholderText=\"Upload Photo\" placeholderIcon=\"cloud_upload\" [autoUpload]=\"true\"\n [uploadData]=\"getProfilePhotoUploadData()\" (uploadSuccess)=\"onProfilePhotoUploadSuccess($event)\"\n (uploadError)=\"onProfilePhotoUploadError($event)\"\n (uploadProgressChange)=\"onProfilePhotoUploadProgress($event)\">\n </cide-ele-file-input>\n </div>\n </div>\n\n\n\n <!-- Status Control -->\n <div class=\"tw-grid tw-grid-cols-1 tw-mb-2\">\n <div class=\"tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-100 tw-rounded-lg\">\n <label\n class=\"tw-flex tw-flex-col tw-cursor-pointer tw-py-2 tw-bg-transparent tw-border-none tw-rounded-none tw-transition-all tw-duration-200 hover:tw-bg-blue-75\">\n <cide-ele-input type=\"checkbox\" label=\"Active User Status\" formControlName=\"user_isactive\"\n class=\"tw-h-5 tw-accent-blue-500 tw-rounded tw-mb-1\" />\n <span class=\"tw-font-semibold tw-text-gray-700 tw-text-base\"></span>\n <span class=\"tw-text-sm tw-text-gray-600 tw-mt-1 tw-leading-relaxed\">Enable this user account for system\n access and operations</span>\n </label>\n </div>\n </div>\n </div>\n }\n\n @case ('auth') {\n <!-- Authentication Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n <!-- Password Fields -->\n @if (shouldShowPasswordFields()) {\n <div class=\"tw-mb-4\">\n <!-- Password Fields Header for Edit Mode -->\n @if (isEditMode()) {\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-3\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-800\">Update Password</h6>\n <button type=\"button\"\n class=\"tw-px-3 tw-py-1 tw-bg-gray-100 tw-text-gray-600 tw-border tw-border-gray-300 tw-rounded-md tw-text-xs tw-font-medium hover:tw-bg-gray-200 tw-transition-colors\"\n (click)=\"cancelPasswordUpdate()\">\n Cancel Password Update\n </button>\n </div>\n }\n\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 md:tw-grid-cols-1 tw-gap-6\">\n <cide-ele-input id=\"user_password\" [label]=\"getPasswordFieldLabel()\" formControlName=\"user_password\"\n type=\"password\" placeholder=\"Enter secure password (min 8 characters)\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input id=\"user_confirm_password\" [label]=\"getPasswordConfirmLabel()\"\n formControlName=\"user_confirm_password\" type=\"password\" placeholder=\"Confirm your password\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n }\n\n <!-- Password Update Option for Edit Mode -->\n @if (isEditMode() && !shouldShowPasswordFields()) {\n <div class=\"tw-mb-4\">\n <div class=\"tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-blue-800 tw-mb-2\">Password Update</h6>\n <p class=\"tw-text-sm tw-text-blue-600 tw-mb-3\">Current password will be kept. Click below to change\n password.</p>\n\n @if (hasPasswordInput()) {\n <div\n class=\"tw-mb-3 tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded tw-text-sm tw-text-yellow-700\">\n <cide-ele-icon variant=\"yellow\" size=\"xs\" class=\"tw-mr-1\">warning</cide-ele-icon>\n Password fields contain text. Click \"Change Password\" to manage existing input.\n </div>\n }\n\n <button type=\"button\"\n class=\"tw-px-4 tw-py-2 tw-bg-blue-100 tw-text-blue-700 tw-border tw-border-blue-300 tw-rounded-md tw-text-sm tw-font-medium hover:tw-bg-blue-200 tw-transition-colors\"\n (click)=\"triggerPasswordUpdate()\">\n @if (hasPasswordInput()) {\n Manage Password Fields\n } @else {\n Change Password\n }\n </button>\n </div>\n </div>\n }\n\n <!-- Password Options -->\n <div class=\"tw-grid tw-grid-cols-1 tw-gap-4 tw-mb-4\">\n <div class=\"tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-100 tw-rounded-lg\">\n <label\n class=\"tw-flex tw-flex-col tw-gap-2 tw-cursor-pointer tw-py-2 tw-bg-transparent tw-border-none tw-rounded-none tw-transition-all tw-duration-200\">\n <cide-ele-input type=\"checkbox\" label=\"Force Password Change on Login\"\n formControlName=\"user_passwordchangeonlogin\" class=\"tw-h-5 tw-accent-yellow-500 tw-rounded tw-mb-1\" />\n <span class=\"tw-text-sm tw-text-gray-600 tw-mt-1 tw-leading-relaxed\">User will be required to change\n password on next login</span>\n </label>\n </div>\n </div>\n\n </div>\n }\n\n @case ('roles') {\n <!-- Entity, Roles & Permissions Mapping Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n\n\n\n <!-- Important Note -->\n <div class=\"tw-bg-amber-50 tw-border tw-border-amber-200 tw-rounded-lg tw-p-2 tw-mb-4\">\n <div class=\"tw-flex tw-items-start tw-gap-3\">\n <cide-ele-icon variant=\"amber\" size=\"lg\">info</cide-ele-icon>\n <div class=\"tw-flex-1\">\n <h4 class=\"tw-text-sm tw-font-semibold tw-text-amber-800 tw-mb-1\">Entity-Role Based Access</h4>\n <p class=\"tw-text-sm tw-text-amber-700 tw-mb-2\">User access is completely managed through entity-role\n mappings below. At least one entity mapping is required for user access.</p>\n @if (hasDefaultEntity()) {\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-mt-2 tw-p-2 tw-bg-amber-100 tw-rounded\">\n <cide-ele-icon variant=\"amber\" size=\"sm\">star</cide-ele-icon>\n <span class=\"tw-text-sm tw-text-amber-800\">\n <strong>Default Entity:</strong> {{ getDefaultEntityName() }}\n </span>\n </div>\n } @else {\n <div class=\"tw-text-sm tw-text-amber-600 tw-mt-2 tw-italic\">\n \u26A0\uFE0F No default entity selected. Please set one entity as default.\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Entity-Role Mapping Section -->\n <div class=\"tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg tw-p-3 tw-mb-4\">\n <div class=\"tw-flex tw-text-center tw-justify-between tw-items-center tw-mb-4\">\n <div>\n <h4 class=\"tw-text-sm tw-text-left tw-font-semibold tw-text-blue-900 tw-mb-1\">Entity-Role Mapping</h4>\n <p class=\"tw-text-sm tw-text-blue-700\">Map user to entities with specific roles and permissions</p>\n </div>\n <div class=\"tw-flex tw-flex-col tw-items-end\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addEntityMapping()\"\n leftIcon=\"add\" [disabled]=\"isAllEntitiesMapped()\">\n Add Entity Mapping\n </button>\n\n @if (isAllEntitiesMapped()) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-md tw-max-w-xs\">\n <p class=\"tw-text-xs tw-text-blue-700\">\n <cide-ele-icon variant=\"info\" size=\"xs\" class=\"tw-mr-1\">info</cide-ele-icon>\n All available entities are already mapped.\n </p>\n </div>\n }\n </div>\n </div>\n\n <div formArrayName=\"core_entity_mapping\">\n @for (mapping of entityMappings(); track $index; let i = $index) {\n <div class=\"tw-bg-white tw-border tw-border-blue-200 tw-rounded-xl tw-mb-6 tw-overflow-hidden tw-shadow-sm\"\n [formGroupName]=\"i\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-blue-50 tw-to-blue-100 tw-px-6 tw-py-3 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-blue-200\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <h5 class=\"tw-m-0 tw-text-blue-800 tw-text-sm tw-font-semibold\">Entity Mapping {{ i + 1 }}</h5>\n @if (mapping.syenm_isdefault) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n <cide-ele-icon variant=\"green\" size=\"xs\" class=\"tw-mr-1\">star</cide-ele-icon>\n Default\n </span>\n }\n </div>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeEntityMapping(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n\n <div>\n <!-- Entity and Role Selection -->\n <div class=\"tw-grid tw-px-3 tw-py-1 tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-4 tw-mb-4\">\n <div>\n <cide-ele-select label=\"Entity *\" [options]=\"getFilteredEntityOptions(i)\"\n formControlName=\"syenm_entity_id_syen\" valueKey=\"_id\" labelKey=\"syen_name\"\n placeholder=\"Select entity\" size=\"md\" (change)=\"onEntityChange(i, $event)\">\n </cide-ele-select>\n\n @if (isAllEntitiesSelected(i)) {\n <div class=\"tw-mt-2 tw-p-2 tw-bg-yellow-50 tw-border tw-border-yellow-200 tw-rounded-md\">\n <p class=\"tw-text-xs tw-text-yellow-700\">\n <cide-ele-icon variant=\"warning\" size=\"xs\" class=\"tw-mr-1\">info</cide-ele-icon>\n All entities are already mapped. Remove another mapping to add this one.\n </p>\n </div>\n }\n </div>\n <cide-ele-select label=\"Role for this Entity\" [options]=\"getRoleOptionsForEntity(i)\"\n formControlName=\"syenm_role_id_syusrol\" valueKey=\"_id\" labelKey=\"syusrol_role_name\"\n placeholder=\"Select role for this entity\" size=\"md\" (change)=\"onRoleChange(i, $event)\">\n </cide-ele-select>\n </div>\n\n\n <!-- Entity-Specific Details and Active Period - All in One Row -->\n <div class=\"tw-grid tw-px-3 tw-grid-cols-1 md:tw-grid-cols-2 lg:tw-grid-cols-4 tw-gap-4 tw-mb-4\">\n <cide-ele-select label=\"Department for this Entity\" [options]=\"getDepartmentOptionsForEntity(i)\"\n formControlName=\"syenm_department_id_sydept\" (change)=\"onDepartmentChange($event)\" valueKey=\"_id\"\n labelKey=\"sydept_name\" placeholder=\"Select department\" size=\"md\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Designation for this Entity\" [options]=\"getDesignationOptionsForEntity(i)\"\n valueKey=\"_id\" labelKey=\"sydsg_name\" formControlName=\"syenm_designation_id_sydsg\"\n placeholder=\"Select designation\" size=\"md\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Active From *\" [id]=\"'syenm_activefrom['+i+']'\"\n formControlName=\"syenm_activefrom\" type=\"date\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Active Until\" [id]=\"'syenm_activeupto['+i+']'\"\n formControlName=\"syenm_activeupto\" type=\"date\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <!-- Mapping Settings -->\n <div class=\"tw-grid tw-px-3 tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-4 tw-mb-4\">\n <div class=\"tw-p-2 tw-bg-green-50 tw-border tw-border-green-200 tw-rounded-lg\">\n <cide-ele-input type=\"checkbox\" label=\"Default Entity\" formControlName=\"syenm_isdefault\"\n (change)=\"onDefaultEntityChange(i, $event)\" class=\"tw-h-5 tw-accent-green-500\" />\n <span class=\"tw-text-xs tw-text-green-600 tw-block tw-mt-1\">Set as user's default entity (only one\n allowed)</span>\n </div>\n\n <div class=\"tw-p-2 tw-bg-blue-50 tw-border tw-border-blue-200 tw-rounded-lg\">\n <cide-ele-input type=\"checkbox\" label=\"Active Mapping\" formControlName=\"syenm_isactive\"\n class=\"tw-h-5 tw-accent-blue-500\" />\n <span class=\"tw-text-xs tw-text-blue-600 tw-block tw-mt-1\">Enable this entity mapping</span>\n </div>\n </div>\n\n <!-- Menu Rights Grid for this Entity-Role -->\n <div class=\"tw-border-t tw-border-gray-200\">\n\n @if (getMenuRightsForMapping(i).length > 0) {\n <!-- Menu Rights Tree Grid -->\n\n <cide-ele-data-grid [config]=\"getMenuRightsGridConfig(i)\"\n [templateRenderers]=\"getMenuRightsTemplateRenderers(i)\"\n (gridEvent)=\"onMenuRightsGridEvent($event, i)\" class=\"tw-h-96 tw-w-full\">\n </cide-ele-data-grid>\n\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-bg-gray-50 tw-border tw-border-gray-200 tw-rounded-lg\">\n <div class=\"tw-text-gray-400 tw-mb-3\">\n <cide-ele-icon variant=\"gray\" size=\"lg\">menu</cide-ele-icon>\n </div>\n <h6 class=\"tw-text-sm tw-font-medium tw-text-gray-600 tw-mb-2\">No Menu Rights Available</h6>\n <p class=\"tw-text-xs tw-text-gray-500 tw-mb-3 tw-text-center\">Select both entity and role to\n automatically load\n menu rights for this mapping.</p>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n @if (entityMappings().length === 0) {\n <div class=\"tw-text-center tw-py-8 tw-bg-white tw-border tw-border-blue-200 tw-rounded-lg\">\n <div class=\"tw-text-blue-400 tw-mb-3\">\n <cide-ele-icon variant=\"blue\" size=\"lg\">business</cide-ele-icon>\n </div>\n <h4 class=\"tw-text-sm tw-font-medium tw-text-blue-800 tw-mb-2\">No Entity Mappings</h4>\n <p class=\"tw-text-blue-600 tw-mb-4 tw-text-center\">Add entity mappings to assign specific roles and\n permissions for different entities.</p>\n <button class=\"tw-mx-auto\" cideEleButton variant=\"primary\" size=\"md\" type=\"button\"\n (click)=\"addEntityMapping()\" leftIcon=\"add\">\n Add First Entity Mapping\n </button>\n </div>\n }\n </div>\n\n\n </div>\n }\n\n @case ('addresses') {\n <!-- Contact Addresses Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n <div class=\"tw-flex tw-justify-end\">\n <div class=\"tw-flex tw-justify-between tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addContactAddress()\"\n leftIcon=\"add\">\n Add New Address\n </button>\n </div>\n </div>\n\n <div formArrayName=\"core_user_contact_addresses\">\n @for (address of contactAddresses(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-4 tw-py-2 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <!-- Use address type as header instead of generic \"Address X\" -->\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">\n {{ getAddressTypeLabel(i) || ('Address ' + (i + 1)) }}\n </h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeContactAddress(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-4\">\n <!-- Main Layout: Inputs on Left, Address Textarea on Right -->\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-4 tw-gap-3 tw-mb-3\">\n \n <!-- Left Side: Input Fields (3/4 width) -->\n <div class=\"lg:tw-col-span-3\">\n <!-- Row 1: Address Type, Contact Person -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3 tw-mb-3\">\n <cide-ele-select label=\"Address Type\" [options]=\"addressTypeOptions()\" id=\"sycad_address_type_id_sygms\"\n formControlName=\"sycad_address_type_id_sygms\" placeholder=\"Select type\" size=\"sm\"\n valueKey=\"_id\" labelKey=\"sygms_title\" (change)=\"onAddressTypeChange(i)\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Contact Person\" formControlName=\"sycad_contact_person_name\"\n placeholder=\"Enter contact person\" size=\"sm\">\n </cide-ele-input>\n </div>\n\n <!-- Row 2: Postal Code, City, State, Country -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-4 tw-gap-3\">\n <cide-ele-select label=\"Postal Code\" [options]=\"addressPostalCodes()[i] || []\"\n formControlName=\"sycad_contact_pin_sypin\" placeholder=\"Select postal code\" [searchable]=\"true\"\n [loading]=\"addressPostalCodesLoading()[i] || false\" (searchChange)=\"onPostalCodeSearch($event, i)\"\n (change)=\"onPostalCodeSelection($event, i)\" size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-input label=\"City\" formControlName=\"sycad_contact_city_sypin\" placeholder=\"Enter city\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"State\" formControlName=\"sycad_contact_state_sypin\" placeholder=\"Enter state\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-select label=\"Country\" [options]=\"addressCountries()[i] || []\"\n formControlName=\"sycad_contact_country_syctr\" placeholder=\"Select country\" valueKey=\"_id\"\n labelKey=\"syctr_country_iso_name\" [searchable]=\"true\" (searchChange)=\"onCountrySearch($event, i)\"\n [loading]=\"addressCountriesLoading()[i] || false\" size=\"sm\">\n </cide-ele-select>\n </div>\n </div>\n\n <!-- Right Side: Address Textarea (1/4 width, spans 2 rows) -->\n <div class=\"lg:tw-col-span-1 lg:tw-row-span-2 tw-flex tw-flex-col\">\n <cide-ele-textarea label=\"Complete Address\" formControlName=\"sycad_contact_address\"\n placeholder=\"Enter complete address with area, city, and landmarks\" [rows]=\"4\" size=\"sm\"\n class=\"tw-h-full\">\n </cide-ele-textarea>\n </div>\n </div>\n\n <!-- Contact Details: Primary Phone, Alt Phone, Fax, Primary Email in 4 columns -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-4 tw-gap-3 tw-mb-3\">\n <cide-ele-input label=\"Primary Phone\" formControlName=\"sycad_contact_phone\" type=\"tel\"\n placeholder=\"Primary phone\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Alternate Phone\" formControlName=\"sycad_contact_phone_alt\" type=\"tel\"\n placeholder=\"Alternate phone\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Fax Number\" formControlName=\"sycad_contact_fax\" placeholder=\"Fax number\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Primary Email\" formControlName=\"sycad_contact_email\" type=\"email\"\n placeholder=\"Primary email\" size=\"sm\">\n </cide-ele-input>\n </div>\n\n <!-- Alternate Email in single row -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input label=\"Alternate Email\" formControlName=\"sycad_contact_email_alt\" type=\"email\"\n placeholder=\"Alternate email address\" size=\"sm\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @case ('documents') {\n <!-- Documents Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n <div class=\"tw-flex tw-justify-end tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addDocument()\" leftIcon=\"add\">\n Add Document\n </button>\n </div>\n\n <div formArrayName=\"core_user_documents\">\n @for (doc of documents(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-4 tw-py-2 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">\n {{ getDocumentTypeLabel(i) || ('Document ' + (i + 1)) }}\n </h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeDocument(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-4\">\n <!-- Main Layout: Inputs on Left, File Upload on Right -->\n <div class=\"tw-grid tw-grid-cols-1 lg:tw-grid-cols-3 tw-gap-4\">\n \n <!-- Left Side: Document Information (2/3 width) -->\n <div class=\"lg:tw-col-span-2\">\n <!-- Row 1: Document Type, Document Number, Name as per Document -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-3 tw-mb-3\">\n <cide-ele-select label=\"Document Type\" [options]=\"documentTypeOptions()\"\n formControlName=\"syusd_document_type_id_sygms\" placeholder=\"Select type\" size=\"sm\"\n valueKey=\"_id\" labelKey=\"sygms_title\" (change)=\"onDocumentTypeChange(i)\">\n </cide-ele-select>\n\n <cide-ele-input label=\"Document Number\" formControlName=\"syusd_doc_number\"\n placeholder=\"Document number\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Name as per Document\" formControlName=\"syusd_doc_name_as_per_doc\"\n placeholder=\"Name on document\" size=\"sm\">\n </cide-ele-input>\n </div>\n\n <!-- Row 2: Issue Date, Expiry Date, Photo Group -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-3 tw-gap-3 tw-mb-3\">\n <cide-ele-input label=\"Issue Date\" formControlName=\"syusd_doc_issue_date\"\n [id]=\"'syusd_doc_issue_date['+i+']'\" type=\"date\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Expiry Date\" formControlName=\"syusd_doc_expiry_date\"\n [id]=\"'syusd_doc_expiry_date['+i+']'\" type=\"date\" size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-select label=\"Photo Group\" [options]=\"photoGroupOptions()\"\n formControlName=\"syusd_photo_group_id_cyfm\" placeholder=\"Select group\" size=\"sm\" valueKey=\"_id\"\n labelKey=\"cyfm_name\">\n </cide-ele-select>\n </div>\n\n <!-- Row 3: Verification Status, KYC Status -->\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-select label=\"Verification Status\" [options]=\"documentVerificationStatusOptions()\"\n formControlName=\"syusd_doc_verification_status_id_sygms\" placeholder=\"Select status\"\n size=\"sm\" valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-select label=\"KYC Status\" [options]=\"documentKycStatusOptions()\"\n formControlName=\"syusd_doc_kyc_status_id_sygms\" placeholder=\"Select KYC status\" size=\"sm\"\n valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n </div>\n </div>\n\n <!-- Right Side: File Upload (1/3 width) -->\n <div class=\"lg:tw-col-span-1\">\n <div class=\"tw-bg-gray-50 tw-border tw-border-gray-200 tw-rounded-lg tw-p-3 tw-h-full\">\n <h5 class=\"tw-text-sm tw-font-medium tw-text-gray-700 tw-mb-3 tw-m-0\">Document Files</h5>\n \n <!-- File Upload Input -->\n {{documentsFormArray.at(i).get('syusd_photo_group_id_cyfm')?.value}}\n <cide-ele-file-input\n [id]=\"'document-files-' + i\"\n [multiple]=\"true\"\n formControlName=\"syusd_photo_group_id_cyfm\"\n [accept]=\"'.pdf,.jpg,.jpeg,.png,.doc,.docx'\"\n [autoUpload]=\"true\"\n [uploadData]=\"getDocumentUploadData(i)\"\n (change)=\"onDocumentFilesSelected($event, i)\"\n (uploadSuccess)=\"onDocumentUploadSuccess($event, i)\"\n (uploadError)=\"onDocumentUploadError($event, i)\"\n (uploadProgressChange)=\"onDocumentUploadProgress($event, i)\"\n cideFloatingUploadTrigger\n class=\"tw-mb-3\"\n size=\"sm\">\n <div class=\"tw-text-center tw-py-4\">\n <cide-ele-icon name=\"cloud_upload\" class=\"tw-w-6 tw-h-6 tw-text-gray-400 tw-mx-auto tw-mb-2\"></cide-ele-icon>\n <p class=\"tw-text-xs tw-text-gray-600 tw-m-0\">Upload document files</p>\n <p class=\"tw-text-xs tw-text-gray-400 tw-m-0\">PDF, Images, Word docs</p>\n </div>\n </cide-ele-file-input>\n\n <!-- Upload Status -->\n @if (getDocumentGroupId(i)) {\n <div class=\"tw-space-y-2\">\n <div class=\"tw-flex tw-items-center tw-justify-between tw-mb-2\">\n <h6 class=\"tw-text-xs tw-font-medium tw-text-gray-600 tw-m-0\">Upload Status:</h6>\n <span class=\"tw-text-xs tw-text-green-600 tw-font-medium\">\n \u2705 Files Uploaded\n </span>\n </div>\n <div class=\"tw-bg-green-50 tw-border tw-border-green-200 tw-rounded tw-p-2\">\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-icon name=\"cloud_done\" class=\"tw-w-4 tw-h-4 tw-text-green-500 tw-flex-shrink-0\"></cide-ele-icon>\n <div class=\"tw-flex tw-flex-col tw-flex-1 tw-min-w-0\">\n <span class=\"tw-text-xs tw-text-green-700 tw-font-medium\">Multiple files uploaded successfully</span>\n <span class=\"tw-text-xs tw-text-green-600 tw-font-mono tw-truncate\" [title]=\"'Group ID: ' + getDocumentGroupId(i)\">\n Group ID: {{ getDocumentGroupId(i).substring(0, 12) }}...\n </span>\n </div>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"tw-text-center tw-text-xs tw-text-gray-400 tw-py-2\">\n No files uploaded yet\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @case ('family') {\n <!-- Family Details Section -->\n <div class=\"tw-py-1 tw-border-b-0 tw-mb-1\">\n <div class=\"tw-flex tw-justify-end tw-items-end tw-mb-2 tw-gap-4\">\n <button cideEleButton variant=\"primary\" size=\"md\" type=\"button\" (click)=\"addFamilyDetail()\" leftIcon=\"add\">\n Add Family Member\n </button>\n </div>\n\n <div formArrayName=\"core_user_family_details\">\n @for (family of familyDetails(); track $index; let i = $index) {\n <div [formGroupName]=\"i\"\n class=\"tw-bg-white tw-border tw-border-gray-200 tw-rounded-xl tw-mb-8 tw-overflow-hidden tw-transition-all tw-duration-300 hover:tw-shadow-lg tw-shadow-sm\">\n <div\n class=\"tw-bg-gradient-to-r tw-from-gray-50 tw-to-gray-100 tw-px-6 tw-py-1 tw-flex tw-justify-between tw-items-center tw-border-b tw-border-gray-200\">\n <h4 class=\"tw-m-0 tw-text-gray-700 tw-text-sm tw-font-semibold tw-tracking-tight\">Family Member {{ i + 1\n }}\n </h4>\n <button cideEleButton variant=\"danger\" size=\"sm\" type=\"button\" (click)=\"removeFamilyDetail(i)\"\n leftIcon=\"delete\">\n Remove\n </button>\n </div>\n <div class=\"tw-p-3\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Family Member Name\" formControlName=\"syfdl_family_member_name\"\n placeholder=\"Enter family member full name\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-select label=\"Family Member User\" [options]=\"userOptions(i)\"\n formControlName=\"syfdl_family_member_id_user\" placeholder=\"Select family member user\" size=\"md\"\n valueKey=\"_id\" labelKey=\"user_fullname\" [searchable]=\"true\"\n [loading]=\"userSearchLoading()[i] || false\" (searchChange)=\"onUserSearchChange($event, i)\"\n (change)=\"onUserSelectionChange($event, i)\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-select label=\"Relationship\" [options]=\"relationshipOptions()\"\n formControlName=\"syfdl_relationship_id_sygms\" placeholder=\"Select relationship\" size=\"md\"\n valueKey=\"_id\" labelKey=\"sygms_title\">\n </cide-ele-select>\n\n <cide-ele-select label=\"Blood Group\" [options]=\"bloodGroupOptions()\"\n formControlName=\"syfdl_blood_group_sygms\" placeholder=\"Select blood group\" size=\"md\" valueKey=\"_id\"\n labelKey=\"sygms_title\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Date of Birth\" formControlName=\"syfdl_family_member_dob\" type=\"date\" size=\"md\"\n [id]=\"'syfdl_family_member_dob['+i+']'\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Contact Phone\" formControlName=\"syfdl_contact_phone\" type=\"tel\"\n placeholder=\"Enter contact phone\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6 tw-mb-6\">\n <cide-ele-input label=\"Contact Email\" formControlName=\"syfdl_contact_email\" type=\"email\"\n placeholder=\"Enter contact email\" size=\"md\">\n </cide-ele-input>\n\n <cide-ele-input label=\"Contact Email ID\" formControlName=\"syfdl_contact_email_id\" type=\"email\"\n placeholder=\"Enter contact email ID\" size=\"md\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6\">\n <cide-ele-input label=\"Contact Number\" formControlName=\"syfdl_contact_number\" type=\"tel\"\n placeholder=\"Enter contact number\" size=\"md\">\n </cide-ele-input>\n\n <div class=\"tw-flex tw-items-center tw-pt-6\">\n <cide-ele-input formControlName=\"syfdl_isactive\" type=\"checkbox\" label=\"Active\" size=\"md\">\n </cide-ele-input>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Form Actions -->\n <div\n class=\"tw-flex tw-justify-end tw-gap-4 tw-py-2 tw-bg-white tw-border-t tw-border-gray-200 tw-sticky tw-bottom-0 tw-z-10\">\n <button cideEleButton type=\"button\" variant=\"secondary\" (click)=\"resetForm()\" leftIcon=\"refresh\"\n [disabled]=\"loading()\">\n Reset Form\n </button>\n\n <button cideEleButton type=\"submit\" variant=\"primary\" [disabled]=\"loading() || userMasterForm.invalid\"\n [loading]=\"loading()\" leftIcon=\"save\">\n Save User Master\n </button>\n </div>\n </form>\n</div>\n\n<!-- Template Renderers for Role Permissions Grid -->\n<ng-template #menuDetailsRendererTemplate let-row=\"row\">\n <div class=\"tw-flex tw-items-center tw-space-x-3 tw-min-w-0\">\n <!-- Menu Icon -->\n <div class=\"tw-flex-shrink-0\">\n @if (row.syme_type === 'module') {\n <cide-ele-icon class=\"tw-text-blue-600 tw-w-4 tw-h-4\">folder</cide-ele-icon>\n } @else if (row.syme_type === 'section') {\n <cide-ele-icon class=\"tw-text-green-600 tw-w-4 tw-h-4\">folder_open</cide-ele-icon>\n } @else if (row.syme_type === 'menu') {\n <cide-ele-icon class=\"tw-text-purple-600 tw-w-4 tw-h-4\">menu</cide-ele-icon>\n } @else {\n <cide-ele-icon class=\"tw-text-gray-600 tw-w-4 tw-h-4\">description</cide-ele-icon>\n }\n </div>\n\n <!-- Menu Details -->\n <div class=\"tw-ml-3 tw-min-w-0 tw-flex-1\">\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <div class=\"tw-text-xs tw-font-medium tw-text-gray-900 tw-truncate\" [title]=\"row.syme_title\">\n {{ row.syme_title || row.menu?.syme_title || row.menu?.syme_menu_name || 'Untitled' }}\n </div>\n <!-- Green pill indicator for parent menus with child permissions -->\n @if (row.syme_type === 'module' || row.syme_type === 'section') {\n @if (hasChildMenusWithPermissions(row._id)) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800 tw-whitespace-nowrap\">\n Assigned\n </span>\n }\n }\n </div>\n @if (row.permission?.sygms_name) {\n <div class=\"tw-text-xs tw-text-blue-500 tw-truncate\" [title]=\"row.permission?.sygms_name\">\n {{ row.permission?.sygms_name }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n\n<!-- Menu Type Renderer Template -->\n<ng-template #menuTypeRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-items-center tw-justify-center\">\n @if (row.syme_type === 'module') {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-blue-100 tw-text-blue-800\">\n Module\n </span>\n } @else if (row.syme_type === 'section') {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n Section\n </span>\n } @else if (row.syme_type === 'menu') {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-purple-100 tw-text-purple-800\">\n Menu\n </span>\n } @else {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2 tw-py-1 tw-rounded-full tw-text-xs tw-font-medium tw-bg-gray-100 tw-text-gray-800\">\n {{ row.syme_type || 'Unknown' }}\n </span>\n }\n </div>\n</ng-template>\n\n<!-- Permissions Checkbox Renderer Template -->\n<ng-template #permissionsCheckboxRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n @if (row.syme_type === 'menu' && row?.syme_permissions_id_sygms && row?.syme_permissions_id_sygms.length > 0) {\n @for (permissionId of row?.syme_permissions_id_sygms || []; track permissionId) {\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <div class=\"tw-flex tw-items-center tw-space-x-1\">\n <input type=\"checkbox\" [checked]=\"isPermissionSelected(row._id, permissionId)\" [disabled]=\"true\"\n class=\"tw-h-4 tw-w-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded focus:tw-ring-blue-500\">\n <label class=\"tw-text-xs tw-text-gray-700\">\n {{ getPermissionById(permissionId)?.sygms_name || 'Unknown' }}\n </label>\n </div>\n </div>\n }\n } @else {\n <!-- Show green checkmark for parent menus with child permissions -->\n @if (row.syme_type === 'module' || row.syme_type === 'section' || row.syme_type === 'title') {\n @if (hasChildMenusWithPermissions(row._id)) {\n <div class=\"tw-flex tw-items-center tw-justify-center tw-w-6 tw-h-6 tw-bg-green-100 tw-rounded-full\">\n <cide-ele-icon class=\"tw-text-green-600\" size=\"xs\">\n check\n </cide-ele-icon>\n </div>\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">N/A</span>\n }\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">N/A</span>\n }\n }\n </div>\n</ng-template>\n\n<!-- Menu Rights Permissions Renderer Template -->\n<ng-template #menuRightsPermissionsRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n <!-- Role Rights Display -->\n @if (row.role_rights && row.role_rights.length > 0) {\n <div class=\"tw-mb-2\">\n <div class=\"tw-text-xs tw-text-gray-500 tw-mb-1\">Role Rights:</div>\n <div class=\"tw-flex tw-flex-wrap tw-gap-1\">\n @for (right of row.role_rights; track $index) {\n <span class=\"tw-inline-block tw-px-2 tw-py-1 tw-text-xs tw-bg-blue-100 tw-text-blue-800 tw-rounded\">\n {{ right }}\n </span>\n }\n </div>\n </div>\n }\n\n\n <!-- Exception Indicator -->\n @if (row.hasException) {\n <div class=\"tw-mt-2\">\n <span class=\"tw-inline-block tw-px-2 tw-py-1 tw-text-xs tw-bg-yellow-100 tw-text-yellow-800 tw-rounded\">\n Override\n </span>\n </div>\n } @else {\n <div class=\"tw-mt-2\">\n <span class=\"tw-text-xs tw-text-gray-400\">Default</span>\n </div>\n }\n </div>\n</ng-template>\n\n<!-- Permissions Renderer Template -->\n<ng-template #permissionsRendererTemplate let-row=\"row\" let-value=\"value\">\n <div class=\"tw-flex tw-flex-wrap tw-gap-2 tw-max-w-full\">\n @if (row._permissionValues && Object.keys(row._permissionValues).length > 0) {\n @for (permissionId of Object.keys(row._permissionValues); track permissionId) {\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <cide-ele-input type=\"checkbox\" [ngModel]=\"row._permissionValues[permissionId].checked\"\n (ngModelChange)=\"onPermissionChangeSafe($event, row, permissionId)\"\n [id]=\"'permission-' + row._id + '-' + permissionId\" class=\"tw-h-4 tw-w-4\">\n </cide-ele-input>\n <label [for]=\"'permission-' + row._id + '-' + permissionId\" class=\"tw-text-xs tw-text-gray-700 tw-cursor-pointer\">\n {{ row._permissionValues[permissionId].permission?.sygms_title }}\n </label>\n </div>\n }\n } @else {\n <span class=\"tw-text-xs tw-text-gray-400\">No permissions</span>\n }\n </div>\n</ng-template>" }]
|
|
13364
14182
|
}], ctorParameters: () => [] });
|
|
13365
14183
|
|
|
13366
14184
|
var userCreate_component = /*#__PURE__*/Object.freeze({
|
|
@@ -13871,7 +14689,7 @@ class CideCoreUserListComponent {
|
|
|
13871
14689
|
}
|
|
13872
14690
|
}
|
|
13873
14691
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideCoreUserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13874
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideCoreUserListComponent, isStandalone: true, selector: "cide-core-user-list", viewQueries: [{ propertyName: "gridComponent", first: true, predicate: CideEleDataGridComponent, descendants: true }, { propertyName: "actionsTemplate", first: true, predicate: ["actionsTemplate"], descendants: true, static: true }, { propertyName: "userDetailsTemplate", first: true, predicate: ["userDetailsTemplate"], descendants: true, static: true }, { propertyName: "contactInfoTemplate", first: true, predicate: ["contactInfoTemplate"], descendants: true, static: true }, { propertyName: "organizationTemplate", first: true, predicate: ["organizationTemplate"], descendants: true, static: true }, { propertyName: "validityTemplate", first: true, predicate: ["validityTemplate"], descendants: true, static: true }, { propertyName: "statusTemplate", first: true, predicate: ["statusTemplate"], descendants: true, static: true }], ngImport: i0, template: "<!-- User Master List Container -->\n<div class=\"user-master-listing-container tw-bg-white tw-shadow-lg tw-rounded-lg tw-table tw-h-full\">\n\n <!-- Header Section with Filters -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div\n 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\">people</cide-ele-icon>\n <div>\n <h5 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">User Master Management</h5>\n <p class=\"tw-text-sm tw-text-gray-600\">Manage and view all user master records in the system</p>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <!-- Status Filter -->\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <label for=\"statusFilter\" class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Status:</label>\n <cide-ele-select id=\"statusFilter\" [options]=\"statusFilterOptions()\" [(ngModel)]=\"selectedStatusFilterValue\"\n (ngModelChange)=\"onFilterChange()\" class=\"tw-min-w-40\">\n </cide-ele-select>\n </div>\n\n <!-- Add User Button -->\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"onAddUser()\"\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 User\n </button>\n </div>\n </div>\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 class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n <div class=\"tw-h-full tw-overflow-auto\">\n <!-- Data Grid Component -->\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers\"\n [serverSidePagination]=\"true\" [totalServerItems]=\"totalItems()\" [currentServerPage]=\"currentPage()\"\n [currentServerPageSize]=\"pageSize()\" (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n </div>\n </div>\n\n</div>\n\n<!-- Template Definitions for Grid Renderers -->\n\n<!-- User Details Template -->\n<ng-template #userDetailsTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <div\n class=\"tw-flex-shrink-0 tw-w-12 tw-h-12 tw-bg-blue-100 tw-rounded-full tw-flex tw-items-center tw-justify-center\">\n <span class=\"tw-text-blue-600 tw-font-semibold tw-text-sm\">\n {{ getUserInitials(row.user_firstname, row.user_lastname) }}\n </span>\n </div>\n <div class=\"tw-flex-1 tw-min-w-0\">\n <p class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-truncate\" [title]=\"row.user_fullname\">\n {{ row.user_fullname || 'Unknown User' }}\n </p>\n <p class=\"tw-text-xs tw-text-blue-600 tw-truncate tw-font-medium\" [title]=\"'Username: ' + row.user_username\">\n @{{ row.user_username || 'No username' }}\n </p>\n <p class=\"tw-text-xs tw-text-gray-400 tw-truncate\" [title]=\"'ID: ' + row._id\">\n ID: {{ row._id?.substring(0, 8) }}...\n </p>\n </div>\n </div>\n</ng-template>\n\n<!-- Contact Info Template -->\n<ng-template #contactInfoTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-space-y-1\">\n <p class=\"tw-text-xs tw-text-gray-900 tw-flex tw-items-center\" [title]=\"'Email: ' + row.user_emailid\">\n <svg class=\"tw-flex-shrink-0 tw-w-3 tw-h-3 tw-text-gray-400 tw-mr-2\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z\" />\n <path d=\"M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z\" />\n </svg>\n <span class=\"tw-truncate\">{{ row.user_emailid || 'No email' }}</span>\n </p>\n <p class=\"tw-text-xs tw-text-gray-600 tw-flex tw-items-center\" [title]=\"'Mobile: ' + row.user_mobileno\">\n <svg class=\"tw-flex-shrink-0 tw-w-3 tw-h-3 tw-text-gray-400 tw-mr-2\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path\n 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\" />\n </svg>\n <span class=\"tw-truncate\">{{ row.user_mobileno || 'No mobile' }}</span>\n </p>\n <p class=\"tw-text-xs tw-text-gray-500 tw-flex tw-items-center\"\n [title]=\"'Password Change: ' + getPasswordChangeText(row.user_passwordchangeonlogin)\">\n <svg class=\"tw-flex-shrink-0 tw-w-3 tw-h-3 tw-text-gray-400 tw-mr-2\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z\"\n clip-rule=\"evenodd\" />\n </svg>\n <span class=\"tw-truncate\">{{ getPasswordChangeText(row.user_passwordchangeonlogin) }}</span>\n </p>\n </div>\n</ng-template>\n\n\n\n<!-- Validity Template -->\n<ng-template #validityTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-text-center tw-space-y-1\">\n <p class=\"tw-text-xs tw-text-gray-900 tw-font-medium\">\n Validity managed per entity\n </p>\n <p class=\"tw-text-xs tw-text-gray-600\">\n Check entity mappings for details\n </p>\n </div>\n</ng-template>\n\n<!-- Status Template -->\n<ng-template #statusTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-flex tw-justify-center\">\n @if (row.user_isactive) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n <svg class=\"tw-w-1.5 tw-h-1.5 tw-mr-1\" fill=\"currentColor\" viewBox=\"0 0 8 8\">\n <circle cx=\"4\" cy=\"4\" r=\"3\" />\n </svg>\n Active\n </span>\n } @else {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-800\">\n <svg class=\"tw-w-1.5 tw-h-1.5 tw-mr-1\" fill=\"currentColor\" viewBox=\"0 0 8 8\">\n <circle cx=\"4\" cy=\"4\" r=\"3\" />\n </svg>\n Inactive\n </span>\n }\n </div>\n</ng-template>\n\n<!-- Actions Template using cide-ele-dropdown -->\n<ng-template #actionsTemplate let-value let-row=\"row\" let-column=\"column\">\n <cide-ele-dropdown [items]=\"getDropdownItems(row)\" [config]=\"{ triggerIcon: 'more_vert', triggerSize: 'sm', usePortal: true, minWidth: 200 }\" (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>", styles: [".user-master-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.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", "valueKey", "labelKey"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }] });
|
|
14692
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideCoreUserListComponent, isStandalone: true, selector: "cide-core-user-list", viewQueries: [{ propertyName: "gridComponent", first: true, predicate: CideEleDataGridComponent, descendants: true }, { propertyName: "actionsTemplate", first: true, predicate: ["actionsTemplate"], descendants: true, static: true }, { propertyName: "userDetailsTemplate", first: true, predicate: ["userDetailsTemplate"], descendants: true, static: true }, { propertyName: "contactInfoTemplate", first: true, predicate: ["contactInfoTemplate"], descendants: true, static: true }, { propertyName: "organizationTemplate", first: true, predicate: ["organizationTemplate"], descendants: true, static: true }, { propertyName: "validityTemplate", first: true, predicate: ["validityTemplate"], descendants: true, static: true }, { propertyName: "statusTemplate", first: true, predicate: ["statusTemplate"], descendants: true, static: true }], ngImport: i0, template: "<!-- User Master List Container -->\n<div class=\"user-master-listing-container tw-bg-white tw-shadow-lg tw-rounded-lg tw-table tw-h-full\">\n\n <!-- Header Section with Filters -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div\n 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\">people</cide-ele-icon>\n <div>\n <h5 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">User Master Management</h5>\n <p class=\"tw-text-sm tw-text-gray-600\">Manage and view all user master records in the system</p>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <!-- Status Filter -->\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <label for=\"statusFilter\" class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Status:</label>\n <cide-ele-select id=\"statusFilter\" [options]=\"statusFilterOptions()\" [(ngModel)]=\"selectedStatusFilterValue\"\n (ngModelChange)=\"onFilterChange()\" class=\"tw-min-w-40\">\n </cide-ele-select>\n </div>\n\n <!-- Add User Button -->\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"onAddUser()\"\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 User\n </button>\n </div>\n </div>\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 class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n <div class=\"tw-h-full tw-overflow-auto\">\n <!-- Data Grid Component -->\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers\"\n [serverSidePagination]=\"true\" [totalServerItems]=\"totalItems()\" [currentServerPage]=\"currentPage()\"\n [currentServerPageSize]=\"pageSize()\" (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n </div>\n </div>\n\n</div>\n\n<!-- Template Definitions for Grid Renderers -->\n\n<!-- User Details Template -->\n<ng-template #userDetailsTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <div\n class=\"tw-flex-shrink-0 tw-w-12 tw-h-12 tw-bg-blue-100 tw-rounded-full tw-flex tw-items-center tw-justify-center\">\n <span class=\"tw-text-blue-600 tw-font-semibold tw-text-sm\">\n {{ getUserInitials(row.user_firstname, row.user_lastname) }}\n </span>\n </div>\n <div class=\"tw-flex-1 tw-min-w-0\">\n <p class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-truncate\" [title]=\"row.user_fullname\">\n {{ row.user_fullname || 'Unknown User' }}\n </p>\n <p class=\"tw-text-xs tw-text-blue-600 tw-truncate tw-font-medium\" [title]=\"'Username: ' + row.user_username\">\n @{{ row.user_username || 'No username' }}\n </p>\n <p class=\"tw-text-xs tw-text-gray-400 tw-truncate\" [title]=\"'ID: ' + row._id\">\n ID: {{ row._id?.substring(0, 8) }}...\n </p>\n </div>\n </div>\n</ng-template>\n\n<!-- Contact Info Template -->\n<ng-template #contactInfoTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-space-y-1\">\n <p class=\"tw-text-xs tw-text-gray-900 tw-flex tw-items-center\" [title]=\"'Email: ' + row.user_emailid\">\n <svg class=\"tw-flex-shrink-0 tw-w-3 tw-h-3 tw-text-gray-400 tw-mr-2\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z\" />\n <path d=\"M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z\" />\n </svg>\n <span class=\"tw-truncate\">{{ row.user_emailid || 'No email' }}</span>\n </p>\n <p class=\"tw-text-xs tw-text-gray-600 tw-flex tw-items-center\" [title]=\"'Mobile: ' + row.user_mobileno\">\n <svg class=\"tw-flex-shrink-0 tw-w-3 tw-h-3 tw-text-gray-400 tw-mr-2\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path\n 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\" />\n </svg>\n <span class=\"tw-truncate\">{{ row.user_mobileno || 'No mobile' }}</span>\n </p>\n <p class=\"tw-text-xs tw-text-gray-500 tw-flex tw-items-center\"\n [title]=\"'Password Change: ' + getPasswordChangeText(row.user_passwordchangeonlogin)\">\n <svg class=\"tw-flex-shrink-0 tw-w-3 tw-h-3 tw-text-gray-400 tw-mr-2\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z\"\n clip-rule=\"evenodd\" />\n </svg>\n <span class=\"tw-truncate\">{{ getPasswordChangeText(row.user_passwordchangeonlogin) }}</span>\n </p>\n </div>\n</ng-template>\n\n\n\n<!-- Validity Template -->\n<ng-template #validityTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-text-center tw-space-y-1\">\n <p class=\"tw-text-xs tw-text-gray-900 tw-font-medium\">\n Validity managed per entity\n </p>\n <p class=\"tw-text-xs tw-text-gray-600\">\n Check entity mappings for details\n </p>\n </div>\n</ng-template>\n\n<!-- Status Template -->\n<ng-template #statusTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-flex tw-justify-center\">\n @if (row.user_isactive) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n <svg class=\"tw-w-1.5 tw-h-1.5 tw-mr-1\" fill=\"currentColor\" viewBox=\"0 0 8 8\">\n <circle cx=\"4\" cy=\"4\" r=\"3\" />\n </svg>\n Active\n </span>\n } @else {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-800\">\n <svg class=\"tw-w-1.5 tw-h-1.5 tw-mr-1\" fill=\"currentColor\" viewBox=\"0 0 8 8\">\n <circle cx=\"4\" cy=\"4\" r=\"3\" />\n </svg>\n Inactive\n </span>\n }\n </div>\n</ng-template>\n\n<!-- Actions Template using cide-ele-dropdown -->\n<ng-template #actionsTemplate let-value let-row=\"row\" let-column=\"column\">\n <cide-ele-dropdown [items]=\"getDropdownItems(row)\" [config]=\"{ triggerIcon: 'more_vert', triggerSize: 'sm', usePortal: true, minWidth: 200 }\" (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>", styles: [".user-master-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.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", "valueKey", "labelKey"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideEleDataGridComponent, selector: "cide-ele-data-grid", inputs: ["config", "templateRenderers", "customFormatters", "actionHandlers", "serverSidePagination", "totalServerItems", "currentServerPage", "currentServerPageSize", "dragDropEnabled"], outputs: ["gridEvent"] }, { kind: "component", type: CideEleDropdownComponent, selector: "cide-ele-dropdown", inputs: ["items", "config", "triggerTemplate", "menuTemplate"], outputs: ["itemClick", "dropdownToggle"] }] });
|
|
13875
14693
|
}
|
|
13876
14694
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideCoreUserListComponent, decorators: [{
|
|
13877
14695
|
type: Component,
|
|
@@ -13883,7 +14701,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
|
|
|
13883
14701
|
CideSelectComponent,
|
|
13884
14702
|
CideEleDataGridComponent,
|
|
13885
14703
|
CideEleDropdownComponent
|
|
13886
|
-
], template: "<!-- User Master List Container -->\n<div class=\"user-master-listing-container tw-bg-white tw-shadow-lg tw-rounded-lg tw-table tw-h-full\">\n\n <!-- Header Section with Filters -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div\n 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\"
|
|
14704
|
+
], template: "<!-- User Master List Container -->\n<div class=\"user-master-listing-container tw-bg-white tw-shadow-lg tw-rounded-lg tw-table tw-h-full\">\n\n <!-- Header Section with Filters -->\n <div class=\"tw-table-row tw-h-0\">\n <div class=\"tw-px-6 tw-py-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div\n 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\">people</cide-ele-icon>\n <div>\n <h5 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">User Master Management</h5>\n <p class=\"tw-text-sm tw-text-gray-600\">Manage and view all user master records in the system</p>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <!-- Status Filter -->\n <div class=\"tw-flex tw-items-center tw-space-x-2\">\n <label for=\"statusFilter\" class=\"tw-text-sm tw-font-medium tw-text-gray-700\">Status:</label>\n <cide-ele-select id=\"statusFilter\" [options]=\"statusFilterOptions()\" [(ngModel)]=\"selectedStatusFilterValue\"\n (ngModelChange)=\"onFilterChange()\" class=\"tw-min-w-40\">\n </cide-ele-select>\n </div>\n\n <!-- Add User Button -->\n <button cideEleButton variant=\"primary\" size=\"sm\" (click)=\"onAddUser()\"\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 User\n </button>\n </div>\n </div>\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 class=\"tw-table-row\">\n <div class=\"tw-table-cell tw-h-full tw-relative\">\n <div class=\"tw-h-full tw-overflow-auto\">\n <!-- Data Grid Component -->\n <cide-ele-data-grid [config]=\"gridConfig()\" [templateRenderers]=\"templateRenderers\"\n [serverSidePagination]=\"true\" [totalServerItems]=\"totalItems()\" [currentServerPage]=\"currentPage()\"\n [currentServerPageSize]=\"pageSize()\" (gridEvent)=\"onGridEvent($event)\">\n </cide-ele-data-grid>\n </div>\n </div>\n </div>\n\n</div>\n\n<!-- Template Definitions for Grid Renderers -->\n\n<!-- User Details Template -->\n<ng-template #userDetailsTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-flex tw-items-center tw-space-x-3\">\n <div\n class=\"tw-flex-shrink-0 tw-w-12 tw-h-12 tw-bg-blue-100 tw-rounded-full tw-flex tw-items-center tw-justify-center\">\n <span class=\"tw-text-blue-600 tw-font-semibold tw-text-sm\">\n {{ getUserInitials(row.user_firstname, row.user_lastname) }}\n </span>\n </div>\n <div class=\"tw-flex-1 tw-min-w-0\">\n <p class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-truncate\" [title]=\"row.user_fullname\">\n {{ row.user_fullname || 'Unknown User' }}\n </p>\n <p class=\"tw-text-xs tw-text-blue-600 tw-truncate tw-font-medium\" [title]=\"'Username: ' + row.user_username\">\n @{{ row.user_username || 'No username' }}\n </p>\n <p class=\"tw-text-xs tw-text-gray-400 tw-truncate\" [title]=\"'ID: ' + row._id\">\n ID: {{ row._id?.substring(0, 8) }}...\n </p>\n </div>\n </div>\n</ng-template>\n\n<!-- Contact Info Template -->\n<ng-template #contactInfoTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-space-y-1\">\n <p class=\"tw-text-xs tw-text-gray-900 tw-flex tw-items-center\" [title]=\"'Email: ' + row.user_emailid\">\n <svg class=\"tw-flex-shrink-0 tw-w-3 tw-h-3 tw-text-gray-400 tw-mr-2\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z\" />\n <path d=\"M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z\" />\n </svg>\n <span class=\"tw-truncate\">{{ row.user_emailid || 'No email' }}</span>\n </p>\n <p class=\"tw-text-xs tw-text-gray-600 tw-flex tw-items-center\" [title]=\"'Mobile: ' + row.user_mobileno\">\n <svg class=\"tw-flex-shrink-0 tw-w-3 tw-h-3 tw-text-gray-400 tw-mr-2\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path\n 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\" />\n </svg>\n <span class=\"tw-truncate\">{{ row.user_mobileno || 'No mobile' }}</span>\n </p>\n <p class=\"tw-text-xs tw-text-gray-500 tw-flex tw-items-center\"\n [title]=\"'Password Change: ' + getPasswordChangeText(row.user_passwordchangeonlogin)\">\n <svg class=\"tw-flex-shrink-0 tw-w-3 tw-h-3 tw-text-gray-400 tw-mr-2\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\"\n d=\"M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z\"\n clip-rule=\"evenodd\" />\n </svg>\n <span class=\"tw-truncate\">{{ getPasswordChangeText(row.user_passwordchangeonlogin) }}</span>\n </p>\n </div>\n</ng-template>\n\n\n\n<!-- Validity Template -->\n<ng-template #validityTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-text-center tw-space-y-1\">\n <p class=\"tw-text-xs tw-text-gray-900 tw-font-medium\">\n Validity managed per entity\n </p>\n <p class=\"tw-text-xs tw-text-gray-600\">\n Check entity mappings for details\n </p>\n </div>\n</ng-template>\n\n<!-- Status Template -->\n<ng-template #statusTemplate let-value let-row=\"row\" let-column=\"column\">\n <div class=\"tw-flex tw-justify-center\">\n @if (row.user_isactive) {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-green-100 tw-text-green-800\">\n <svg class=\"tw-w-1.5 tw-h-1.5 tw-mr-1\" fill=\"currentColor\" viewBox=\"0 0 8 8\">\n <circle cx=\"4\" cy=\"4\" r=\"3\" />\n </svg>\n Active\n </span>\n } @else {\n <span\n class=\"tw-inline-flex tw-items-center tw-px-2.5 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium tw-bg-red-100 tw-text-red-800\">\n <svg class=\"tw-w-1.5 tw-h-1.5 tw-mr-1\" fill=\"currentColor\" viewBox=\"0 0 8 8\">\n <circle cx=\"4\" cy=\"4\" r=\"3\" />\n </svg>\n Inactive\n </span>\n }\n </div>\n</ng-template>\n\n<!-- Actions Template using cide-ele-dropdown -->\n<ng-template #actionsTemplate let-value let-row=\"row\" let-column=\"column\">\n <cide-ele-dropdown [items]=\"getDropdownItems(row)\" [config]=\"{ triggerIcon: 'more_vert', triggerSize: 'sm', usePortal: true, minWidth: 200 }\" (itemClick)=\"onDropdownItemClick($event, row)\">\n </cide-ele-dropdown>\n</ng-template>", styles: [".user-master-listing-container{@apply tw-w-full tw-h-full;}:host{@apply tw-w-full tw-h-full tw-flex tw-flex-col;}\n"] }]
|
|
13887
14705
|
}], propDecorators: { gridComponent: [{
|
|
13888
14706
|
type: ViewChild,
|
|
13889
14707
|
args: [CideEleDataGridComponent]
|