cloud-ide-fees 0.0.17 → 0.0.19

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.
@@ -8,12 +8,12 @@ import { CommonModule, DatePipe } from '@angular/common';
8
8
  import * as i1$1 from '@angular/forms';
9
9
  import { FormsModule, FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
10
10
  import { Router, ActivatedRoute } from '@angular/router';
11
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
11
+ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
12
12
  import { ConfirmationService, NotificationService, CideIconComponent, CideEleButtonComponent, CideEleDataGridComponent, CideEleDropdownComponent, CideInputComponent, CideTextareaComponent, CideEleTabComponent, CideSelectComponent, CurrencyPipe } from 'cloud-ide-element';
13
13
  import { AppStateHelperService, CideLytSharedWrapperComponent, AppStateService } from 'cloud-ide-layout';
14
14
  import { ENTITY_SERVICE_TOKEN, ACADEMIC_YEAR_SERVICE_TOKEN, CLASS_PROGRAM_MASTER_SERVICE_TOKEN, PROGRAM_TERM_SECTION_SERVICE_TOKEN, ProgramSectionSelectorWrapperComponent } from 'cloud-ide-shared';
15
15
  import { CideCoreGeneralMasterService } from 'cloud-ide-core';
16
- import { forkJoin } from 'rxjs';
16
+ import { forkJoin, startWith } from 'rxjs';
17
17
  import { DomSanitizer } from '@angular/platform-browser';
18
18
 
19
19
  class CloudIdeFees {
@@ -40,28 +40,28 @@ const feesRoutes = [
40
40
  loadComponent: () => Promise.resolve().then(function () { return feeStructureList_component; }).then(c => c.FeeStructureListComponent),
41
41
  title: 'Fee Structure Management',
42
42
  canActivate: [authGuard],
43
- data: { reuseTab: true, sypg_page_code: "fee_structure" }
43
+ data: { sypg_page_code: "fee_structure" }
44
44
  },
45
45
  {
46
46
  path: 'structure/create',
47
47
  loadComponent: () => Promise.resolve().then(function () { return feeStructureCreate_component; }).then(c => c.FeeStructureCreateComponent),
48
48
  title: 'Create Fee Structure',
49
49
  canActivate: [authGuard],
50
- data: { reuseTab: true, sypg_page_code: "fee_structure" }
50
+ data: { sypg_page_code: "fee_structure" }
51
51
  },
52
52
  {
53
53
  path: 'structure/edit/:query',
54
54
  loadComponent: () => Promise.resolve().then(function () { return feeStructureCreate_component; }).then(c => c.FeeStructureCreateComponent),
55
55
  title: 'Edit Fee Structure',
56
56
  canActivate: [authGuard],
57
- data: { reuseTab: true, sypg_page_code: "fee_structure" }
57
+ data: { sypg_page_code: "fee_structure" }
58
58
  },
59
59
  {
60
60
  path: 'structure/view/:query',
61
61
  loadComponent: () => Promise.resolve().then(function () { return feeStructureCreate_component; }).then(c => c.FeeStructureCreateComponent),
62
62
  title: 'View Fee Structure',
63
63
  canActivate: [authGuard],
64
- data: { reuseTab: true, sypg_page_code: "fee_structure" }
64
+ data: { sypg_page_code: "fee_structure" }
65
65
  },
66
66
  // Fee Assignment Routes
67
67
  {
@@ -69,28 +69,28 @@ const feesRoutes = [
69
69
  loadComponent: () => Promise.resolve().then(function () { return feeAssignmentList_component; }).then(c => c.FeeAssignmentListComponent),
70
70
  title: 'Fee Assignment Management',
71
71
  canActivate: [authGuard],
72
- data: { reuseTab: true, sypg_page_code: "fee_assignment" }
72
+ data: { sypg_page_code: "fee_assignment" }
73
73
  },
74
74
  {
75
75
  path: 'assignment/create',
76
76
  loadComponent: () => Promise.resolve().then(function () { return feeAssignmentCreate_component; }).then(c => c.FeeAssignmentCreateComponent),
77
77
  title: 'Assign Fee to Student',
78
78
  canActivate: [authGuard],
79
- data: { reuseTab: true, sypg_page_code: "fee_assignment" }
79
+ data: { sypg_page_code: "fee_assignment" }
80
80
  },
81
81
  {
82
82
  path: 'assignment/edit/:query',
83
83
  loadComponent: () => Promise.resolve().then(function () { return feeAssignmentCreate_component; }).then(c => c.FeeAssignmentCreateComponent),
84
84
  title: 'Edit Fee Assignment',
85
85
  canActivate: [authGuard],
86
- data: { reuseTab: true, sypg_page_code: "fee_assignment" }
86
+ data: { sypg_page_code: "fee_assignment" }
87
87
  },
88
88
  {
89
89
  path: 'assignment/view/:query',
90
90
  loadComponent: () => Promise.resolve().then(function () { return feeAssignmentCreate_component; }).then(c => c.FeeAssignmentCreateComponent),
91
91
  title: 'View Fee Assignment',
92
92
  canActivate: [authGuard],
93
- data: { reuseTab: true, sypg_page_code: "fee_assignment" }
93
+ data: { sypg_page_code: "fee_assignment" }
94
94
  },
95
95
  // Fee Payment Management Routes
96
96
  {
@@ -98,21 +98,21 @@ const feesRoutes = [
98
98
  loadComponent: () => Promise.resolve().then(function () { return feePaymentList_component; }).then(c => c.FeePaymentListComponent),
99
99
  title: 'Fee Payment Management',
100
100
  canActivate: [authGuard],
101
- data: { reuseTab: true, sypg_page_code: "fee_payment" }
101
+ data: { sypg_page_code: "fee_payment" }
102
102
  },
103
103
  {
104
104
  path: 'payment/process',
105
105
  loadComponent: () => Promise.resolve().then(function () { return feePaymentProcess_component; }).then(c => c.FeePaymentProcessComponent),
106
106
  title: 'Process Fee Payment',
107
107
  canActivate: [authGuard],
108
- data: { reuseTab: true, sypg_page_code: "fee_payment" }
108
+ data: { sypg_page_code: "fee_payment" }
109
109
  },
110
110
  {
111
111
  path: 'payment/view/:query',
112
112
  loadComponent: () => Promise.resolve().then(function () { return feePaymentView_component; }).then(c => c.FeePaymentViewComponent),
113
113
  title: 'View Fee Payment',
114
114
  canActivate: [authGuard],
115
- data: { reuseTab: true, sypg_page_code: "fee_payment" }
115
+ data: { sypg_page_code: "fee_payment" }
116
116
  },
117
117
  // Discount & Scholarship Management
118
118
  {
@@ -120,7 +120,7 @@ const feesRoutes = [
120
120
  loadComponent: () => Promise.resolve().then(function () { return discountRules_component; }).then(c => c.DiscountRulesComponent),
121
121
  title: 'Discount & Scholarship Management',
122
122
  canActivate: [authGuard],
123
- data: { reuseTab: true, sypg_page_code: "fee_discounts" }
123
+ data: { sypg_page_code: "fee_discounts" }
124
124
  },
125
125
  // Receipt Template Designer
126
126
  {
@@ -128,7 +128,7 @@ const feesRoutes = [
128
128
  loadComponent: () => Promise.resolve().then(function () { return templateDesigner_component; }).then(c => c.TemplateDesignerComponent),
129
129
  title: 'Receipt Template Designer',
130
130
  canActivate: [authGuard],
131
- data: { reuseTab: true, sypg_page_code: "receipt_template" }
131
+ data: { sypg_page_code: "receipt_template" }
132
132
  },
133
133
  // Reports
134
134
  {
@@ -136,7 +136,7 @@ const feesRoutes = [
136
136
  loadComponent: () => Promise.resolve().then(function () { return collectionReport_component; }).then(c => c.CollectionReportComponent),
137
137
  title: 'Fee Collection Report',
138
138
  canActivate: [authGuard],
139
- data: { reuseTab: true, sypg_page_code: "fee_reports" }
139
+ data: { sypg_page_code: "fee_reports" }
140
140
  },
141
141
  // Student Fees (Integrated into Dashboard)
142
142
  {
@@ -144,14 +144,14 @@ const feesRoutes = [
144
144
  loadComponent: () => Promise.resolve().then(function () { return myFeeStatement_component; }).then(c => c.MyFeeStatementComponent),
145
145
  title: 'My Fee Statement',
146
146
  canActivate: [authGuard],
147
- data: { reuseTab: true, sypg_page_code: "my_fee_statement" }
147
+ data: { sypg_page_code: "my_fee_statement" }
148
148
  },
149
149
  {
150
150
  path: 'payment',
151
151
  loadComponent: () => Promise.resolve().then(function () { return myOnlinePayment_component; }).then(c => c.MyOnlinePaymentComponent),
152
152
  title: 'Online Fee Payment',
153
153
  canActivate: [authGuard],
154
- data: { reuseTab: true, sypg_page_code: "my_online_payment" }
154
+ data: { sypg_page_code: "my_online_payment" }
155
155
  }
156
156
  ];
157
157
 
@@ -5583,7 +5583,15 @@ class TemplateDesignerComponent extends CideLytSharedWrapperComponent {
5583
5583
  return category.tags.filter(tag => tag.code.toLowerCase().includes(query) ||
5584
5584
  tag.description.toLowerCase().includes(query));
5585
5585
  }, ...(ngDevMode ? [{ debugName: "filteredTags" }] : []));
5586
+ // Reactive signal for template HTML - tracks form control changes
5587
+ templateHtmlSignal = toSignal(this.templateForm.get('template_html').valueChanges.pipe(startWith(this.templateForm.get('template_html')?.value || '')), { initialValue: this.templateForm.get('template_html')?.value || '' });
5588
+ // Reactive signal for preview type - tracks preview type changes
5589
+ previewTypeSignal = toSignal(this.templateForm.get('preview_type').valueChanges.pipe(startWith(this.templateForm.get('preview_type')?.value || 'STUDENT')), { initialValue: this.templateForm.get('preview_type')?.value || 'STUDENT' });
5586
5590
  previewHtml = computed(() => {
5591
+ // Access both signals to make computed reactive to both changes
5592
+ const templateHtml = this.templateHtmlSignal(); // Read to track dependency
5593
+ const previewType = this.previewTypeSignal(); // Read to track dependency
5594
+ // Use the reactive signal instead of reading directly from form
5587
5595
  const htmlContent = this.getPreviewWithSampleData();
5588
5596
  return this.sanitizer.bypassSecurityTrustHtml(htmlContent);
5589
5597
  }, ...(ngDevMode ? [{ debugName: "previewHtml" }] : []));
@@ -5641,7 +5649,8 @@ class TemplateDesignerComponent extends CideLytSharedWrapperComponent {
5641
5649
  }, 0);
5642
5650
  }
5643
5651
  getPreviewWithSampleData() {
5644
- let html = this.templateForm.get('template_html')?.value || '';
5652
+ // Use the reactive signal to ensure preview updates when template changes
5653
+ let html = this.templateHtmlSignal() || '';
5645
5654
  // Sample fee payment items data
5646
5655
  const sampleFeeItems = [
5647
5656
  {
@@ -6196,7 +6205,7 @@ class TemplateDesignerComponent extends CideLytSharedWrapperComponent {
6196
6205
  });
6197
6206
  }
6198
6207
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: TemplateDesignerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6199
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: TemplateDesignerComponent, isStandalone: true, selector: "cide-receipt-template-designer", inputs: { shared_wrapper_setup_param: { classPropertyName: "shared_wrapper_setup_param", publicName: "shared_wrapper_setup_param", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "htmlEditorRef", first: true, predicate: ["htmlEditor"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<!-- Receipt Template Designer -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"shared_wrapper_setup_param()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"loadTemplates()\" leftIcon=\"folder_open\">\n Load Template\n </button>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"saveTemplate()\" leftIcon=\"save\"\n [disabled]=\"saving() || templateForm.invalid\" [loading]=\"saving()\">\n Save Template\n </button>\n </div>\n\n <!-- Main Content - Three Column Layout -->\n <div class=\"tw-w-full tw-h-full tw-overflow-hidden\" style=\"height: calc(100vh - 80px); max-width: 100vw;\">\n <div class=\"tw-grid tw-grid-cols-12 tw-gap-3 tw-h-full tw-min-h-0 tw-p-3\">\n \n <!-- Left Sidebar - Tag Categories & Tags -->\n <div class=\"tw-col-span-12 lg:tw-col-span-3 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden tw-flex tw-flex-col tw-min-w-0\">\n <!-- Tag Categories Header -->\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2\">Available Tags</h6>\n <form [formGroup]=\"templateForm\">\n <cide-ele-input\n formControlName=\"tag_search\"\n placeholder=\"Search tags...\"\n size=\"sm\"\n leadingIcon=\"search\">\n </cide-ele-input>\n </form>\n </div>\n\n <!-- Category Tabs -->\n <div class=\"tw-flex tw-flex-wrap tw-gap-1 tw-p-2 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-overflow-x-auto\">\n @for (category of tagCategories; track category.id) {\n <button\n type=\"button\"\n class=\"tw-px-2 tw-py-1 tw-text-xs tw-font-medium tw-rounded tw-transition-colors tw-whitespace-nowrap\"\n [class.tw-bg-blue-100]=\"activeCategory() === category.id\"\n [class.tw-text-blue-700]=\"activeCategory() === category.id\"\n [class.tw-bg-gray-100]=\"activeCategory() !== category.id\"\n [class.tw-text-gray-700]=\"activeCategory() !== category.id\"\n (click)=\"onCategoryChange(category.id)\"\n [title]=\"category.name\">\n <cide-ele-icon class=\"tw-w-3 tw-h-3 tw-inline-block tw-mr-1\">{{ category.icon }}</cide-ele-icon>\n <span class=\"tw-hidden sm:tw-inline\">{{ category.name }}</span>\n </button>\n }\n </div>\n\n <!-- Tags List -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-2\">\n @if (filteredTags().length > 0) {\n <div class=\"tw-space-y-1\">\n @for (tag of filteredTags(); track tag.code) {\n <button\n type=\"button\"\n class=\"tw-w-full tw-text-left tw-p-2 tw-rounded tw-border tw-border-gray-200 tw-bg-white hover:tw-bg-blue-50 hover:tw-border-blue-300 tw-transition-colors tw-cursor-pointer tw-group\"\n (click)=\"insertTag(tag)\"\n [title]=\"tag.description\">\n <div class=\"tw-flex tw-items-start tw-justify-between tw-gap-2\">\n <div class=\"tw-flex-1 tw-min-w-0\">\n <code class=\"tw-text-xs tw-font-mono tw-text-blue-600 tw-font-semibold tw-block tw-break-all\">\n {{ tag.code }}\n </code>\n <span class=\"tw-text-xs tw-text-gray-600 tw-block tw-mt-1\">{{ tag.description }}</span>\n @if (tag.example) {\n <span class=\"tw-text-xs tw-text-gray-400 tw-block tw-mt-0.5\">e.g., {{ tag.example }}</span>\n }\n </div>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400 group-hover:tw-text-blue-600 tw-flex-shrink-0 tw-mt-0.5\">add_circle</cide-ele-icon>\n </div>\n </button>\n }\n </div>\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-mx-auto tw-mb-2 tw-text-gray-400\">search_off</cide-ele-icon>\n <p class=\"tw-text-xs\">No tags found</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Middle Column - HTML Editor -->\n <div class=\"tw-col-span-12 lg:tw-col-span-5 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-min-w-0\">\n <div class=\"tw-p-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-4\">Template Configuration</h6>\n \n <form [formGroup]=\"templateForm\" class=\"tw-space-y-3\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input\n label=\"Template Name *\"\n formControlName=\"template_name\"\n placeholder=\"e.g., Standard Receipt\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input\n label=\"Template Code *\"\n formControlName=\"template_code\"\n placeholder=\"e.g., STD_RECEIPT_01\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-select\n label=\"Template Type *\"\n formControlName=\"template_type\"\n [options]=\"[{value: 'PAYMENT', label: 'Payment Receipt'}, {value: 'REFUND', label: 'Refund Receipt'}, {value: 'PROVISIONAL', label: 'Provisional Receipt'}]\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-select\n label=\"Template For\"\n formControlName=\"template_for\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}, {value: 'BOTH', label: 'Both'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"is_default\" type=\"checkbox\" size=\"sm\"></cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Set as Default Template</span>\n </div>\n </form>\n </div>\n\n <div class=\"tw-flex-1 tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">HTML Template *</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">Click tags on left to insert or paste HTML here</span>\n </div>\n </div>\n <div class=\"tw-flex-1 tw-p-3 tw-overflow-hidden tw-min-h-0\">\n <form [formGroup]=\"templateForm\">\n <textarea\n #htmlEditor\n formControlName=\"template_html\"\n placeholder=\"Enter HTML template code here... Use tags from the left sidebar or paste your HTML design.\"\n class=\"template-html-editor tw-w-full tw-h-full tw-p-3 tw-border tw-border-gray-300 tw-rounded-md tw-font-mono tw-text-xs tw-leading-relaxed tw-resize-none focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-blue-500 focus:tw-border-blue-500 tw-bg-white tw-text-gray-900\"\n spellcheck=\"false\"></textarea>\n </form>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Live Preview -->\n <div class=\"tw-col-span-12 lg:tw-col-span-4 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-w-0\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">Live Preview</h6>\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-select\n formControlName=\"preview_type\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}]\"\n size=\"xs\"\n class=\"tw-w-24\">\n </cide-ele-select>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400\" title=\"Auto-refreshes on template change\">sync</cide-ele-icon>\n </div>\n </div>\n </div>\n \n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4 tw-bg-gray-50\">\n <div class=\"tw-bg-white tw-shadow-sm tw-rounded tw-p-4 tw-min-h-full\" [innerHTML]=\"previewHtml()\"></div>\n </div>\n </div>\n\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n", styles: [":host{display:block;height:100%;width:100%;max-width:100vw;overflow:hidden}:host .template-html-editor{height:100%!important;min-height:400px;resize:none;font-family:Courier New,Monaco,Consolas,Menlo,monospace;font-size:13px;line-height:1.6;tab-size:2;-moz-tab-size:2;white-space:pre;overflow-wrap:normal;overflow-x:auto;overflow-y:auto;box-sizing:border-box;width:100%;max-width:100%}:host .template-html-editor::placeholder{color:#9ca3af;font-style:italic}:host .template-html-editor:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}:host .tw-grid{height:100%;max-width:100%;overflow:hidden}:host .tw-overflow-hidden{min-height:0;max-width:100%;overflow:hidden}:host .tw-flex-col{min-height:0;max-width:100%}:host [class*=tw-col-span]{display:flex;flex-direction:column;min-height:0;min-width:0;max-width:100%;overflow:hidden}:host *{max-width:100%;box-sizing:border-box}button[type=button]:hover{transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}button[type=button]:active{transform:translateY(0)}[innerHTML] img{max-width:100%;height:auto}[innerHTML] table{width:100%;border-collapse:collapse}[innerHTML] *{max-width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
6208
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: TemplateDesignerComponent, isStandalone: true, selector: "cide-receipt-template-designer", inputs: { shared_wrapper_setup_param: { classPropertyName: "shared_wrapper_setup_param", publicName: "shared_wrapper_setup_param", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "htmlEditorRef", first: true, predicate: ["htmlEditor"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<!-- Receipt Template Designer -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"shared_wrapper_setup_param()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions class=\"tw-flex tw-items-center tw-gap-2\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"loadTemplates()\" leftIcon=\"folder_open\">\n Load Template\n </button>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"saveTemplate()\" leftIcon=\"save\"\n [disabled]=\"saving() || templateForm.invalid\" [loading]=\"saving()\">\n Save Template\n </button>\n </div>\n\n <!-- Main Content - Three Column Layout -->\n <div class=\"tw-w-full tw-h-full tw-overflow-hidden tw-flex tw-flex-col\" style=\"height: calc(100vh - 120px); max-width: 100vw;\">\n <div class=\"tw-grid tw-grid-cols-12 tw-gap-3 tw-flex-1 tw-min-h-0 tw-p-3\">\n \n <!-- Left Sidebar - Tag Categories & Tags -->\n <div class=\"tw-col-span-12 lg:tw-col-span-3 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden tw-flex tw-flex-col tw-min-w-0 tw-h-full\">\n <!-- Tag Categories Header -->\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2\">Available Tags</h6>\n <form [formGroup]=\"templateForm\">\n <cide-ele-input\n formControlName=\"tag_search\"\n placeholder=\"Search tags...\"\n size=\"sm\"\n leadingIcon=\"search\">\n </cide-ele-input>\n </form>\n </div>\n\n <!-- Category Tabs -->\n <div class=\"tw-flex tw-flex-wrap tw-gap-1 tw-p-2 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-overflow-x-auto\">\n @for (category of tagCategories; track category.id) {\n <button\n type=\"button\"\n class=\"tw-px-2 tw-py-1 tw-text-xs tw-font-medium tw-rounded tw-transition-colors tw-whitespace-nowrap\"\n [class.tw-bg-blue-100]=\"activeCategory() === category.id\"\n [class.tw-text-blue-700]=\"activeCategory() === category.id\"\n [class.tw-bg-gray-100]=\"activeCategory() !== category.id\"\n [class.tw-text-gray-700]=\"activeCategory() !== category.id\"\n (click)=\"onCategoryChange(category.id)\"\n [title]=\"category.name\">\n <cide-ele-icon class=\"tw-w-3 tw-h-3 tw-inline-block tw-mr-1\">{{ category.icon }}</cide-ele-icon>\n <span class=\"tw-hidden sm:tw-inline\">{{ category.name }}</span>\n </button>\n }\n </div>\n\n <!-- Tags List -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-2 tw-min-h-0\">\n @if (filteredTags().length > 0) {\n <div class=\"tw-space-y-1\">\n @for (tag of filteredTags(); track tag.code) {\n <button\n type=\"button\"\n class=\"tw-w-full tw-text-left tw-p-2 tw-rounded tw-border tw-border-gray-200 tw-bg-white hover:tw-bg-blue-50 hover:tw-border-blue-300 tw-transition-colors tw-cursor-pointer tw-group\"\n (click)=\"insertTag(tag)\"\n [title]=\"tag.description\">\n <div class=\"tw-flex tw-items-start tw-justify-between tw-gap-2\">\n <div class=\"tw-flex-1 tw-min-w-0\">\n <code class=\"tw-text-xs tw-font-mono tw-text-blue-600 tw-font-semibold tw-block tw-break-all\">\n {{ tag.code }}\n </code>\n <span class=\"tw-text-xs tw-text-gray-600 tw-block tw-mt-1\">{{ tag.description }}</span>\n @if (tag.example) {\n <span class=\"tw-text-xs tw-text-gray-400 tw-block tw-mt-0.5\">e.g., {{ tag.example }}</span>\n }\n </div>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400 group-hover:tw-text-blue-600 tw-flex-shrink-0 tw-mt-0.5\">add_circle</cide-ele-icon>\n </div>\n </button>\n }\n </div>\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-mx-auto tw-mb-2 tw-text-gray-400\">search_off</cide-ele-icon>\n <p class=\"tw-text-xs\">No tags found</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Middle Column - HTML Editor -->\n <div class=\"tw-col-span-12 lg:tw-col-span-5 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-4\">Template Configuration</h6>\n \n <form [formGroup]=\"templateForm\" class=\"tw-space-y-3\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input\n label=\"Template Name *\"\n formControlName=\"template_name\"\n placeholder=\"e.g., Standard Receipt\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input\n label=\"Template Code *\"\n formControlName=\"template_code\"\n placeholder=\"e.g., STD_RECEIPT_01\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-select\n label=\"Template Type *\"\n formControlName=\"template_type\"\n [options]=\"[{value: 'PAYMENT', label: 'Payment Receipt'}, {value: 'REFUND', label: 'Refund Receipt'}, {value: 'PROVISIONAL', label: 'Provisional Receipt'}]\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-select\n label=\"Template For\"\n formControlName=\"template_for\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}, {value: 'BOTH', label: 'Both'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"is_default\" type=\"checkbox\" size=\"sm\"></cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Set as Default Template</span>\n </div>\n </form>\n </div>\n\n <div class=\"tw-flex-1 tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">HTML Template *</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">Click tags on left to insert or paste HTML here</span>\n </div>\n </div>\n <div class=\"tw-flex-1 tw-p-3 tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <form [formGroup]=\"templateForm\" class=\"tw-h-full\">\n <textarea\n #htmlEditor\n formControlName=\"template_html\"\n placeholder=\"Enter HTML template code here... Use tags from the left sidebar or paste your HTML design.\"\n class=\"template-html-editor tw-w-full tw-h-full tw-p-3 tw-border tw-border-gray-300 tw-rounded-md tw-font-mono tw-text-xs tw-leading-relaxed tw-resize-none focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-blue-500 focus:tw-border-blue-500 tw-bg-white tw-text-gray-900\"\n spellcheck=\"false\"></textarea>\n </form>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Live Preview -->\n <div class=\"tw-col-span-12 lg:tw-col-span-4 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">Live Preview</h6>\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-select\n formControlName=\"preview_type\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}]\"\n size=\"xs\"\n class=\"tw-w-24\">\n </cide-ele-select>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400\" title=\"Auto-refreshes on template change\">sync</cide-ele-icon>\n </div>\n </div>\n </div>\n \n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4 tw-bg-gray-50 tw-min-h-0\">\n <div class=\"tw-bg-white tw-shadow-sm tw-rounded tw-p-4\" [innerHTML]=\"previewHtml()\"></div>\n </div>\n </div>\n\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n", styles: [":host{display:flex;flex-direction:column;height:100%;width:100%;max-width:100vw;overflow:hidden}:host .template-html-editor{height:100%!important;min-height:0;resize:none;font-family:Courier New,Monaco,Consolas,Menlo,monospace;font-size:13px;line-height:1.6;tab-size:2;-moz-tab-size:2;white-space:pre;overflow-wrap:normal;overflow-x:auto;overflow-y:auto;box-sizing:border-box;width:100%;max-width:100%}:host .template-html-editor::placeholder{color:#9ca3af;font-style:italic}:host .template-html-editor:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}:host .tw-grid{height:100%;max-width:100%;overflow:hidden;min-height:0}:host .tw-overflow-hidden{min-height:0;max-width:100%;overflow:hidden}:host .tw-flex-col{min-height:0;max-width:100%;height:100%}:host [class*=tw-col-span]{display:flex;flex-direction:column;min-height:0;min-width:0;max-width:100%;overflow:hidden;height:100%}:host *{max-width:100%;box-sizing:border-box}:host [breadcrumb-actions]{display:flex;align-items:center;gap:.5rem;flex-wrap:nowrap}button[type=button]:hover{transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}button[type=button]:active{transform:translateY(0)}[innerHTML] img{max-width:100%;height:auto}[innerHTML] table{width:100%;border-collapse:collapse}[innerHTML] *{max-width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "component", type: CideSelectComponent, selector: "cide-ele-select", inputs: ["label", "labelHide", "placeholder", "helperText", "errorText", "required", "disabled", "id", "size", "fill", "labelPlacement", "labelDir", "leadingIcon", "trailingIcon", "clearInput", "options", "multiple", "searchable", "showSearchInput", "loading", "valueKey", "labelKey", "treeView"], outputs: ["ngModelChange", "change", "searchChange"] }, { kind: "component", type: CideLytSharedWrapperComponent, selector: "cide-lyt-shared-wrapper", inputs: ["shared_wrapper_setup_param", "breadcrumb_data"] }] });
6200
6209
  }
6201
6210
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: TemplateDesignerComponent, decorators: [{
6202
6211
  type: Component,
@@ -6208,7 +6217,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
6208
6217
  CideIconComponent,
6209
6218
  CideSelectComponent,
6210
6219
  CideLytSharedWrapperComponent
6211
- ], template: "<!-- Receipt Template Designer -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"shared_wrapper_setup_param()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions>\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"loadTemplates()\" leftIcon=\"folder_open\">\n Load Template\n </button>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"saveTemplate()\" leftIcon=\"save\"\n [disabled]=\"saving() || templateForm.invalid\" [loading]=\"saving()\">\n Save Template\n </button>\n </div>\n\n <!-- Main Content - Three Column Layout -->\n <div class=\"tw-w-full tw-h-full tw-overflow-hidden\" style=\"height: calc(100vh - 80px); max-width: 100vw;\">\n <div class=\"tw-grid tw-grid-cols-12 tw-gap-3 tw-h-full tw-min-h-0 tw-p-3\">\n \n <!-- Left Sidebar - Tag Categories & Tags -->\n <div class=\"tw-col-span-12 lg:tw-col-span-3 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden tw-flex tw-flex-col tw-min-w-0\">\n <!-- Tag Categories Header -->\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2\">Available Tags</h6>\n <form [formGroup]=\"templateForm\">\n <cide-ele-input\n formControlName=\"tag_search\"\n placeholder=\"Search tags...\"\n size=\"sm\"\n leadingIcon=\"search\">\n </cide-ele-input>\n </form>\n </div>\n\n <!-- Category Tabs -->\n <div class=\"tw-flex tw-flex-wrap tw-gap-1 tw-p-2 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-overflow-x-auto\">\n @for (category of tagCategories; track category.id) {\n <button\n type=\"button\"\n class=\"tw-px-2 tw-py-1 tw-text-xs tw-font-medium tw-rounded tw-transition-colors tw-whitespace-nowrap\"\n [class.tw-bg-blue-100]=\"activeCategory() === category.id\"\n [class.tw-text-blue-700]=\"activeCategory() === category.id\"\n [class.tw-bg-gray-100]=\"activeCategory() !== category.id\"\n [class.tw-text-gray-700]=\"activeCategory() !== category.id\"\n (click)=\"onCategoryChange(category.id)\"\n [title]=\"category.name\">\n <cide-ele-icon class=\"tw-w-3 tw-h-3 tw-inline-block tw-mr-1\">{{ category.icon }}</cide-ele-icon>\n <span class=\"tw-hidden sm:tw-inline\">{{ category.name }}</span>\n </button>\n }\n </div>\n\n <!-- Tags List -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-2\">\n @if (filteredTags().length > 0) {\n <div class=\"tw-space-y-1\">\n @for (tag of filteredTags(); track tag.code) {\n <button\n type=\"button\"\n class=\"tw-w-full tw-text-left tw-p-2 tw-rounded tw-border tw-border-gray-200 tw-bg-white hover:tw-bg-blue-50 hover:tw-border-blue-300 tw-transition-colors tw-cursor-pointer tw-group\"\n (click)=\"insertTag(tag)\"\n [title]=\"tag.description\">\n <div class=\"tw-flex tw-items-start tw-justify-between tw-gap-2\">\n <div class=\"tw-flex-1 tw-min-w-0\">\n <code class=\"tw-text-xs tw-font-mono tw-text-blue-600 tw-font-semibold tw-block tw-break-all\">\n {{ tag.code }}\n </code>\n <span class=\"tw-text-xs tw-text-gray-600 tw-block tw-mt-1\">{{ tag.description }}</span>\n @if (tag.example) {\n <span class=\"tw-text-xs tw-text-gray-400 tw-block tw-mt-0.5\">e.g., {{ tag.example }}</span>\n }\n </div>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400 group-hover:tw-text-blue-600 tw-flex-shrink-0 tw-mt-0.5\">add_circle</cide-ele-icon>\n </div>\n </button>\n }\n </div>\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-mx-auto tw-mb-2 tw-text-gray-400\">search_off</cide-ele-icon>\n <p class=\"tw-text-xs\">No tags found</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Middle Column - HTML Editor -->\n <div class=\"tw-col-span-12 lg:tw-col-span-5 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-min-w-0\">\n <div class=\"tw-p-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-4\">Template Configuration</h6>\n \n <form [formGroup]=\"templateForm\" class=\"tw-space-y-3\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input\n label=\"Template Name *\"\n formControlName=\"template_name\"\n placeholder=\"e.g., Standard Receipt\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input\n label=\"Template Code *\"\n formControlName=\"template_code\"\n placeholder=\"e.g., STD_RECEIPT_01\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-select\n label=\"Template Type *\"\n formControlName=\"template_type\"\n [options]=\"[{value: 'PAYMENT', label: 'Payment Receipt'}, {value: 'REFUND', label: 'Refund Receipt'}, {value: 'PROVISIONAL', label: 'Provisional Receipt'}]\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-select\n label=\"Template For\"\n formControlName=\"template_for\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}, {value: 'BOTH', label: 'Both'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"is_default\" type=\"checkbox\" size=\"sm\"></cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Set as Default Template</span>\n </div>\n </form>\n </div>\n\n <div class=\"tw-flex-1 tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">HTML Template *</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">Click tags on left to insert or paste HTML here</span>\n </div>\n </div>\n <div class=\"tw-flex-1 tw-p-3 tw-overflow-hidden tw-min-h-0\">\n <form [formGroup]=\"templateForm\">\n <textarea\n #htmlEditor\n formControlName=\"template_html\"\n placeholder=\"Enter HTML template code here... Use tags from the left sidebar or paste your HTML design.\"\n class=\"template-html-editor tw-w-full tw-h-full tw-p-3 tw-border tw-border-gray-300 tw-rounded-md tw-font-mono tw-text-xs tw-leading-relaxed tw-resize-none focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-blue-500 focus:tw-border-blue-500 tw-bg-white tw-text-gray-900\"\n spellcheck=\"false\"></textarea>\n </form>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Live Preview -->\n <div class=\"tw-col-span-12 lg:tw-col-span-4 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-w-0\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">Live Preview</h6>\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-select\n formControlName=\"preview_type\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}]\"\n size=\"xs\"\n class=\"tw-w-24\">\n </cide-ele-select>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400\" title=\"Auto-refreshes on template change\">sync</cide-ele-icon>\n </div>\n </div>\n </div>\n \n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4 tw-bg-gray-50\">\n <div class=\"tw-bg-white tw-shadow-sm tw-rounded tw-p-4 tw-min-h-full\" [innerHTML]=\"previewHtml()\"></div>\n </div>\n </div>\n\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n", styles: [":host{display:block;height:100%;width:100%;max-width:100vw;overflow:hidden}:host .template-html-editor{height:100%!important;min-height:400px;resize:none;font-family:Courier New,Monaco,Consolas,Menlo,monospace;font-size:13px;line-height:1.6;tab-size:2;-moz-tab-size:2;white-space:pre;overflow-wrap:normal;overflow-x:auto;overflow-y:auto;box-sizing:border-box;width:100%;max-width:100%}:host .template-html-editor::placeholder{color:#9ca3af;font-style:italic}:host .template-html-editor:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}:host .tw-grid{height:100%;max-width:100%;overflow:hidden}:host .tw-overflow-hidden{min-height:0;max-width:100%;overflow:hidden}:host .tw-flex-col{min-height:0;max-width:100%}:host [class*=tw-col-span]{display:flex;flex-direction:column;min-height:0;min-width:0;max-width:100%;overflow:hidden}:host *{max-width:100%;box-sizing:border-box}button[type=button]:hover{transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}button[type=button]:active{transform:translateY(0)}[innerHTML] img{max-width:100%;height:auto}[innerHTML] table{width:100%;border-collapse:collapse}[innerHTML] *{max-width:100%}\n"] }]
6220
+ ], template: "<!-- Receipt Template Designer -->\n<cide-lyt-shared-wrapper [shared_wrapper_setup_param]=\"shared_wrapper_setup_param()\">\n \n <!-- Action Buttons in Breadcrumb Area -->\n <div breadcrumb-actions class=\"tw-flex tw-items-center tw-gap-2\">\n <button cideEleButton type=\"button\" variant=\"secondary\" size=\"sm\" (click)=\"loadTemplates()\" leftIcon=\"folder_open\">\n Load Template\n </button>\n <button cideEleButton type=\"button\" variant=\"primary\" size=\"sm\" (click)=\"saveTemplate()\" leftIcon=\"save\"\n [disabled]=\"saving() || templateForm.invalid\" [loading]=\"saving()\">\n Save Template\n </button>\n </div>\n\n <!-- Main Content - Three Column Layout -->\n <div class=\"tw-w-full tw-h-full tw-overflow-hidden tw-flex tw-flex-col\" style=\"height: calc(100vh - 120px); max-width: 100vw;\">\n <div class=\"tw-grid tw-grid-cols-12 tw-gap-3 tw-flex-1 tw-min-h-0 tw-p-3\">\n \n <!-- Left Sidebar - Tag Categories & Tags -->\n <div class=\"tw-col-span-12 lg:tw-col-span-3 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-overflow-hidden tw-flex tw-flex-col tw-min-w-0 tw-h-full\">\n <!-- Tag Categories Header -->\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2\">Available Tags</h6>\n <form [formGroup]=\"templateForm\">\n <cide-ele-input\n formControlName=\"tag_search\"\n placeholder=\"Search tags...\"\n size=\"sm\"\n leadingIcon=\"search\">\n </cide-ele-input>\n </form>\n </div>\n\n <!-- Category Tabs -->\n <div class=\"tw-flex tw-flex-wrap tw-gap-1 tw-p-2 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-overflow-x-auto\">\n @for (category of tagCategories; track category.id) {\n <button\n type=\"button\"\n class=\"tw-px-2 tw-py-1 tw-text-xs tw-font-medium tw-rounded tw-transition-colors tw-whitespace-nowrap\"\n [class.tw-bg-blue-100]=\"activeCategory() === category.id\"\n [class.tw-text-blue-700]=\"activeCategory() === category.id\"\n [class.tw-bg-gray-100]=\"activeCategory() !== category.id\"\n [class.tw-text-gray-700]=\"activeCategory() !== category.id\"\n (click)=\"onCategoryChange(category.id)\"\n [title]=\"category.name\">\n <cide-ele-icon class=\"tw-w-3 tw-h-3 tw-inline-block tw-mr-1\">{{ category.icon }}</cide-ele-icon>\n <span class=\"tw-hidden sm:tw-inline\">{{ category.name }}</span>\n </button>\n }\n </div>\n\n <!-- Tags List -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-2 tw-min-h-0\">\n @if (filteredTags().length > 0) {\n <div class=\"tw-space-y-1\">\n @for (tag of filteredTags(); track tag.code) {\n <button\n type=\"button\"\n class=\"tw-w-full tw-text-left tw-p-2 tw-rounded tw-border tw-border-gray-200 tw-bg-white hover:tw-bg-blue-50 hover:tw-border-blue-300 tw-transition-colors tw-cursor-pointer tw-group\"\n (click)=\"insertTag(tag)\"\n [title]=\"tag.description\">\n <div class=\"tw-flex tw-items-start tw-justify-between tw-gap-2\">\n <div class=\"tw-flex-1 tw-min-w-0\">\n <code class=\"tw-text-xs tw-font-mono tw-text-blue-600 tw-font-semibold tw-block tw-break-all\">\n {{ tag.code }}\n </code>\n <span class=\"tw-text-xs tw-text-gray-600 tw-block tw-mt-1\">{{ tag.description }}</span>\n @if (tag.example) {\n <span class=\"tw-text-xs tw-text-gray-400 tw-block tw-mt-0.5\">e.g., {{ tag.example }}</span>\n }\n </div>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400 group-hover:tw-text-blue-600 tw-flex-shrink-0 tw-mt-0.5\">add_circle</cide-ele-icon>\n </div>\n </button>\n }\n </div>\n } @else {\n <div class=\"tw-text-center tw-py-8 tw-text-gray-500\">\n <cide-ele-icon class=\"tw-w-8 tw-h-8 tw-mx-auto tw-mb-2 tw-text-gray-400\">search_off</cide-ele-icon>\n <p class=\"tw-text-xs\">No tags found</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Middle Column - HTML Editor -->\n <div class=\"tw-col-span-12 lg:tw-col-span-5 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-4 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-4\">Template Configuration</h6>\n \n <form [formGroup]=\"templateForm\" class=\"tw-space-y-3\">\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-input\n label=\"Template Name *\"\n formControlName=\"template_name\"\n placeholder=\"e.g., Standard Receipt\"\n size=\"sm\">\n </cide-ele-input>\n\n <cide-ele-input\n label=\"Template Code *\"\n formControlName=\"template_code\"\n placeholder=\"e.g., STD_RECEIPT_01\"\n size=\"sm\">\n </cide-ele-input>\n </div>\n\n <div class=\"tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-3\">\n <cide-ele-select\n label=\"Template Type *\"\n formControlName=\"template_type\"\n [options]=\"[{value: 'PAYMENT', label: 'Payment Receipt'}, {value: 'REFUND', label: 'Refund Receipt'}, {value: 'PROVISIONAL', label: 'Provisional Receipt'}]\"\n size=\"sm\">\n </cide-ele-select>\n\n <cide-ele-select\n label=\"Template For\"\n formControlName=\"template_for\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}, {value: 'BOTH', label: 'Both'}]\"\n size=\"sm\">\n </cide-ele-select>\n </div>\n\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-p-2 tw-bg-gray-50 tw-rounded\">\n <cide-ele-input formControlName=\"is_default\" type=\"checkbox\" size=\"sm\"></cide-ele-input>\n <span class=\"tw-text-xs tw-text-gray-700\">Set as Default Template</span>\n </div>\n </form>\n </div>\n\n <div class=\"tw-flex-1 tw-flex tw-flex-col tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50 tw-flex-shrink-0\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">HTML Template *</h6>\n <span class=\"tw-text-xs tw-text-gray-500\">Click tags on left to insert or paste HTML here</span>\n </div>\n </div>\n <div class=\"tw-flex-1 tw-p-3 tw-overflow-hidden tw-min-h-0 tw-h-full\">\n <form [formGroup]=\"templateForm\" class=\"tw-h-full\">\n <textarea\n #htmlEditor\n formControlName=\"template_html\"\n placeholder=\"Enter HTML template code here... Use tags from the left sidebar or paste your HTML design.\"\n class=\"template-html-editor tw-w-full tw-h-full tw-p-3 tw-border tw-border-gray-300 tw-rounded-md tw-font-mono tw-text-xs tw-leading-relaxed tw-resize-none focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-blue-500 focus:tw-border-blue-500 tw-bg-white tw-text-gray-900\"\n spellcheck=\"false\"></textarea>\n </form>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Live Preview -->\n <div class=\"tw-col-span-12 lg:tw-col-span-4 tw-bg-white tw-rounded-lg tw-border tw-border-gray-200 tw-shadow-sm tw-flex tw-flex-col tw-overflow-hidden tw-min-w-0 tw-h-full\">\n <div class=\"tw-p-3 tw-border-b tw-border-gray-200 tw-bg-gray-50\">\n <div class=\"tw-flex tw-items-center tw-justify-between\">\n <h6 class=\"tw-text-sm tw-font-semibold tw-text-gray-900\">Live Preview</h6>\n <div class=\"tw-flex tw-items-center tw-gap-2\">\n <cide-ele-select\n formControlName=\"preview_type\"\n [options]=\"[{value: 'STUDENT', label: 'Student'}, {value: 'OFFICE', label: 'Office'}]\"\n size=\"xs\"\n class=\"tw-w-24\">\n </cide-ele-select>\n <cide-ele-icon class=\"tw-w-4 tw-h-4 tw-text-gray-400\" title=\"Auto-refreshes on template change\">sync</cide-ele-icon>\n </div>\n </div>\n </div>\n \n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4 tw-bg-gray-50 tw-min-h-0\">\n <div class=\"tw-bg-white tw-shadow-sm tw-rounded tw-p-4\" [innerHTML]=\"previewHtml()\"></div>\n </div>\n </div>\n\n </div>\n </div>\n</cide-lyt-shared-wrapper>\n\n", styles: [":host{display:flex;flex-direction:column;height:100%;width:100%;max-width:100vw;overflow:hidden}:host .template-html-editor{height:100%!important;min-height:0;resize:none;font-family:Courier New,Monaco,Consolas,Menlo,monospace;font-size:13px;line-height:1.6;tab-size:2;-moz-tab-size:2;white-space:pre;overflow-wrap:normal;overflow-x:auto;overflow-y:auto;box-sizing:border-box;width:100%;max-width:100%}:host .template-html-editor::placeholder{color:#9ca3af;font-style:italic}:host .template-html-editor:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}:host .tw-grid{height:100%;max-width:100%;overflow:hidden;min-height:0}:host .tw-overflow-hidden{min-height:0;max-width:100%;overflow:hidden}:host .tw-flex-col{min-height:0;max-width:100%;height:100%}:host [class*=tw-col-span]{display:flex;flex-direction:column;min-height:0;min-width:0;max-width:100%;overflow:hidden;height:100%}:host *{max-width:100%;box-sizing:border-box}:host [breadcrumb-actions]{display:flex;align-items:center;gap:.5rem;flex-wrap:nowrap}button[type=button]:hover{transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}button[type=button]:active{transform:translateY(0)}[innerHTML] img{max-width:100%;height:auto}[innerHTML] table{width:100%;border-collapse:collapse}[innerHTML] *{max-width:100%}\n"] }]
6212
6221
  }], ctorParameters: () => [], propDecorators: { htmlEditorRef: [{
6213
6222
  type: ViewChild,
6214
6223
  args: ['htmlEditor', { static: false }]
@@ -7576,428 +7585,426 @@ class FeeDetailsViewerComponent {
7576
7585
  this.closed.emit();
7577
7586
  }
7578
7587
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeDetailsViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7579
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: FeeDetailsViewerComponent, isStandalone: true, selector: "cide-fee-details-viewer", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, studentId: { classPropertyName: "studentId", publicName: "studentId", isSignal: true, isRequired: false, transformFunction: null }, feeId: { classPropertyName: "feeId", publicName: "feeId", isSignal: true, isRequired: false, transformFunction: null }, feeData: { classPropertyName: "feeData", publicName: "feeData", isSignal: true, isRequired: false, transformFunction: null }, assignmentDate: { classPropertyName: "assignmentDate", publicName: "assignmentDate", isSignal: true, isRequired: false, transformFunction: null }, discount: { classPropertyName: "discount", publicName: "discount", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: `
7580
- <div class="tw-p-4 tw-overflow-y-auto tw-h-full">
7581
- @if (loading()) {
7582
- <div class="tw-text-center tw-py-12">
7583
- <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-gray-400 tw-animate-spin tw-mx-auto tw-mb-2">refresh</cide-ele-icon>
7584
- <span class="tw-text-sm tw-text-gray-500">Loading fee details...</span>
7585
- </div>
7586
- } @else if (error()) {
7587
- <div class="tw-text-center tw-py-12">
7588
- <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-red-400 tw-mx-auto tw-mb-2">error</cide-ele-icon>
7589
- <p class="tw-text-sm tw-text-red-600">{{ error() }}</p>
7590
- </div>
7591
- } @else {
7592
- @if (feeDetails(); as details) {
7593
- <div class="tw-space-y-4 tw-text-sm">
7594
- <!-- Basic Information -->
7595
- <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7596
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Basic Information</h4>
7597
- <div class="tw-grid tw-grid-cols-2 tw-gap-3">
7598
- <div>
7599
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Fee Name:</span>
7600
- <span class="tw-font-medium tw-text-gray-900">{{ details.name }}</span>
7601
- </div>
7602
- <div>
7603
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Fee Code:</span>
7604
- <span class="tw-text-gray-900">{{ details.itemCode }}</span>
7605
- </div>
7606
- <div>
7607
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Category:</span>
7608
- <span class="tw-text-gray-900">{{ details.category }}</span>
7609
- </div>
7610
- <div>
7611
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Structure:</span>
7612
- <span class="tw-text-gray-900">{{ details.structureName }}</span>
7613
- </div>
7614
- </div>
7615
- @if (details.description) {
7616
- <div class="tw-mt-3 tw-pt-3 tw-border-t tw-border-gray-200">
7617
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Description:</span>
7618
- <p class="tw-text-gray-900 tw-text-sm">{{ details.description }}</p>
7619
- </div>
7620
- }
7621
- </div>
7622
-
7623
- <!-- Amount Breakdown -->
7624
- <div class="tw-bg-blue-50 tw-rounded-lg tw-p-3 tw-border tw-border-blue-200">
7625
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Amount Breakdown</h4>
7626
- <div class="tw-space-y-2">
7627
- <div class="tw-flex tw-justify-between tw-items-center">
7628
- <span class="tw-text-gray-600">Original Amount:</span>
7629
- <span class="tw-font-medium tw-text-gray-900">{{ details.amount | currency }}</span>
7630
- </div>
7631
- @if (details.discount > 0) {
7632
- <div class="tw-flex tw-justify-between tw-items-center">
7633
- <span class="tw-text-gray-600">Discount Applied:</span>
7634
- <span class="tw-font-medium tw-text-blue-600">-{{ details.discount | currency }}</span>
7635
- </div>
7636
- }
7637
- @if (details.taxApplicable && details.taxPercentage > 0) {
7638
- <div class="tw-flex tw-justify-between tw-items-center">
7639
- <span class="tw-text-gray-600">Tax ({{ details.taxPercentage }}%):</span>
7640
- <span class="tw-font-medium tw-text-gray-900">{{ (details.finalAmount * details.taxPercentage) / 100 | currency }}</span>
7641
- </div>
7642
- }
7643
- <div class="tw-flex tw-justify-between tw-items-center tw-pt-2 tw-border-t tw-border-blue-200">
7644
- <span class="tw-font-semibold tw-text-gray-900">Final Amount:</span>
7645
- <span class="tw-font-bold tw-text-green-600 tw-text-base">{{ details.finalAmount | currency }}</span>
7646
- </div>
7647
- </div>
7648
- </div>
7649
-
7650
- <!-- Installment Breakdown -->
7651
- @if (details.installmentAllowed && details.installments && details.installments.length > 1) {
7652
- <div class="tw-bg-purple-50 tw-rounded-lg tw-p-3 tw-border tw-border-purple-200">
7653
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Installment Plan</h4>
7654
- <div class="tw-mb-2 tw-text-xs tw-text-gray-600">
7655
- Total Amount: <span class="tw-font-semibold">{{ details.finalAmount | currency }}</span>
7656
- divided into <span class="tw-font-semibold">{{ details.installmentCount }}</span> installments
7657
- </div>
7658
- <div class="tw-overflow-x-auto">
7659
- <table class="tw-min-w-full tw-divide-y tw-divide-purple-200">
7660
- <thead class="tw-bg-purple-100">
7661
- <tr>
7662
- <th class="tw-px-3 tw-py-2 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700">Installment #</th>
7663
- <th class="tw-px-3 tw-py-2 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700">Amount</th>
7664
- <th class="tw-px-3 tw-py-2 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700">Due Date</th>
7665
- <th class="tw-px-3 tw-py-2 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700">Days from Assignment</th>
7666
- <th class="tw-px-3 tw-py-2 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700">Days from Previous</th>
7667
- </tr>
7668
- </thead>
7669
- <tbody class="tw-bg-white tw-divide-y tw-divide-purple-200">
7670
- @for (installment of details.installments; track installment.number) {
7671
- <tr>
7672
- <td class="tw-px-3 tw-py-2 tw-text-sm tw-text-gray-900 tw-font-medium">#{{ installment.number }}</td>
7673
- <td class="tw-px-3 tw-py-2 tw-text-sm tw-text-gray-900 tw-text-right tw-font-semibold">{{ installment.amount | currency }}</td>
7674
- <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600">{{ installment.dueDate || 'TBD' }}</td>
7675
- <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600 tw-text-center">
7676
- @if (installment.daysFromAssignment !== undefined) {
7677
- <span class="tw-font-medium">{{ installment.daysFromAssignment }} days</span>
7678
- } @else {
7679
- <span class="tw-text-gray-400">-</span>
7680
- }
7681
- </td>
7682
- <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600 tw-text-center">
7683
- @if (installment.daysFromPrevious !== undefined) {
7684
- <span class="tw-font-medium">{{ installment.daysFromPrevious }} days</span>
7685
- } @else {
7686
- <span class="tw-text-gray-400">-</span>
7687
- }
7688
- </td>
7689
- </tr>
7690
- }
7691
- </tbody>
7692
- <tfoot class="tw-bg-purple-100">
7693
- <tr>
7694
- <td class="tw-px-3 tw-py-2 tw-text-sm tw-font-bold tw-text-gray-900">Total:</td>
7695
- <td class="tw-px-3 tw-py-2 tw-text-sm tw-font-bold tw-text-green-600 tw-text-right">{{ details.finalAmount | currency }}</td>
7696
- <td colspan="3"></td>
7697
- </tr>
7698
- </tfoot>
7699
- </table>
7700
- </div>
7701
- </div>
7702
- } @else {
7703
- <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7704
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2">Payment Information</h4>
7705
- <div class="tw-space-y-1 tw-text-xs">
7706
- <div class="tw-flex tw-justify-between">
7707
- <span class="tw-text-gray-600">Payment Type:</span>
7708
- <span class="tw-font-medium tw-text-gray-900">One-time Payment</span>
7709
- </div>
7710
- <div class="tw-flex tw-justify-between">
7711
- <span class="tw-text-gray-600">Amount to Pay:</span>
7712
- <span class="tw-font-bold tw-text-green-600">{{ details.finalAmount | currency }}</span>
7713
- </div>
7714
- @if (details.installments && details.installments.length > 0 && details.installments[0].dueDate) {
7715
- <div class="tw-flex tw-justify-between">
7716
- <span class="tw-text-gray-600">Due Date:</span>
7717
- <span class="tw-font-medium tw-text-gray-900">{{ details.installments[0].dueDate }}</span>
7718
- </div>
7719
- }
7720
- @if (details.dueDateOffset > 0) {
7721
- <div class="tw-flex tw-justify-between">
7722
- <span class="tw-text-gray-600">Due Date Offset:</span>
7723
- <span class="tw-text-gray-900">{{ details.dueDateOffset }} days from assignment date</span>
7724
- </div>
7725
- }
7726
- @if (details.installments && details.installments.length > 0 && details.installments[0].daysFromAssignment) {
7727
- <div class="tw-flex tw-justify-between">
7728
- <span class="tw-text-gray-600">Days from Assignment:</span>
7729
- <span class="tw-text-gray-900">{{ details.installments[0].daysFromAssignment }} days</span>
7730
- </div>
7731
- }
7732
- </div>
7733
- </div>
7734
- }
7735
-
7736
- <!-- Fee Properties -->
7737
- <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7738
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Fee Properties</h4>
7739
- <div class="tw-grid tw-grid-cols-2 tw-gap-3">
7740
- <div>
7741
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Mandatory:</span>
7742
- <span class="tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium" [class]="details.isMandatory ? 'tw-bg-red-100 tw-text-red-800' : 'tw-bg-gray-100 tw-text-gray-800'">
7743
- {{ details.isMandatory ? 'Yes - Required' : 'No - Optional' }}
7744
- </span>
7745
- </div>
7746
- <div>
7747
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Refundable:</span>
7748
- <span class="tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium" [class]="details.isRefundable ? 'tw-bg-green-100 tw-text-green-800' : 'tw-bg-gray-100 tw-text-gray-800'">
7749
- {{ details.isRefundable ? 'Yes' : 'No' }}
7750
- </span>
7751
- </div>
7752
- <div>
7753
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Amount Editable:</span>
7754
- <span class="tw-text-gray-900 tw-text-sm">{{ details.isAmountEditable ? 'Yes' : 'No' }}</span>
7755
- </div>
7756
- @if (details.isAmountEditable && (details.minAmount || details.maxAmount)) {
7757
- <div>
7758
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Amount Range:</span>
7759
- <span class="tw-text-gray-900 tw-text-sm">
7760
- {{ details.minAmount ? (details.minAmount | currency) : 'No min' }} -
7761
- {{ details.maxAmount ? (details.maxAmount | currency) : 'No max' }}
7762
- </span>
7763
- </div>
7764
- }
7765
- @if (details.taxApplicable) {
7766
- <div>
7767
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Tax Applicable:</span>
7768
- <span class="tw-text-gray-900 tw-text-sm">{{ details.taxPercentage }}%</span>
7769
- </div>
7770
- }
7771
- @if (details.collectionStartOffset || details.collectionEndOffset) {
7772
- <div>
7773
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Collection Window:</span>
7774
- <span class="tw-text-gray-900 tw-text-sm">
7775
- Day {{ details.collectionStartOffset }} to Day {{ details.collectionEndOffset }}
7776
- </span>
7777
- </div>
7778
- }
7779
- </div>
7780
- </div>
7781
- </div>
7782
- }
7783
- }
7784
- </div>
7588
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: FeeDetailsViewerComponent, isStandalone: true, selector: "cide-fee-details-viewer", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, studentId: { classPropertyName: "studentId", publicName: "studentId", isSignal: true, isRequired: false, transformFunction: null }, feeId: { classPropertyName: "feeId", publicName: "feeId", isSignal: true, isRequired: false, transformFunction: null }, feeData: { classPropertyName: "feeData", publicName: "feeData", isSignal: true, isRequired: false, transformFunction: null }, assignmentDate: { classPropertyName: "assignmentDate", publicName: "assignmentDate", isSignal: true, isRequired: false, transformFunction: null }, discount: { classPropertyName: "discount", publicName: "discount", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: `
7589
+ <div class="tw-p-4 tw-overflow-y-auto tw-h-full">
7590
+ @if (loading()) {
7591
+ <div class="tw-text-center tw-py-12">
7592
+ <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-gray-400 tw-animate-spin tw-mx-auto tw-mb-2">refresh</cide-ele-icon>
7593
+ <span class="tw-text-sm tw-text-gray-500">Loading fee details...</span>
7594
+ </div>
7595
+ } @else if (error()) {
7596
+ <div class="tw-text-center tw-py-12">
7597
+ <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-red-400 tw-mx-auto tw-mb-2">error</cide-ele-icon>
7598
+ <p class="tw-text-sm tw-text-red-600">{{ error() }}</p>
7599
+ </div>
7600
+ } @else {
7601
+ @if (feeDetails(); as details) {
7602
+ <div class="tw-space-y-4 tw-text-sm">
7603
+ <!-- Basic Information -->
7604
+ <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7605
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Basic Information</h4>
7606
+ <div class="tw-grid tw-grid-cols-2 tw-gap-3">
7607
+ <div>
7608
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Fee Name:</span>
7609
+ <span class="tw-font-medium tw-text-gray-900">{{ details.name }}</span>
7610
+ </div>
7611
+ <div>
7612
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Fee Code:</span>
7613
+ <span class="tw-text-gray-900">{{ details.itemCode }}</span>
7614
+ </div>
7615
+ <div>
7616
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Category:</span>
7617
+ <span class="tw-text-gray-900">{{ details.category }}</span>
7618
+ </div>
7619
+ <div>
7620
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Structure:</span>
7621
+ <span class="tw-text-gray-900">{{ details.structureName }}</span>
7622
+ </div>
7623
+ </div>
7624
+ @if (details.description) {
7625
+ <div class="tw-mt-3 tw-pt-3 tw-border-t tw-border-gray-200">
7626
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Description:</span>
7627
+ <p class="tw-text-gray-900 tw-text-sm">{{ details.description }}</p>
7628
+ </div>
7629
+ }
7630
+ </div>
7631
+
7632
+ <!-- Amount Breakdown -->
7633
+ <div class="tw-bg-blue-50 tw-rounded-lg tw-p-3 tw-border tw-border-blue-200">
7634
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Amount Breakdown</h4>
7635
+ <div class="tw-space-y-2">
7636
+ <div class="tw-flex tw-justify-between tw-items-center">
7637
+ <span class="tw-text-gray-600">Original Amount:</span>
7638
+ <span class="tw-font-medium tw-text-gray-900">{{ details.amount | currency }}</span>
7639
+ </div>
7640
+ @if (details.discount > 0) {
7641
+ <div class="tw-flex tw-justify-between tw-items-center">
7642
+ <span class="tw-text-gray-600">Discount Applied:</span>
7643
+ <span class="tw-font-medium tw-text-blue-600">-{{ details.discount | currency }}</span>
7644
+ </div>
7645
+ }
7646
+ @if (details.taxApplicable && details.taxPercentage > 0) {
7647
+ <div class="tw-flex tw-justify-between tw-items-center">
7648
+ <span class="tw-text-gray-600">Tax ({{ details.taxPercentage }}%):</span>
7649
+ <span class="tw-font-medium tw-text-gray-900">{{ (details.finalAmount * details.taxPercentage) / 100 | currency }}</span>
7650
+ </div>
7651
+ }
7652
+ <div class="tw-flex tw-justify-between tw-items-center tw-pt-2 tw-border-t tw-border-blue-200">
7653
+ <span class="tw-font-semibold tw-text-gray-900">Final Amount:</span>
7654
+ <span class="tw-font-bold tw-text-green-600 tw-text-base">{{ details.finalAmount | currency }}</span>
7655
+ </div>
7656
+ </div>
7657
+ </div>
7658
+
7659
+ <!-- Installment Breakdown -->
7660
+ @if (details.installmentAllowed && details.installments && details.installments.length > 1) {
7661
+ <div class="tw-bg-purple-50 tw-rounded-lg tw-p-3 tw-border tw-border-purple-200">
7662
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Installment Plan</h4>
7663
+ <div class="tw-mb-2 tw-text-xs tw-text-gray-600">
7664
+ Total Amount: <span class="tw-font-semibold">{{ details.finalAmount | currency }}</span>
7665
+ divided into <span class="tw-font-semibold">{{ details.installmentCount }}</span> installments
7666
+ </div>
7667
+ <div class="tw-overflow-x-auto">
7668
+ <table class="tw-min-w-full tw-divide-y tw-divide-purple-200">
7669
+ <thead class="tw-bg-purple-100">
7670
+ <tr>
7671
+ <th class="tw-px-3 tw-py-2 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700">Installment #</th>
7672
+ <th class="tw-px-3 tw-py-2 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700">Amount</th>
7673
+ <th class="tw-px-3 tw-py-2 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700">Due Date</th>
7674
+ <th class="tw-px-3 tw-py-2 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700">Days from Assignment</th>
7675
+ <th class="tw-px-3 tw-py-2 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700">Days from Previous</th>
7676
+ </tr>
7677
+ </thead>
7678
+ <tbody class="tw-bg-white tw-divide-y tw-divide-purple-200">
7679
+ @for (installment of details.installments; track installment.number) {
7680
+ <tr>
7681
+ <td class="tw-px-3 tw-py-2 tw-text-sm tw-text-gray-900 tw-font-medium">#{{ installment.number }}</td>
7682
+ <td class="tw-px-3 tw-py-2 tw-text-sm tw-text-gray-900 tw-text-right tw-font-semibold">{{ installment.amount | currency }}</td>
7683
+ <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600">{{ installment.dueDate || 'TBD' }}</td>
7684
+ <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600 tw-text-center">
7685
+ @if (installment.daysFromAssignment !== undefined) {
7686
+ <span class="tw-font-medium">{{ installment.daysFromAssignment }} days</span>
7687
+ } @else {
7688
+ <span class="tw-text-gray-400">-</span>
7689
+ }
7690
+ </td>
7691
+ <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600 tw-text-center">
7692
+ @if (installment.daysFromPrevious !== undefined) {
7693
+ <span class="tw-font-medium">{{ installment.daysFromPrevious }} days</span>
7694
+ } @else {
7695
+ <span class="tw-text-gray-400">-</span>
7696
+ }
7697
+ </td>
7698
+ </tr>
7699
+ }
7700
+ </tbody>
7701
+ <tfoot class="tw-bg-purple-100">
7702
+ <tr>
7703
+ <td class="tw-px-3 tw-py-2 tw-text-sm tw-font-bold tw-text-gray-900">Total:</td>
7704
+ <td class="tw-px-3 tw-py-2 tw-text-sm tw-font-bold tw-text-green-600 tw-text-right">{{ details.finalAmount | currency }}</td>
7705
+ <td colspan="3"></td>
7706
+ </tr>
7707
+ </tfoot>
7708
+ </table>
7709
+ </div>
7710
+ </div>
7711
+ } @else {
7712
+ <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7713
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2">Payment Information</h4>
7714
+ <div class="tw-space-y-1 tw-text-xs">
7715
+ <div class="tw-flex tw-justify-between">
7716
+ <span class="tw-text-gray-600">Payment Type:</span>
7717
+ <span class="tw-font-medium tw-text-gray-900">One-time Payment</span>
7718
+ </div>
7719
+ <div class="tw-flex tw-justify-between">
7720
+ <span class="tw-text-gray-600">Amount to Pay:</span>
7721
+ <span class="tw-font-bold tw-text-green-600">{{ details.finalAmount | currency }}</span>
7722
+ </div>
7723
+ @if (details.installments && details.installments.length > 0 && details.installments[0].dueDate) {
7724
+ <div class="tw-flex tw-justify-between">
7725
+ <span class="tw-text-gray-600">Due Date:</span>
7726
+ <span class="tw-font-medium tw-text-gray-900">{{ details.installments[0].dueDate }}</span>
7727
+ </div>
7728
+ }
7729
+ @if (details.dueDateOffset > 0) {
7730
+ <div class="tw-flex tw-justify-between">
7731
+ <span class="tw-text-gray-600">Due Date Offset:</span>
7732
+ <span class="tw-text-gray-900">{{ details.dueDateOffset }} days from assignment date</span>
7733
+ </div>
7734
+ }
7735
+ @if (details.installments && details.installments.length > 0 && details.installments[0].daysFromAssignment) {
7736
+ <div class="tw-flex tw-justify-between">
7737
+ <span class="tw-text-gray-600">Days from Assignment:</span>
7738
+ <span class="tw-text-gray-900">{{ details.installments[0].daysFromAssignment }} days</span>
7739
+ </div>
7740
+ }
7741
+ </div>
7742
+ </div>
7743
+ }
7744
+
7745
+ <!-- Fee Properties -->
7746
+ <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7747
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Fee Properties</h4>
7748
+ <div class="tw-grid tw-grid-cols-2 tw-gap-3">
7749
+ <div>
7750
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Mandatory:</span>
7751
+ <span class="tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium" [class]="details.isMandatory ? 'tw-bg-red-100 tw-text-red-800' : 'tw-bg-gray-100 tw-text-gray-800'">
7752
+ {{ details.isMandatory ? 'Yes - Required' : 'No - Optional' }}
7753
+ </span>
7754
+ </div>
7755
+ <div>
7756
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Refundable:</span>
7757
+ <span class="tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium" [class]="details.isRefundable ? 'tw-bg-green-100 tw-text-green-800' : 'tw-bg-gray-100 tw-text-gray-800'">
7758
+ {{ details.isRefundable ? 'Yes' : 'No' }}
7759
+ </span>
7760
+ </div>
7761
+ <div>
7762
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Amount Editable:</span>
7763
+ <span class="tw-text-gray-900 tw-text-sm">{{ details.isAmountEditable ? 'Yes' : 'No' }}</span>
7764
+ </div>
7765
+ @if (details.isAmountEditable && (details.minAmount || details.maxAmount)) {
7766
+ <div>
7767
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Amount Range:</span>
7768
+ <span class="tw-text-gray-900 tw-text-sm">
7769
+ {{ details.minAmount ? (details.minAmount | currency) : 'No min' }} -
7770
+ {{ details.maxAmount ? (details.maxAmount | currency) : 'No max' }}
7771
+ </span>
7772
+ </div>
7773
+ }
7774
+ @if (details.taxApplicable) {
7775
+ <div>
7776
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Tax Applicable:</span>
7777
+ <span class="tw-text-gray-900 tw-text-sm">{{ details.taxPercentage }}%</span>
7778
+ </div>
7779
+ }
7780
+ @if (details.collectionStartOffset || details.collectionEndOffset) {
7781
+ <div>
7782
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Collection Window:</span>
7783
+ <span class="tw-text-gray-900 tw-text-sm">
7784
+ Day {{ details.collectionStartOffset }} to Day {{ details.collectionEndOffset }}
7785
+ </span>
7786
+ </div>
7787
+ }
7788
+ </div>
7789
+ </div>
7790
+ </div>
7791
+ }
7792
+ }
7793
+ </div>
7785
7794
  `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }] });
7786
7795
  }
7787
7796
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FeeDetailsViewerComponent, decorators: [{
7788
7797
  type: Component,
7789
7798
  args: [{ selector: 'cide-fee-details-viewer', standalone: true, imports: [
7790
7799
  CommonModule,
7791
- DatePipe,
7792
7800
  CideIconComponent,
7793
- CideEleButtonComponent,
7794
7801
  CurrencyPipe
7795
- ], template: `
7796
- <div class="tw-p-4 tw-overflow-y-auto tw-h-full">
7797
- @if (loading()) {
7798
- <div class="tw-text-center tw-py-12">
7799
- <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-gray-400 tw-animate-spin tw-mx-auto tw-mb-2">refresh</cide-ele-icon>
7800
- <span class="tw-text-sm tw-text-gray-500">Loading fee details...</span>
7801
- </div>
7802
- } @else if (error()) {
7803
- <div class="tw-text-center tw-py-12">
7804
- <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-red-400 tw-mx-auto tw-mb-2">error</cide-ele-icon>
7805
- <p class="tw-text-sm tw-text-red-600">{{ error() }}</p>
7806
- </div>
7807
- } @else {
7808
- @if (feeDetails(); as details) {
7809
- <div class="tw-space-y-4 tw-text-sm">
7810
- <!-- Basic Information -->
7811
- <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7812
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Basic Information</h4>
7813
- <div class="tw-grid tw-grid-cols-2 tw-gap-3">
7814
- <div>
7815
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Fee Name:</span>
7816
- <span class="tw-font-medium tw-text-gray-900">{{ details.name }}</span>
7817
- </div>
7818
- <div>
7819
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Fee Code:</span>
7820
- <span class="tw-text-gray-900">{{ details.itemCode }}</span>
7821
- </div>
7822
- <div>
7823
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Category:</span>
7824
- <span class="tw-text-gray-900">{{ details.category }}</span>
7825
- </div>
7826
- <div>
7827
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Structure:</span>
7828
- <span class="tw-text-gray-900">{{ details.structureName }}</span>
7829
- </div>
7830
- </div>
7831
- @if (details.description) {
7832
- <div class="tw-mt-3 tw-pt-3 tw-border-t tw-border-gray-200">
7833
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Description:</span>
7834
- <p class="tw-text-gray-900 tw-text-sm">{{ details.description }}</p>
7835
- </div>
7836
- }
7837
- </div>
7838
-
7839
- <!-- Amount Breakdown -->
7840
- <div class="tw-bg-blue-50 tw-rounded-lg tw-p-3 tw-border tw-border-blue-200">
7841
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Amount Breakdown</h4>
7842
- <div class="tw-space-y-2">
7843
- <div class="tw-flex tw-justify-between tw-items-center">
7844
- <span class="tw-text-gray-600">Original Amount:</span>
7845
- <span class="tw-font-medium tw-text-gray-900">{{ details.amount | currency }}</span>
7846
- </div>
7847
- @if (details.discount > 0) {
7848
- <div class="tw-flex tw-justify-between tw-items-center">
7849
- <span class="tw-text-gray-600">Discount Applied:</span>
7850
- <span class="tw-font-medium tw-text-blue-600">-{{ details.discount | currency }}</span>
7851
- </div>
7852
- }
7853
- @if (details.taxApplicable && details.taxPercentage > 0) {
7854
- <div class="tw-flex tw-justify-between tw-items-center">
7855
- <span class="tw-text-gray-600">Tax ({{ details.taxPercentage }}%):</span>
7856
- <span class="tw-font-medium tw-text-gray-900">{{ (details.finalAmount * details.taxPercentage) / 100 | currency }}</span>
7857
- </div>
7858
- }
7859
- <div class="tw-flex tw-justify-between tw-items-center tw-pt-2 tw-border-t tw-border-blue-200">
7860
- <span class="tw-font-semibold tw-text-gray-900">Final Amount:</span>
7861
- <span class="tw-font-bold tw-text-green-600 tw-text-base">{{ details.finalAmount | currency }}</span>
7862
- </div>
7863
- </div>
7864
- </div>
7865
-
7866
- <!-- Installment Breakdown -->
7867
- @if (details.installmentAllowed && details.installments && details.installments.length > 1) {
7868
- <div class="tw-bg-purple-50 tw-rounded-lg tw-p-3 tw-border tw-border-purple-200">
7869
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Installment Plan</h4>
7870
- <div class="tw-mb-2 tw-text-xs tw-text-gray-600">
7871
- Total Amount: <span class="tw-font-semibold">{{ details.finalAmount | currency }}</span>
7872
- divided into <span class="tw-font-semibold">{{ details.installmentCount }}</span> installments
7873
- </div>
7874
- <div class="tw-overflow-x-auto">
7875
- <table class="tw-min-w-full tw-divide-y tw-divide-purple-200">
7876
- <thead class="tw-bg-purple-100">
7877
- <tr>
7878
- <th class="tw-px-3 tw-py-2 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700">Installment #</th>
7879
- <th class="tw-px-3 tw-py-2 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700">Amount</th>
7880
- <th class="tw-px-3 tw-py-2 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700">Due Date</th>
7881
- <th class="tw-px-3 tw-py-2 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700">Days from Assignment</th>
7882
- <th class="tw-px-3 tw-py-2 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700">Days from Previous</th>
7883
- </tr>
7884
- </thead>
7885
- <tbody class="tw-bg-white tw-divide-y tw-divide-purple-200">
7886
- @for (installment of details.installments; track installment.number) {
7887
- <tr>
7888
- <td class="tw-px-3 tw-py-2 tw-text-sm tw-text-gray-900 tw-font-medium">#{{ installment.number }}</td>
7889
- <td class="tw-px-3 tw-py-2 tw-text-sm tw-text-gray-900 tw-text-right tw-font-semibold">{{ installment.amount | currency }}</td>
7890
- <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600">{{ installment.dueDate || 'TBD' }}</td>
7891
- <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600 tw-text-center">
7892
- @if (installment.daysFromAssignment !== undefined) {
7893
- <span class="tw-font-medium">{{ installment.daysFromAssignment }} days</span>
7894
- } @else {
7895
- <span class="tw-text-gray-400">-</span>
7896
- }
7897
- </td>
7898
- <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600 tw-text-center">
7899
- @if (installment.daysFromPrevious !== undefined) {
7900
- <span class="tw-font-medium">{{ installment.daysFromPrevious }} days</span>
7901
- } @else {
7902
- <span class="tw-text-gray-400">-</span>
7903
- }
7904
- </td>
7905
- </tr>
7906
- }
7907
- </tbody>
7908
- <tfoot class="tw-bg-purple-100">
7909
- <tr>
7910
- <td class="tw-px-3 tw-py-2 tw-text-sm tw-font-bold tw-text-gray-900">Total:</td>
7911
- <td class="tw-px-3 tw-py-2 tw-text-sm tw-font-bold tw-text-green-600 tw-text-right">{{ details.finalAmount | currency }}</td>
7912
- <td colspan="3"></td>
7913
- </tr>
7914
- </tfoot>
7915
- </table>
7916
- </div>
7917
- </div>
7918
- } @else {
7919
- <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7920
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2">Payment Information</h4>
7921
- <div class="tw-space-y-1 tw-text-xs">
7922
- <div class="tw-flex tw-justify-between">
7923
- <span class="tw-text-gray-600">Payment Type:</span>
7924
- <span class="tw-font-medium tw-text-gray-900">One-time Payment</span>
7925
- </div>
7926
- <div class="tw-flex tw-justify-between">
7927
- <span class="tw-text-gray-600">Amount to Pay:</span>
7928
- <span class="tw-font-bold tw-text-green-600">{{ details.finalAmount | currency }}</span>
7929
- </div>
7930
- @if (details.installments && details.installments.length > 0 && details.installments[0].dueDate) {
7931
- <div class="tw-flex tw-justify-between">
7932
- <span class="tw-text-gray-600">Due Date:</span>
7933
- <span class="tw-font-medium tw-text-gray-900">{{ details.installments[0].dueDate }}</span>
7934
- </div>
7935
- }
7936
- @if (details.dueDateOffset > 0) {
7937
- <div class="tw-flex tw-justify-between">
7938
- <span class="tw-text-gray-600">Due Date Offset:</span>
7939
- <span class="tw-text-gray-900">{{ details.dueDateOffset }} days from assignment date</span>
7940
- </div>
7941
- }
7942
- @if (details.installments && details.installments.length > 0 && details.installments[0].daysFromAssignment) {
7943
- <div class="tw-flex tw-justify-between">
7944
- <span class="tw-text-gray-600">Days from Assignment:</span>
7945
- <span class="tw-text-gray-900">{{ details.installments[0].daysFromAssignment }} days</span>
7946
- </div>
7947
- }
7948
- </div>
7949
- </div>
7950
- }
7951
-
7952
- <!-- Fee Properties -->
7953
- <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7954
- <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Fee Properties</h4>
7955
- <div class="tw-grid tw-grid-cols-2 tw-gap-3">
7956
- <div>
7957
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Mandatory:</span>
7958
- <span class="tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium" [class]="details.isMandatory ? 'tw-bg-red-100 tw-text-red-800' : 'tw-bg-gray-100 tw-text-gray-800'">
7959
- {{ details.isMandatory ? 'Yes - Required' : 'No - Optional' }}
7960
- </span>
7961
- </div>
7962
- <div>
7963
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Refundable:</span>
7964
- <span class="tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium" [class]="details.isRefundable ? 'tw-bg-green-100 tw-text-green-800' : 'tw-bg-gray-100 tw-text-gray-800'">
7965
- {{ details.isRefundable ? 'Yes' : 'No' }}
7966
- </span>
7967
- </div>
7968
- <div>
7969
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Amount Editable:</span>
7970
- <span class="tw-text-gray-900 tw-text-sm">{{ details.isAmountEditable ? 'Yes' : 'No' }}</span>
7971
- </div>
7972
- @if (details.isAmountEditable && (details.minAmount || details.maxAmount)) {
7973
- <div>
7974
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Amount Range:</span>
7975
- <span class="tw-text-gray-900 tw-text-sm">
7976
- {{ details.minAmount ? (details.minAmount | currency) : 'No min' }} -
7977
- {{ details.maxAmount ? (details.maxAmount | currency) : 'No max' }}
7978
- </span>
7979
- </div>
7980
- }
7981
- @if (details.taxApplicable) {
7982
- <div>
7983
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Tax Applicable:</span>
7984
- <span class="tw-text-gray-900 tw-text-sm">{{ details.taxPercentage }}%</span>
7985
- </div>
7986
- }
7987
- @if (details.collectionStartOffset || details.collectionEndOffset) {
7988
- <div>
7989
- <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Collection Window:</span>
7990
- <span class="tw-text-gray-900 tw-text-sm">
7991
- Day {{ details.collectionStartOffset }} to Day {{ details.collectionEndOffset }}
7992
- </span>
7993
- </div>
7994
- }
7995
- </div>
7996
- </div>
7997
- </div>
7998
- }
7999
- }
8000
- </div>
7802
+ ], template: `
7803
+ <div class="tw-p-4 tw-overflow-y-auto tw-h-full">
7804
+ @if (loading()) {
7805
+ <div class="tw-text-center tw-py-12">
7806
+ <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-gray-400 tw-animate-spin tw-mx-auto tw-mb-2">refresh</cide-ele-icon>
7807
+ <span class="tw-text-sm tw-text-gray-500">Loading fee details...</span>
7808
+ </div>
7809
+ } @else if (error()) {
7810
+ <div class="tw-text-center tw-py-12">
7811
+ <cide-ele-icon class="tw-w-8 tw-h-8 tw-text-red-400 tw-mx-auto tw-mb-2">error</cide-ele-icon>
7812
+ <p class="tw-text-sm tw-text-red-600">{{ error() }}</p>
7813
+ </div>
7814
+ } @else {
7815
+ @if (feeDetails(); as details) {
7816
+ <div class="tw-space-y-4 tw-text-sm">
7817
+ <!-- Basic Information -->
7818
+ <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7819
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Basic Information</h4>
7820
+ <div class="tw-grid tw-grid-cols-2 tw-gap-3">
7821
+ <div>
7822
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Fee Name:</span>
7823
+ <span class="tw-font-medium tw-text-gray-900">{{ details.name }}</span>
7824
+ </div>
7825
+ <div>
7826
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Fee Code:</span>
7827
+ <span class="tw-text-gray-900">{{ details.itemCode }}</span>
7828
+ </div>
7829
+ <div>
7830
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Category:</span>
7831
+ <span class="tw-text-gray-900">{{ details.category }}</span>
7832
+ </div>
7833
+ <div>
7834
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Structure:</span>
7835
+ <span class="tw-text-gray-900">{{ details.structureName }}</span>
7836
+ </div>
7837
+ </div>
7838
+ @if (details.description) {
7839
+ <div class="tw-mt-3 tw-pt-3 tw-border-t tw-border-gray-200">
7840
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Description:</span>
7841
+ <p class="tw-text-gray-900 tw-text-sm">{{ details.description }}</p>
7842
+ </div>
7843
+ }
7844
+ </div>
7845
+
7846
+ <!-- Amount Breakdown -->
7847
+ <div class="tw-bg-blue-50 tw-rounded-lg tw-p-3 tw-border tw-border-blue-200">
7848
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Amount Breakdown</h4>
7849
+ <div class="tw-space-y-2">
7850
+ <div class="tw-flex tw-justify-between tw-items-center">
7851
+ <span class="tw-text-gray-600">Original Amount:</span>
7852
+ <span class="tw-font-medium tw-text-gray-900">{{ details.amount | currency }}</span>
7853
+ </div>
7854
+ @if (details.discount > 0) {
7855
+ <div class="tw-flex tw-justify-between tw-items-center">
7856
+ <span class="tw-text-gray-600">Discount Applied:</span>
7857
+ <span class="tw-font-medium tw-text-blue-600">-{{ details.discount | currency }}</span>
7858
+ </div>
7859
+ }
7860
+ @if (details.taxApplicable && details.taxPercentage > 0) {
7861
+ <div class="tw-flex tw-justify-between tw-items-center">
7862
+ <span class="tw-text-gray-600">Tax ({{ details.taxPercentage }}%):</span>
7863
+ <span class="tw-font-medium tw-text-gray-900">{{ (details.finalAmount * details.taxPercentage) / 100 | currency }}</span>
7864
+ </div>
7865
+ }
7866
+ <div class="tw-flex tw-justify-between tw-items-center tw-pt-2 tw-border-t tw-border-blue-200">
7867
+ <span class="tw-font-semibold tw-text-gray-900">Final Amount:</span>
7868
+ <span class="tw-font-bold tw-text-green-600 tw-text-base">{{ details.finalAmount | currency }}</span>
7869
+ </div>
7870
+ </div>
7871
+ </div>
7872
+
7873
+ <!-- Installment Breakdown -->
7874
+ @if (details.installmentAllowed && details.installments && details.installments.length > 1) {
7875
+ <div class="tw-bg-purple-50 tw-rounded-lg tw-p-3 tw-border tw-border-purple-200">
7876
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Installment Plan</h4>
7877
+ <div class="tw-mb-2 tw-text-xs tw-text-gray-600">
7878
+ Total Amount: <span class="tw-font-semibold">{{ details.finalAmount | currency }}</span>
7879
+ divided into <span class="tw-font-semibold">{{ details.installmentCount }}</span> installments
7880
+ </div>
7881
+ <div class="tw-overflow-x-auto">
7882
+ <table class="tw-min-w-full tw-divide-y tw-divide-purple-200">
7883
+ <thead class="tw-bg-purple-100">
7884
+ <tr>
7885
+ <th class="tw-px-3 tw-py-2 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700">Installment #</th>
7886
+ <th class="tw-px-3 tw-py-2 tw-text-right tw-text-xs tw-font-semibold tw-text-gray-700">Amount</th>
7887
+ <th class="tw-px-3 tw-py-2 tw-text-left tw-text-xs tw-font-semibold tw-text-gray-700">Due Date</th>
7888
+ <th class="tw-px-3 tw-py-2 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700">Days from Assignment</th>
7889
+ <th class="tw-px-3 tw-py-2 tw-text-center tw-text-xs tw-font-semibold tw-text-gray-700">Days from Previous</th>
7890
+ </tr>
7891
+ </thead>
7892
+ <tbody class="tw-bg-white tw-divide-y tw-divide-purple-200">
7893
+ @for (installment of details.installments; track installment.number) {
7894
+ <tr>
7895
+ <td class="tw-px-3 tw-py-2 tw-text-sm tw-text-gray-900 tw-font-medium">#{{ installment.number }}</td>
7896
+ <td class="tw-px-3 tw-py-2 tw-text-sm tw-text-gray-900 tw-text-right tw-font-semibold">{{ installment.amount | currency }}</td>
7897
+ <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600">{{ installment.dueDate || 'TBD' }}</td>
7898
+ <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600 tw-text-center">
7899
+ @if (installment.daysFromAssignment !== undefined) {
7900
+ <span class="tw-font-medium">{{ installment.daysFromAssignment }} days</span>
7901
+ } @else {
7902
+ <span class="tw-text-gray-400">-</span>
7903
+ }
7904
+ </td>
7905
+ <td class="tw-px-3 tw-py-2 tw-text-xs tw-text-gray-600 tw-text-center">
7906
+ @if (installment.daysFromPrevious !== undefined) {
7907
+ <span class="tw-font-medium">{{ installment.daysFromPrevious }} days</span>
7908
+ } @else {
7909
+ <span class="tw-text-gray-400">-</span>
7910
+ }
7911
+ </td>
7912
+ </tr>
7913
+ }
7914
+ </tbody>
7915
+ <tfoot class="tw-bg-purple-100">
7916
+ <tr>
7917
+ <td class="tw-px-3 tw-py-2 tw-text-sm tw-font-bold tw-text-gray-900">Total:</td>
7918
+ <td class="tw-px-3 tw-py-2 tw-text-sm tw-font-bold tw-text-green-600 tw-text-right">{{ details.finalAmount | currency }}</td>
7919
+ <td colspan="3"></td>
7920
+ </tr>
7921
+ </tfoot>
7922
+ </table>
7923
+ </div>
7924
+ </div>
7925
+ } @else {
7926
+ <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7927
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-2">Payment Information</h4>
7928
+ <div class="tw-space-y-1 tw-text-xs">
7929
+ <div class="tw-flex tw-justify-between">
7930
+ <span class="tw-text-gray-600">Payment Type:</span>
7931
+ <span class="tw-font-medium tw-text-gray-900">One-time Payment</span>
7932
+ </div>
7933
+ <div class="tw-flex tw-justify-between">
7934
+ <span class="tw-text-gray-600">Amount to Pay:</span>
7935
+ <span class="tw-font-bold tw-text-green-600">{{ details.finalAmount | currency }}</span>
7936
+ </div>
7937
+ @if (details.installments && details.installments.length > 0 && details.installments[0].dueDate) {
7938
+ <div class="tw-flex tw-justify-between">
7939
+ <span class="tw-text-gray-600">Due Date:</span>
7940
+ <span class="tw-font-medium tw-text-gray-900">{{ details.installments[0].dueDate }}</span>
7941
+ </div>
7942
+ }
7943
+ @if (details.dueDateOffset > 0) {
7944
+ <div class="tw-flex tw-justify-between">
7945
+ <span class="tw-text-gray-600">Due Date Offset:</span>
7946
+ <span class="tw-text-gray-900">{{ details.dueDateOffset }} days from assignment date</span>
7947
+ </div>
7948
+ }
7949
+ @if (details.installments && details.installments.length > 0 && details.installments[0].daysFromAssignment) {
7950
+ <div class="tw-flex tw-justify-between">
7951
+ <span class="tw-text-gray-600">Days from Assignment:</span>
7952
+ <span class="tw-text-gray-900">{{ details.installments[0].daysFromAssignment }} days</span>
7953
+ </div>
7954
+ }
7955
+ </div>
7956
+ </div>
7957
+ }
7958
+
7959
+ <!-- Fee Properties -->
7960
+ <div class="tw-bg-gray-50 tw-rounded-lg tw-p-3 tw-border tw-border-gray-200">
7961
+ <h4 class="tw-text-sm tw-font-semibold tw-text-gray-900 tw-mb-3">Fee Properties</h4>
7962
+ <div class="tw-grid tw-grid-cols-2 tw-gap-3">
7963
+ <div>
7964
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Mandatory:</span>
7965
+ <span class="tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium" [class]="details.isMandatory ? 'tw-bg-red-100 tw-text-red-800' : 'tw-bg-gray-100 tw-text-gray-800'">
7966
+ {{ details.isMandatory ? 'Yes - Required' : 'No - Optional' }}
7967
+ </span>
7968
+ </div>
7969
+ <div>
7970
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Refundable:</span>
7971
+ <span class="tw-inline-flex tw-items-center tw-px-2 tw-py-0.5 tw-rounded-full tw-text-xs tw-font-medium" [class]="details.isRefundable ? 'tw-bg-green-100 tw-text-green-800' : 'tw-bg-gray-100 tw-text-gray-800'">
7972
+ {{ details.isRefundable ? 'Yes' : 'No' }}
7973
+ </span>
7974
+ </div>
7975
+ <div>
7976
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Amount Editable:</span>
7977
+ <span class="tw-text-gray-900 tw-text-sm">{{ details.isAmountEditable ? 'Yes' : 'No' }}</span>
7978
+ </div>
7979
+ @if (details.isAmountEditable && (details.minAmount || details.maxAmount)) {
7980
+ <div>
7981
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Amount Range:</span>
7982
+ <span class="tw-text-gray-900 tw-text-sm">
7983
+ {{ details.minAmount ? (details.minAmount | currency) : 'No min' }} -
7984
+ {{ details.maxAmount ? (details.maxAmount | currency) : 'No max' }}
7985
+ </span>
7986
+ </div>
7987
+ }
7988
+ @if (details.taxApplicable) {
7989
+ <div>
7990
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Tax Applicable:</span>
7991
+ <span class="tw-text-gray-900 tw-text-sm">{{ details.taxPercentage }}%</span>
7992
+ </div>
7993
+ }
7994
+ @if (details.collectionStartOffset || details.collectionEndOffset) {
7995
+ <div>
7996
+ <span class="tw-text-gray-500 tw-block tw-text-xs tw-mb-1">Collection Window:</span>
7997
+ <span class="tw-text-gray-900 tw-text-sm">
7998
+ Day {{ details.collectionStartOffset }} to Day {{ details.collectionEndOffset }}
7999
+ </span>
8000
+ </div>
8001
+ }
8002
+ </div>
8003
+ </div>
8004
+ </div>
8005
+ }
8006
+ }
8007
+ </div>
8001
8008
  `, styles: [":host{display:block}\n"] }]
8002
8009
  }] });
8003
8010