@unifylib/ui-lib 1.0.3 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/ng-package.json +7 -7
  2. package/package.json +14 -12
  3. package/src/lib/base-model/SearchStrConfig.ts +12 -12
  4. package/src/lib/base-model/api-response.ts +23 -23
  5. package/src/lib/base-model/audit-log-entry.ts +7 -7
  6. package/src/lib/base-model/button-action-settings.ts +29 -25
  7. package/src/lib/base-model/column-def.model.ts +34 -34
  8. package/src/lib/base-model/do-action-request.ts +11 -11
  9. package/src/lib/base-model/feature-item.ts +9 -0
  10. package/src/lib/base-model/field-action.ts +7 -7
  11. package/src/lib/base-model/field-filter.model.ts +7 -14
  12. package/src/lib/base-model/field-info.ts +102 -98
  13. package/src/lib/base-model/field-predicate.model.ts +7 -7
  14. package/src/lib/base-model/filter-request.ts +27 -27
  15. package/src/lib/base-model/filter.model.ts +49 -49
  16. package/src/lib/base-model/get-items-list.ts +24 -24
  17. package/src/lib/base-model/index.ts +11 -11
  18. package/src/lib/base-model/items-total.model.ts +12 -0
  19. package/src/lib/base-model/line-item.model.ts +18 -0
  20. package/src/lib/base-model/lookupItem.ts +21 -21
  21. package/src/lib/base-model/null-snackmessage.ts +9 -9
  22. package/src/lib/base-model/page-info.ts +54 -51
  23. package/src/lib/base-model/report-request.model.ts +33 -33
  24. package/src/lib/base-model/response-envelop.model.ts +15 -15
  25. package/src/lib/base-model/snack-message.model.ts +14 -14
  26. package/src/lib/base-model/snackmessage-interface.ts +7 -7
  27. package/src/lib/base-model/table-column.interface.ts +29 -29
  28. package/src/lib/base-model/table-page-user-action.interface.ts +33 -33
  29. package/src/lib/base-model/workflow/workflow-steps.model.ts +9 -9
  30. package/src/lib/base-model/workflow/workflow.model.ts +52 -52
  31. package/src/lib/components/action-comment/action-comment.component.css +52 -0
  32. package/src/lib/components/action-comment/action-comment.component.html +47 -0
  33. package/src/lib/components/{rejection-comment → action-comment}/action-comment.component.spec.ts +23 -23
  34. package/src/lib/components/{rejection-comment → action-comment}/action-comment.component.ts +102 -86
  35. package/src/lib/components/action-confirmation/action-confirmation.component.css +46 -34
  36. package/src/lib/components/action-confirmation/action-confirmation.component.html +32 -18
  37. package/src/lib/components/action-confirmation/action-confirmation.component.spec.ts +23 -23
  38. package/src/lib/components/action-confirmation/action-confirmation.component.ts +58 -58
  39. package/src/lib/components/activity-report-form/activity-report-form.component.html +110 -109
  40. package/src/lib/components/activity-report-form/activity-report-form.component.scss +69 -0
  41. package/src/lib/components/activity-report-form/activity-report-form.component.spec.ts +25 -25
  42. package/src/lib/components/activity-report-form/activity-report-form.component.ts +616 -605
  43. package/src/lib/components/advanced-filter/field-filter/field-filter.component.html +8 -0
  44. package/src/lib/components/advanced-filter/field-filter/field-filter.component.scss +0 -0
  45. package/src/lib/components/advanced-filter/field-filter/field-filter.component.spec.ts +25 -0
  46. package/src/lib/components/advanced-filter/field-filter/field-filter.component.ts +55 -0
  47. package/src/lib/components/advanced-filter/filter-builder/filter-builder.component.html +36 -0
  48. package/src/lib/components/advanced-filter/filter-builder/filter-builder.component.scss +130 -0
  49. package/src/lib/components/advanced-filter/filter-builder/filter-builder.component.spec.ts +25 -0
  50. package/src/lib/components/advanced-filter/filter-builder/filter-builder.component.ts +186 -0
  51. package/src/lib/components/audit-log-details-dialog/audit-log-details-dialog.component.css +51 -51
  52. package/src/lib/components/audit-log-details-dialog/audit-log-details-dialog.component.html +23 -23
  53. package/src/lib/components/audit-log-details-dialog/audit-log-details-dialog.component.spec.ts +23 -23
  54. package/src/lib/components/audit-log-details-dialog/audit-log-details-dialog.component.ts +69 -69
  55. package/src/lib/components/audit-log-list/audit-log.component.html +26 -23
  56. package/src/lib/components/audit-log-list/audit-log.component.scss +50 -0
  57. package/src/lib/components/audit-log-list/audit-log.component.spec.ts +25 -25
  58. package/src/lib/components/audit-log-list/audit-log.component.ts +114 -116
  59. package/src/lib/components/auto-complete/auto-complete.component.css +55 -14
  60. package/src/lib/components/auto-complete/auto-complete.component.html +45 -29
  61. package/src/lib/components/auto-complete/auto-complete.component.spec.ts +23 -23
  62. package/src/lib/components/auto-complete/auto-complete.component.ts +331 -330
  63. package/src/lib/components/base-form/base-form.component.html +59 -58
  64. package/src/lib/components/base-form/base-form.component.scss +68 -0
  65. package/src/lib/components/base-form/base-form.component.spec.ts +25 -25
  66. package/src/lib/components/base-form/base-form.component.ts +323 -305
  67. package/src/lib/components/base-form-canvas/base-form-canvas.component.css +196 -22
  68. package/src/lib/components/base-form-canvas/base-form-canvas.component.html +1095 -1006
  69. package/src/lib/components/base-form-canvas/base-form-canvas.component.spec.ts +23 -23
  70. package/src/lib/components/base-form-canvas/base-form-canvas.component.ts +680 -573
  71. package/src/lib/components/base-input-dialog/base-input-dialog.component.css +67 -0
  72. package/src/lib/components/base-input-dialog/base-input-dialog.component.html +47 -42
  73. package/src/lib/components/base-input-dialog/base-input-dialog.component.spec.ts +23 -23
  74. package/src/lib/components/base-input-dialog/base-input-dialog.component.ts +77 -78
  75. package/src/lib/components/base-table/base-table.component.html +268 -242
  76. package/src/lib/components/base-table/base-table.component.scss +140 -31
  77. package/src/lib/components/base-table/base-table.component.spec.ts +25 -25
  78. package/src/lib/components/base-table/base-table.component.ts +621 -568
  79. package/src/lib/components/button-actions/button-actions.component.html +27 -28
  80. package/src/lib/components/button-actions/button-actions.component.scss +101 -6
  81. package/src/lib/components/button-actions/button-actions.component.spec.ts +23 -23
  82. package/src/lib/components/button-actions/button-actions.component.ts +70 -72
  83. package/src/lib/components/editable-base-table/editable-base-table.component.html +337 -372
  84. package/src/lib/components/editable-base-table/editable-base-table.component.scss +126 -44
  85. package/src/lib/components/editable-base-table/editable-base-table.component.spec.ts +25 -25
  86. package/src/lib/components/editable-base-table/editable-base-table.component.ts +579 -570
  87. package/src/lib/components/equation-builder/equation-builder.component.css +39 -0
  88. package/src/lib/components/equation-builder/equation-builder.component.html +31 -31
  89. package/src/lib/components/equation-builder/equation-builder.component.spec.ts +23 -23
  90. package/src/lib/components/equation-builder/equation-builder.component.ts +119 -121
  91. package/src/lib/components/item-line-editor/item-line-editor.component.html +102 -0
  92. package/src/lib/components/item-line-editor/item-line-editor.component.scss +152 -0
  93. package/src/lib/components/item-line-editor/item-line-editor.component.spec.ts +23 -0
  94. package/src/lib/components/item-line-editor/item-line-editor.component.ts +306 -0
  95. package/src/lib/components/multi-auto-complete/multi-auto-complete.component.css +19 -11
  96. package/src/lib/components/multi-auto-complete/multi-auto-complete.component.html +38 -38
  97. package/src/lib/components/multi-auto-complete/multi-auto-complete.component.spec.ts +23 -23
  98. package/src/lib/components/multi-auto-complete/multi-auto-complete.component.ts +315 -317
  99. package/src/lib/components/paginator/paginator.component.css +65 -25
  100. package/src/lib/components/paginator/paginator.component.html +30 -34
  101. package/src/lib/components/paginator/paginator.component.ts +87 -94
  102. package/src/lib/components/report-details-dialog/report-details-dialog.component.css +17 -17
  103. package/src/lib/components/report-details-dialog/report-details-dialog.component.html +16 -16
  104. package/src/lib/components/report-details-dialog/report-details-dialog.component.spec.ts +23 -23
  105. package/src/lib/components/report-details-dialog/report-details-dialog.component.ts +111 -113
  106. package/src/lib/components/report-form/report-form.component.html +92 -94
  107. package/src/lib/components/report-form/report-form.component.scss +51 -0
  108. package/src/lib/components/report-form/report-form.component.spec.ts +25 -25
  109. package/src/lib/components/report-form/report-form.component.ts +599 -588
  110. package/src/lib/components/search-bar/search-bar.component.html +51 -62
  111. package/src/lib/components/search-bar/search-bar.component.scss +63 -8
  112. package/src/lib/components/search-bar/search-bar.component.spec.ts +25 -25
  113. package/src/lib/components/search-bar/search-bar.component.ts +68 -70
  114. package/src/lib/components/section-form-canvas/section-form-canvas.component.html +43 -0
  115. package/src/lib/components/section-form-canvas/section-form-canvas.component.scss +81 -0
  116. package/src/lib/components/section-form-canvas/section-form-canvas.component.spec.ts +23 -0
  117. package/src/lib/components/section-form-canvas/section-form-canvas.component.ts +67 -0
  118. package/src/lib/components/shared/action-button/action-button.component.html +12 -0
  119. package/src/lib/components/shared/action-button/action-button.component.scss +45 -0
  120. package/src/lib/components/shared/action-button/action-button.component.ts +51 -0
  121. package/src/lib/components/shared/action-card/action-card.component.html +78 -0
  122. package/src/lib/components/shared/action-card/action-card.component.scss +238 -0
  123. package/src/lib/components/shared/action-card/action-card.component.ts +56 -0
  124. package/src/lib/components/shared/attachment-uploader/attachment-uploader.component.css +135 -54
  125. package/src/lib/components/shared/attachment-uploader/attachment-uploader.component.html +36 -22
  126. package/src/lib/components/shared/attachment-uploader/attachment-uploader.component.spec.ts +23 -23
  127. package/src/lib/components/shared/attachment-uploader/attachment-uploader.component.ts +71 -45
  128. package/src/lib/components/shared-list/shared-list.component.html +17 -17
  129. package/src/lib/components/shared-list/shared-list.component.spec.ts +23 -23
  130. package/src/lib/components/shared-list/shared-list.component.ts +53 -53
  131. package/src/lib/components/snackbar-static/snackbar-static.component.html +20 -0
  132. package/src/lib/components/snackbar-static/snackbar-static.component.scss +135 -0
  133. package/src/lib/components/snackbar-static/snackbar-static.component.ts +26 -0
  134. package/src/lib/components/title-bar/title-bar.component.html +35 -31
  135. package/src/lib/components/title-bar/title-bar.component.scss +126 -23
  136. package/src/lib/components/title-bar/title-bar.component.spec.ts +23 -23
  137. package/src/lib/components/title-bar/title-bar.component.ts +126 -119
  138. package/src/lib/services/backend-service.ts +287 -286
  139. package/src/lib/services/index.ts +3 -3
  140. package/src/lib/services/top-panel.ts +17 -17
  141. package/src/lib/services/trigger-form.service.ts +11 -11
  142. package/src/lib/share-module/shared-module.ts +10 -10
  143. package/src/lib/utils/base-utils.ts +102 -102
  144. package/src/lib/validators/date-range-validator.ts +31 -31
  145. package/src/lib/validators/index.ts +3 -3
  146. package/src/lib/validators/match-list.validator.ts +10 -10
  147. package/src/lib/validators/multi-email-validator.ts +15 -15
  148. package/src/public-api.ts +29 -21
  149. package/tsconfig.lib.json +15 -15
  150. package/tsconfig.lib.prod.json +11 -11
  151. package/tsconfig.spec.json +15 -15
  152. package/src/lib/components/rejection-comment/action-comment.component.css +0 -33
  153. package/src/lib/components/rejection-comment/action-comment.component.html +0 -46
  154. package/src/lib/styles/invoiceq-theme.scss +0 -252
  155. package/src/lib/styles/styles.scss +0 -1723
@@ -0,0 +1,39 @@
1
+ .flex-row {
2
+ display: flex;
3
+ flex-direction: row;
4
+ }
5
+
6
+ .flex-column {
7
+ display: flex;
8
+ flex-direction: column;
9
+ }
10
+
11
+ .flex-full {
12
+ flex: 1 1 auto;
13
+ }
14
+
15
+ .flex-none {
16
+ flex: 0 0 auto;
17
+ }
18
+
19
+ .fill {
20
+ width: 100%;
21
+ }
22
+
23
+ .align-start-center {
24
+ align-items: center;
25
+ justify-content: flex-start;
26
+ }
27
+
28
+ .align-center-center {
29
+ align-items: center;
30
+ justify-content: center;
31
+ }
32
+
33
+ .gap-5 {
34
+ gap: 5px;
35
+ }
36
+
37
+ .gap-10 {
38
+ gap: 10px;
39
+ }
@@ -1,31 +1,31 @@
1
- <div fxLayout="row" fxLayoutGap="10px" fxFlexFill fxLayoutAlign="start center">
2
- <ng-container *ngFor="let item of items; let i = index">
3
- <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="5px">
4
- <ng-container [ngSwitch]="item.type">
5
- <ng-container *ngSwitchCase="'lookup'">
6
- <app-auto-complete
7
- fxFlex
8
- [field]="field"
9
- [form]="form"
10
- [defaultValue]="item.value"
11
- (selectedValue)="onLookupChange(i, $event)">
12
- </app-auto-complete>
13
- </ng-container>
14
-
15
- <ng-container *ngSwitchCase="'dropdown'">
16
- <mat-form-field appearance="outline" fxFlex="none" style="width: 100px">
17
- <mat-select [disabled]="readOnly" [value]="item.value" (selectionChange)="onDropdownChange(i, $event.value)">
18
- <mat-option *ngFor="let opt of operators" [value]="opt.value">
19
- {{ opt.label }}
20
- </mat-option>
21
- </mat-select>
22
- </mat-form-field>
23
- </ng-container>
24
- </ng-container>
25
- </div>
26
- </ng-container>
27
-
28
- <button [disabled]="isPending" mat-icon-button color="warn" (click)="onClearAll()" *ngIf="items.length > 0">
29
- <mat-icon>delete</mat-icon>
30
- </button>
31
- </div>
1
+ <div class="flex-row gap-10 fill align-start-center">
2
+ <ng-container *ngFor="let item of items; let i = index">
3
+ <div class="flex-row align-start-center gap-5">
4
+ <ng-container [ngSwitch]="item.type">
5
+ <ng-container *ngSwitchCase="'lookup'">
6
+ <app-auto-complete
7
+ class="flex-full"
8
+ [field]="field"
9
+ [form]="form"
10
+ [defaultValue]="item.value"
11
+ (selectedValue)="onLookupChange(i, $event)">
12
+ </app-auto-complete>
13
+ </ng-container>
14
+
15
+ <ng-container *ngSwitchCase="'dropdown'">
16
+ <mat-form-field class="flex-none" appearance="outline" style="width: 100px">
17
+ <mat-select [disabled]="readOnly" [value]="item.value" (selectionChange)="onDropdownChange(i, $event.value)">
18
+ <mat-option *ngFor="let opt of operators" [value]="opt.value">
19
+ {{ opt.label }}
20
+ </mat-option>
21
+ </mat-select>
22
+ </mat-form-field>
23
+ </ng-container>
24
+ </ng-container>
25
+ </div>
26
+ </ng-container>
27
+
28
+ <button [disabled]="isPending" mat-icon-button color="warn" (click)="onClearAll()" *ngIf="items.length > 0" id="equation-clear-all-btn">
29
+ <mat-icon>delete</mat-icon>
30
+ </button>
31
+ </div>
@@ -1,23 +1,23 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
-
3
- import { EquationBuilderComponent } from './equation-builder.component';
4
-
5
- describe('EquationBuilderComponent', () => {
6
- let component: EquationBuilderComponent;
7
- let fixture: ComponentFixture<EquationBuilderComponent>;
8
-
9
- beforeEach(async () => {
10
- await TestBed.configureTestingModule({
11
- imports: [EquationBuilderComponent]
12
- })
13
- .compileComponents();
14
-
15
- fixture = TestBed.createComponent(EquationBuilderComponent);
16
- component = fixture.componentInstance;
17
- fixture.detectChanges();
18
- });
19
-
20
- it('should create', () => {
21
- expect(component).toBeTruthy();
22
- });
23
- });
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { EquationBuilderComponent } from './equation-builder.component';
4
+
5
+ describe('EquationBuilderComponent', () => {
6
+ let component: EquationBuilderComponent;
7
+ let fixture: ComponentFixture<EquationBuilderComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [EquationBuilderComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(EquationBuilderComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
@@ -1,121 +1,119 @@
1
- import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
2
- import { FormGroup } from "@angular/forms";
3
- import { AutoCompleteComponent } from "../auto-complete/auto-complete.component";
4
- import { MatFormField, MatOption, MatSelect } from "@angular/material/select";
5
- import {NgForOf, NgIf, NgSwitch, NgSwitchCase} from "@angular/common";
6
- import { FlexLayoutModule } from "@angular/flex-layout";
7
- import {MatIcon} from "@angular/material/icon";
8
- import {MatIconButton} from "@angular/material/button";
9
-
10
- @Component({
11
- selector: 'lib-equation-builder',
12
- standalone: true,
13
- imports: [
14
- AutoCompleteComponent,
15
- MatSelect,
16
- MatOption,
17
- MatFormField,
18
- NgSwitch,
19
- NgForOf,
20
- NgSwitchCase,
21
- FlexLayoutModule,
22
- MatIcon,
23
- MatIconButton,
24
- NgIf
25
- ],
26
- templateUrl: './equation-builder.component.html',
27
- styleUrl: './equation-builder.component.css'
28
- })
29
- export class EquationBuilderComponent implements OnInit {
30
- @Input() form!: FormGroup;
31
- @Input() field!: any;
32
- @Input() isPending!: boolean;
33
- @Output() valueChanged = new EventEmitter<any>();
34
-
35
- operators = [
36
- { label: '+', value: '+' },
37
- { label: '-', value: '-' },
38
- { label: '=', value: '=' }
39
- ];
40
-
41
- items: any[] = [];
42
- @Input() readOnly!: boolean;
43
-
44
- ngOnInit() {
45
- const fieldValues: any[] = this.form.get('fieldValue')?.value;
46
-
47
- if (Array.isArray(fieldValues) && fieldValues.length > 0) {
48
- this.items = fieldValues.map(val => {
49
- if (this.operators.some(op => op.value === val)) {
50
- return { type: 'dropdown', value: val };
51
- } else {
52
- return {
53
- type: 'lookup',
54
- value: this.getLookupByCode(val)
55
- };
56
- }
57
- });
58
- } else {
59
- this.items = [{ type: 'lookup', value: null }];
60
- }
61
-
62
- }
63
-
64
- getLookupByCode(code: string): any {
65
- return { code: code, id: 1, englishName: code, arabicName: code }
66
- }
67
-
68
- onLookupChange(index: number, value: any) {
69
- this.items[index].value = value;
70
-
71
- if (index === this.items.length - 1) {
72
- this.items.push({ type: 'dropdown', value: null});
73
- }
74
-
75
- this.emitChange();
76
- }
77
-
78
- onDropdownChange(index: number, value: any) {
79
- this.items[index].value = value;
80
-
81
- if (index !== this.items.length - 1) {
82
- this.emitChange();
83
- return;
84
- }
85
-
86
- if (value === '=') {
87
- this.items = this.items.slice(0, index + 1);
88
- } else if (value != null && value !== '') {
89
- const lastItem = this.items[this.items.length - 1];
90
- if (lastItem.type !== 'lookup') {
91
- this.items.push({ type: 'lookup', value: null });
92
- }
93
- }
94
-
95
- this.emitChange();
96
- }
97
-
98
- emitChange() {
99
- const simplifiedItems = this.items.map(item => {
100
- if (item?.type === 'lookup') {
101
- return item.value?.code ?? null;
102
- } else if (item?.type === 'dropdown') {
103
- return item.value ?? null;
104
- }
105
- return null;
106
- });
107
- const isValid = simplifiedItems[simplifiedItems.length - 1] === '=';
108
-
109
- this.valueChanged.emit({
110
- value: simplifiedItems.filter(val => val !== '='),
111
- valid: isValid
112
- });
113
- }
114
-
115
- onClearAll(): void {
116
- this.items = [{ type: 'lookup', value: null }];
117
- this.emitChange();
118
- }
119
-
120
-
121
- }
1
+ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
2
+ import { FormGroup } from "@angular/forms";
3
+ import { AutoCompleteComponent } from "../auto-complete/auto-complete.component";
4
+ import { MatFormField, MatOption, MatSelect } from "@angular/material/select";
5
+ import {NgForOf, NgIf, NgSwitch, NgSwitchCase} from "@angular/common";
6
+ import {MatIcon} from "@angular/material/icon";
7
+ import {MatIconButton} from "@angular/material/button";
8
+
9
+ @Component({
10
+ selector: 'lib-equation-builder',
11
+ standalone: true,
12
+ imports: [
13
+ AutoCompleteComponent,
14
+ MatSelect,
15
+ MatOption,
16
+ MatFormField,
17
+ NgSwitch,
18
+ NgForOf,
19
+ NgSwitchCase,
20
+ MatIcon,
21
+ MatIconButton,
22
+ NgIf
23
+ ],
24
+ templateUrl: './equation-builder.component.html',
25
+ styleUrl: './equation-builder.component.css'
26
+ })
27
+ export class EquationBuilderComponent implements OnInit {
28
+ @Input() form!: FormGroup;
29
+ @Input() field!: any;
30
+ @Input() isPending!: boolean;
31
+ @Output() valueChanged = new EventEmitter<any>();
32
+
33
+ operators = [
34
+ { label: '+', value: '+' },
35
+ { label: '-', value: '-' },
36
+ { label: '=', value: '=' }
37
+ ];
38
+
39
+ items: any[] = [];
40
+ @Input() readOnly!: boolean;
41
+
42
+ ngOnInit() {
43
+ const fieldValues: any[] = this.form.get('fieldValue')?.value;
44
+
45
+ if (Array.isArray(fieldValues) && fieldValues.length > 0) {
46
+ this.items = fieldValues.map(val => {
47
+ if (this.operators.some(op => op.value === val)) {
48
+ return { type: 'dropdown', value: val };
49
+ } else {
50
+ return {
51
+ type: 'lookup',
52
+ value: this.getLookupByCode(val)
53
+ };
54
+ }
55
+ });
56
+ } else {
57
+ this.items = [{ type: 'lookup', value: null }];
58
+ }
59
+
60
+ }
61
+
62
+ getLookupByCode(code: string): any {
63
+ return { code: code, id: 1, englishName: code, arabicName: code }
64
+ }
65
+
66
+ onLookupChange(index: number, value: any) {
67
+ this.items[index].value = value;
68
+
69
+ if (index === this.items.length - 1) {
70
+ this.items.push({ type: 'dropdown', value: null});
71
+ }
72
+
73
+ this.emitChange();
74
+ }
75
+
76
+ onDropdownChange(index: number, value: any) {
77
+ this.items[index].value = value;
78
+
79
+ if (index !== this.items.length - 1) {
80
+ this.emitChange();
81
+ return;
82
+ }
83
+
84
+ if (value === '=') {
85
+ this.items = this.items.slice(0, index + 1);
86
+ } else if (value != null && value !== '') {
87
+ const lastItem = this.items[this.items.length - 1];
88
+ if (lastItem.type !== 'lookup') {
89
+ this.items.push({ type: 'lookup', value: null });
90
+ }
91
+ }
92
+
93
+ this.emitChange();
94
+ }
95
+
96
+ emitChange() {
97
+ const simplifiedItems = this.items.map(item => {
98
+ if (item?.type === 'lookup') {
99
+ return item.value?.code ?? null;
100
+ } else if (item?.type === 'dropdown') {
101
+ return item.value ?? null;
102
+ }
103
+ return null;
104
+ });
105
+ const isValid = simplifiedItems[simplifiedItems.length - 1] === '=';
106
+
107
+ this.valueChanged.emit({
108
+ value: simplifiedItems.filter(val => val !== '='),
109
+ valid: isValid
110
+ });
111
+ }
112
+
113
+ onClearAll(): void {
114
+ this.items = [{ type: 'lookup', value: null }];
115
+ this.emitChange();
116
+ }
117
+
118
+
119
+ }
@@ -0,0 +1,102 @@
1
+ <div class="item-line-editor">
2
+
3
+ <h3 class="title">{{ title | translate }}</h3>
4
+ <p class="subtitle">{{ subtitle | translate }}</p>
5
+
6
+ <div class="table-header" [ngStyle]="{ 'grid-template-columns': gridTemplate }">
7
+ <ng-container *ngFor="let f of headerFields; let idx = index">
8
+ <div class="col">
9
+ {{ labelOf(f) | translate }}
10
+ </div>
11
+ </ng-container>
12
+ </div>
13
+ @if (!noDataFound) {
14
+ <div class="table-body" *ngFor="let it of items; let i = index; trackBy: trackByIndex">
15
+
16
+ <div class="table-row">
17
+
18
+ <div class="row-inputs">
19
+ <app-base-form-canvas
20
+ [pageInfo]="pageInfo"
21
+ [fields]="fields"
22
+ [editable]="editing[i]"
23
+ [emitOnValueChanges]="true"
24
+ [item]="it"
25
+ [currency]="currency"
26
+ (formUpdated)="onFormUpdated($event, i)">
27
+ </app-base-form-canvas>
28
+ </div>
29
+
30
+
31
+ </div>
32
+ <div class="row-actions">
33
+
34
+ <button *ngIf="editing[i]" mat-stroked-button class="btn-none-background-primary save-btn" (click)="saveRow(i)"
35
+ [disabled]="!canSave(i)">
36
+ <div class="button-text">
37
+ <mat-icon>check</mat-icon>
38
+ <span>{{ 'item-line.save' | translate }}</span>
39
+ </div>
40
+ </button>
41
+
42
+ <button *ngIf="!editing[i] && editable" mat-stroked-button class="btn-none-background-primary edit-btn"
43
+ (click)="editRow(i)">
44
+ <div class="button-text">
45
+ <mat-icon>edit</mat-icon>
46
+ <span>{{ 'item-line.edit' | translate }}</span>
47
+ </div>
48
+ </button>
49
+
50
+ <button *ngIf="allowDelete && editable" mat-stroked-button class="btn-none-background-primary delete-btn"
51
+ (click)="deleteItem(i)" type="button">
52
+ <div class="button-text">
53
+ <mat-icon>delete</mat-icon>
54
+ <span>{{ 'item-line.delete' | translate }}</span>
55
+ </div>
56
+ </button>
57
+ </div>
58
+ </div>
59
+ }
60
+ @if (noDataFound) {
61
+ <div class="dataNotFound flex-column">
62
+ <mat-icon class="dataNotFound__icon">{{ noDataFoundIcon }}</mat-icon>
63
+ <span class="dataNotFound__title">{{ noDataFoundTitle | translate }}</span>
64
+ <span class="dataNotFound__subtitle">{{ noDataFoundSubtitle | translate }}</span>
65
+ </div>
66
+
67
+ }
68
+ <div class="add-item" *ngIf="allowAdd && editable">
69
+ <div class="divider" style="border-top: 1px solid var(--primary-color-3nd)"></div>
70
+ <button mat-stroked-button color="primary" class="btn-none-background-primary" (click)="addNewItem()"
71
+ [disabled]="!canAddNew">
72
+ <div class="button-text">
73
+ <mat-icon>add</mat-icon>
74
+ <span> {{ 'item-line.addNewItem' | translate }}</span>
75
+ </div>
76
+ </button>
77
+
78
+ </div>
79
+
80
+ @if (!noDataFound) {
81
+ <div class="totals-box">
82
+
83
+ <div class="total-row">
84
+ <span class="label">{{ 'item-line.discount' | translate }}</span>
85
+ <span class="value red">{{ discountTotal | currency:currency }}</span>
86
+ </div>
87
+
88
+ <div class="total-row">
89
+ <span class="label">{{ 'item-line.amount' | translate }}</span>
90
+ <span class="value">{{ subtotal | currency:currency }}</span>
91
+ </div>
92
+
93
+ <div class="divider"></div>
94
+
95
+ <div class="total-row grand">
96
+ <span class="label">{{ 'item-line.grandTotal' | translate }}</span>
97
+ <span class="value strong green">{{ grandTotal | currency:currency }}</span>
98
+ </div>
99
+ </div>
100
+ }
101
+
102
+ </div>
@@ -0,0 +1,152 @@
1
+ .item-line-editor {
2
+ background: #fff;
3
+ border-radius: 8px;
4
+ padding: 20px;
5
+ }
6
+
7
+ .title {
8
+ font-size: 20px;
9
+ margin-bottom: 4px;
10
+ font-weight: 600;
11
+ }
12
+
13
+ .subtitle {
14
+ color: #777;
15
+ font-size: 13px;
16
+ margin-bottom: 16px;
17
+ }
18
+
19
+ .table-header {
20
+ display: grid;
21
+ grid-template-columns: 20% 25% 15% 10% 15% 15%;
22
+ font-weight: 600;
23
+ font-size: 13px;
24
+ padding-bottom: 8px;
25
+ border-bottom: 2px solid var(--primary-color-3nd);
26
+ margin-bottom: 12px;
27
+ }
28
+
29
+ .col {
30
+ padding-left: 4px;
31
+ }
32
+
33
+ .table-body .table-row {
34
+ display: grid;
35
+ padding: 10px 0;
36
+ border-bottom: 1px solid #e6e6e6;
37
+ }
38
+
39
+ .row-inputs {
40
+ padding-right: 10px;
41
+ }
42
+
43
+ .row-actions {
44
+ display: flex;
45
+ flex-direction: row;
46
+ align-items: center;
47
+ justify-content: flex-end;
48
+ gap: 6px;
49
+ margin-top: 24px;
50
+ }
51
+
52
+
53
+ .line-total {
54
+ font-weight: 600;
55
+ font-size: 14px;
56
+ }
57
+
58
+ .save-btn , .edit-btn , .delete-btn {
59
+ width: 114px !important;
60
+ height: 32px !important;
61
+ border-radius: 9999px !important;
62
+ border: 1px solid var(--primary-color-3nd);
63
+ background: #FFF;
64
+ }
65
+ .delete-btn {
66
+ color: #ce3b3a !important;
67
+ border: 1px solid #ce3b3a !important;
68
+ }
69
+ .add-item {
70
+ margin-top: 16px;
71
+ }
72
+ .totals-box {
73
+ margin-top: 20px;
74
+ width: 400px;
75
+ }
76
+
77
+ .total-row {
78
+ display: flex;
79
+ justify-content: space-between;
80
+ font-size: 15px;
81
+ margin: 6px 0;
82
+ }
83
+
84
+ .grand{
85
+ font-family: 'lusail-bold', sans-serif !important;
86
+ }
87
+
88
+ .total-row .label {
89
+ font-weight: 500;
90
+ color: #333;
91
+ }
92
+
93
+ .total-row .value {
94
+ font-weight: 600;
95
+ }
96
+
97
+ .divider {
98
+ border-top: 1px solid #e0e0e0;
99
+ margin: 10px 0;
100
+ }
101
+
102
+ .red {
103
+ color: #d9534f;
104
+ }
105
+
106
+ .green {
107
+ color: #0c7d5e;
108
+ font-weight: 700;
109
+ }
110
+
111
+ .grand .value {
112
+ font-size: 16px;
113
+ }
114
+
115
+ .button-text {
116
+
117
+ span{
118
+ font-size: 16px;
119
+ }
120
+ mat-icon {
121
+ font-size: 16px !important;
122
+ }
123
+ }
124
+ .dataNotFound {
125
+ display: flex;
126
+ flex-direction: column;
127
+ justify-content: center;
128
+ align-items: center;
129
+ height: 100%;
130
+ text-align: center;
131
+
132
+ &__icon {
133
+ color: var(--primary-color-3nd);
134
+ font-size: 24px;
135
+ height: 24px;
136
+ width: 24px;
137
+ margin-bottom: 8px;
138
+ }
139
+
140
+ &__title {
141
+ color: #6A6A6A;
142
+ font-size: 18px;
143
+ font-weight: 700;
144
+ margin-bottom: 4px;
145
+ }
146
+
147
+ &__subtitle {
148
+ color: #6A6A6A;
149
+ font-size: 16px;
150
+ font-weight: 400;
151
+ }
152
+ }
@@ -0,0 +1,23 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { ItemLineEditorComponent } from './item-line-editor.component';
4
+
5
+ describe('ItemLineEditorComponent', () => {
6
+ let component: ItemLineEditorComponent;
7
+ let fixture: ComponentFixture<ItemLineEditorComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [ItemLineEditorComponent]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(ItemLineEditorComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });