fx-form-builder-wrapper 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/ng-package.json +7 -0
- package/package.json +16 -0
- package/src/lib/components/button/button.component.css +0 -0
- package/src/lib/components/button/button.component.html +1 -0
- package/src/lib/components/button/button.component.ts +24 -0
- package/src/lib/components/dynamic-table/dynamic-table.component.css +0 -0
- package/src/lib/components/dynamic-table/dynamic-table.component.html +69 -0
- package/src/lib/components/dynamic-table/dynamic-table.component.ts +201 -0
- package/src/lib/components/fx-form-component/fx-form-component.component.ts +64 -0
- package/src/lib/components/toggle/toggle.component.css +51 -0
- package/src/lib/components/toggle/toggle.component.html +12 -0
- package/src/lib/components/toggle/toggle.component.ts +33 -0
- package/src/lib/components/toggle-button/toggle-button.component.css +22 -0
- package/src/lib/components/toggle-button/toggle-button.component.html +10 -0
- package/src/lib/components/toggle-button/toggle-button.component.ts +40 -0
- package/src/lib/components/uploader/uploader.component.css +49 -0
- package/src/lib/components/uploader/uploader.component.html +23 -0
- package/src/lib/components/uploader/uploader.component.ts +59 -0
- package/src/lib/custom-controls/dispatch-to-clinic/dispatch-to-clinic.component.html +78 -0
- package/src/lib/custom-controls/dispatch-to-clinic/dispatch-to-clinic.component.ts +44 -0
- package/src/lib/fx-builder-wrapper.component.ts +64 -0
- package/src/lib/fx-builder-wrapper.service.ts +34 -0
- package/src/lib/panel/configuration-panel/configuration-panel.component.css +65 -0
- package/src/lib/panel/configuration-panel/configuration-panel.component.html +96 -0
- package/src/lib/panel/configuration-panel/configuration-panel.component.ts +90 -0
- package/src/lib/panel/settings-panel/settings-panel.component.css +30 -0
- package/src/lib/panel/settings-panel/settings-panel.component.html +28 -0
- package/src/lib/panel/settings-panel/settings-panel.component.ts +23 -0
- package/src/public-api.ts +7 -0
- package/src/styles/styles.css +22 -0
- package/tsconfig.lib.json +15 -0
- package/tsconfig.lib.prod.json +11 -0
- package/tsconfig.spec.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# FxBuilderWrapper
|
|
2
|
+
|
|
3
|
+
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 18.2.0.
|
|
4
|
+
|
|
5
|
+
## Code scaffolding
|
|
6
|
+
|
|
7
|
+
Run `ng generate component component-name --project fx-builder-wrapper` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project fx-builder-wrapper`.
|
|
8
|
+
> Note: Don't forget to add `--project fx-builder-wrapper` or else it will be added to the default project in your `angular.json` file.
|
|
9
|
+
|
|
10
|
+
## Build
|
|
11
|
+
|
|
12
|
+
Run `ng build fx-builder-wrapper` to build the project. The build artifacts will be stored in the `dist/` directory.
|
|
13
|
+
|
|
14
|
+
## Publishing
|
|
15
|
+
|
|
16
|
+
After building your library with `ng build fx-builder-wrapper`, go to the dist folder `cd dist/fx-builder-wrapper` and run `npm publish`.
|
|
17
|
+
|
|
18
|
+
## Running unit tests
|
|
19
|
+
|
|
20
|
+
Run `ng test fx-builder-wrapper` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
|
21
|
+
|
|
22
|
+
## Further help
|
|
23
|
+
|
|
24
|
+
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
package/ng-package.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fx-form-builder-wrapper",
|
|
3
|
+
"version": "0.0.11",
|
|
4
|
+
"peerDependencies": {
|
|
5
|
+
"@angular/common": "^18.2.0",
|
|
6
|
+
"@angular/core": "^18.2.0",
|
|
7
|
+
"@instantsys-labs/fx": "2.0.2",
|
|
8
|
+
"uuid": "^11.0.5",
|
|
9
|
+
"primeng": "^18.0.2",
|
|
10
|
+
"tailwindcss-primeui": "^0.4.0"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"tslib": "^2.3.0"
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": false
|
|
16
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<p>button works!</p>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { ChangeDetectorRef, Component } from '@angular/core';
|
|
3
|
+
import { FxBaseComponent, FxSetting, FxStringSetting, FxValidation, FxValidatorService } from '@instantsys-labs/fx';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'lib-button',
|
|
7
|
+
standalone: true,
|
|
8
|
+
imports: [CommonModule],
|
|
9
|
+
templateUrl: './button.component.html',
|
|
10
|
+
styleUrl: './button.component.css'
|
|
11
|
+
})
|
|
12
|
+
export class ButtonComponent extends FxBaseComponent {
|
|
13
|
+
constructor(private cdr: ChangeDetectorRef) {
|
|
14
|
+
super(cdr)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
protected settings(): FxSetting[] {
|
|
18
|
+
return [new FxStringSetting({ key: 'heading-text', $title: 'Heading Text', value: 'My Default Value' })];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
protected validations(): FxValidation[] {
|
|
22
|
+
return [FxValidatorService.required];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<fx-settings-panel [fxData]="fxData" (configuration)="onChangeConfiguration($event)">
|
|
2
|
+
<div style="padding: 0 1.5rem;" *ngIf="fxData">
|
|
3
|
+
<table style="width: 100%;">
|
|
4
|
+
<thead>
|
|
5
|
+
<tr>
|
|
6
|
+
<th *ngFor="let column of tableConfig.columns">{{ column.header }}</th>
|
|
7
|
+
</tr>
|
|
8
|
+
</thead>
|
|
9
|
+
<tbody>
|
|
10
|
+
<tr *ngFor="let row of tableConfig.rows; let rowIndex = index">
|
|
11
|
+
<td style="text-align: center;" *ngFor="let column of tableConfig.columns">
|
|
12
|
+
<ng-container [ngSwitch]="column.cellType">
|
|
13
|
+
<span [class]="column?.className" *ngSwitchCase="'text'">{{row[column.header]}}</span>
|
|
14
|
+
|
|
15
|
+
<input [class]="column?.className" *ngSwitchCase="'input-text'"
|
|
16
|
+
[(ngModel)]="row[column.header]" />
|
|
17
|
+
|
|
18
|
+
<input [class]="column?.className" *ngSwitchCase="'input-number'" type="number"
|
|
19
|
+
[(ngModel)]="row[column.header]" />
|
|
20
|
+
|
|
21
|
+
<select [class]="column?.className" *ngSwitchCase="'dropdown'"
|
|
22
|
+
[(ngModel)]="row[column.header]">
|
|
23
|
+
<option *ngFor="let option of column?.options" [value]="option?.optionValue">
|
|
24
|
+
{{ option?.optionName }}
|
|
25
|
+
</option>
|
|
26
|
+
</select>
|
|
27
|
+
|
|
28
|
+
<select [class]="column?.className" style="width: 60%;" *ngSwitchCase="'smart-dropdown'"
|
|
29
|
+
[(ngModel)]="row[column.header]">
|
|
30
|
+
<option *ngFor="let option of smartDropdownOptions[column.header]" [value]="option?.value">
|
|
31
|
+
{{option?.name }}
|
|
32
|
+
</option>
|
|
33
|
+
</select>
|
|
34
|
+
|
|
35
|
+
<input [class]="column?.className" *ngSwitchCase="'checkbox'" type="checkbox"
|
|
36
|
+
[(ngModel)]="row[column.header]" />
|
|
37
|
+
|
|
38
|
+
<input name="radio-{{rowIndex}}" [class]="column?.className" *ngSwitchCase="'radio'" type="radio"
|
|
39
|
+
[(ngModel)]="row[column.header]" />
|
|
40
|
+
|
|
41
|
+
<div [class]="column?.className" style="display: flex; justify-content: center; gap: 10px;"
|
|
42
|
+
*ngSwitchCase="'radio-group'">
|
|
43
|
+
<label *ngFor="let option of column.options">
|
|
44
|
+
<input name="radio-group-{{rowIndex}}" type="radio" [value]="option?.optionName"
|
|
45
|
+
[(ngModel)]="row[column.header]" />
|
|
46
|
+
{{ option?.optionName }}
|
|
47
|
+
</label>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<ng-container *ngSwitchCase="'file-upload'">
|
|
51
|
+
<div style="display: flex; flex-direction: column; align-items: center;">
|
|
52
|
+
<img width="100" *ngIf="uploadedImages[rowIndex]" [src]="uploadedImages[rowIndex]"
|
|
53
|
+
alt="Uploaded Image" (click)="deleteFile(uploadedImages[rowIndex], rowIndex)"/>
|
|
54
|
+
<input [class]="column?.className" type="file" name="file" #uploadFile [(ngModel)]="row[column.header]" hidden multiple
|
|
55
|
+
(change)="uploadImage($event, rowIndex)" />
|
|
56
|
+
<button (click)="uploadFile.click()">Upload</button>
|
|
57
|
+
</div>
|
|
58
|
+
</ng-container>
|
|
59
|
+
|
|
60
|
+
<ng-container *ngSwitchCase="'textarea'">
|
|
61
|
+
<textarea [class]="column?.className" name="" id="" cols="30" rows="2"></textarea>
|
|
62
|
+
</ng-container>
|
|
63
|
+
</ng-container>
|
|
64
|
+
</td>
|
|
65
|
+
</tr>
|
|
66
|
+
</tbody>
|
|
67
|
+
</table>
|
|
68
|
+
</div>
|
|
69
|
+
</fx-settings-panel>
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { AfterViewInit, ChangeDetectorRef, Component, inject, Input, NgZone, OnDestroy, OnInit } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import { HttpClient } from '@angular/common/http';
|
|
5
|
+
import { FxBaseComponent, FxMode, FxSetting, FxStringSetting, FxValidation, FxValidatorService } from '@instantsys-labs/fx';
|
|
6
|
+
import { SettingsPanelComponent } from '../../panel/settings-panel/settings-panel.component';
|
|
7
|
+
import { FxBuilderWrapperService } from '../../fx-builder-wrapper.service';
|
|
8
|
+
import {Subject, takeUntil } from 'rxjs';
|
|
9
|
+
|
|
10
|
+
export interface TableColumnConfig {
|
|
11
|
+
header: string;
|
|
12
|
+
cellType: 'text' | 'input-text' | 'input-number' | 'dropdown' | 'smart-dropdown' | 'checkbox' | 'radio' | 'radio-group' | 'file-upload' | 'textarea';
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
options?: string[];
|
|
15
|
+
apiUrl?: string;
|
|
16
|
+
valueKey?: string;
|
|
17
|
+
labelKey?: string;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface TableConfig {
|
|
21
|
+
columns: TableColumnConfig[];
|
|
22
|
+
rows: any[];
|
|
23
|
+
}
|
|
24
|
+
@Component({
|
|
25
|
+
selector: 'fx-dynamic-table',
|
|
26
|
+
standalone: true,
|
|
27
|
+
imports: [CommonModule, FormsModule, SettingsPanelComponent, ReactiveFormsModule],
|
|
28
|
+
templateUrl: './dynamic-table.component.html',
|
|
29
|
+
styleUrl: './dynamic-table.component.css',
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
export class DynamicTableComponent extends FxBaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
33
|
+
@Input() tableRows: Array<any> = [];
|
|
34
|
+
@Input() previewType: FxMode = FxMode.VIEW;
|
|
35
|
+
@Input() tableConfig: any = {
|
|
36
|
+
columns: [
|
|
37
|
+
{ header: 'Column 1', cellType: 'text' },
|
|
38
|
+
{ header: 'Column 2', cellType: 'text' },
|
|
39
|
+
{ header: 'Column 3', cellType: 'text' },
|
|
40
|
+
{ header: 'Column 4', cellType: 'text' },
|
|
41
|
+
{ header: 'Column 5', cellType: 'text' },
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
private destroy$ = new Subject<Boolean>();
|
|
46
|
+
public uploadedImages: Array<string | null> = [];
|
|
47
|
+
public tableFormControl = new FormControl();
|
|
48
|
+
public smartDropdownOptions: { [key: string]: Array<{ name: string, value: string }> } = {};
|
|
49
|
+
private http = inject(HttpClient);
|
|
50
|
+
constructor(private cdr: ChangeDetectorRef, private fxBuilderWrapperService: FxBuilderWrapperService) {
|
|
51
|
+
super(cdr);
|
|
52
|
+
this.onInit.subscribe((fxData)=>{
|
|
53
|
+
this._register(this.tableFormControl);
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public ngOnInit(): void {
|
|
58
|
+
this.fxBuilderWrapperService.variables$.pipe(
|
|
59
|
+
takeUntil(this.destroy$)).subscribe((variables: any) => {
|
|
60
|
+
if(variables) {
|
|
61
|
+
let dynamicTableValues: any;
|
|
62
|
+
for(const [key, value] of Object.entries(variables)) {
|
|
63
|
+
if(key.includes('dynamic-table')) {
|
|
64
|
+
dynamicTableValues = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if(Object.keys(dynamicTableValues).length) {
|
|
68
|
+
const fileHeaderName = dynamicTableValues?.columns.find((f: any) => f.cellType === 'file-upload')?.header;
|
|
69
|
+
dynamicTableValues?.rows?.forEach((item: any, index: number) => {
|
|
70
|
+
this.uploadedImages[index] = item[fileHeaderName] ? item[fileHeaderName]: null;
|
|
71
|
+
})
|
|
72
|
+
this.tableConfig = dynamicTableValues;
|
|
73
|
+
this.fxData.value = this.tableConfig;
|
|
74
|
+
this.tableFormControl.reset();
|
|
75
|
+
this.tableFormControl.setValue(this.tableConfig);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public ngAfterViewInit(): void {
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
if(this.fxData?.value && Object.keys(this.fxData?.value)?.length != 0) {
|
|
84
|
+
this.tableConfig = this.fxData.value;
|
|
85
|
+
this.fetchSmartDropdownData();
|
|
86
|
+
}
|
|
87
|
+
}, 100)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
protected fetchSmartDropdownData(): void {
|
|
91
|
+
this.tableConfig.columns
|
|
92
|
+
.filter((column: TableColumnConfig) => column.cellType === 'smart-dropdown' && column?.apiUrl)
|
|
93
|
+
.forEach((column: TableColumnConfig) => {
|
|
94
|
+
this.http.get<any>(column.apiUrl!).subscribe((response: any) => {
|
|
95
|
+
this.smartDropdownOptions[column.header] = response.map((item: any) => ({
|
|
96
|
+
value: item[column.valueKey!],
|
|
97
|
+
name: item[column.labelKey!],
|
|
98
|
+
}));
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public uploadImage(event: Event, rowIndex: number): void {
|
|
104
|
+
const file = (event.target as HTMLInputElement).files?.[0];
|
|
105
|
+
if (file) {
|
|
106
|
+
const reader = new FileReader();
|
|
107
|
+
reader.onload = () => {
|
|
108
|
+
this.uploadedImages[rowIndex] = reader.result as string;
|
|
109
|
+
};
|
|
110
|
+
reader.readAsDataURL(file);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
protected settings(): FxSetting[] {
|
|
115
|
+
return [
|
|
116
|
+
new FxStringSetting({ key: 'column-size', $title: 'No. of columns', value: 1 }),
|
|
117
|
+
new FxStringSetting({ key: 'table-config', $title: 'Table Configuration', value: {} }),
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
protected validations(): FxValidation[] {
|
|
122
|
+
return [FxValidatorService.required];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public getArray(count: number): number[] {
|
|
126
|
+
return Array.from({ length: count });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public onChangeConfiguration(event: any): void {
|
|
130
|
+
const columns = event.columns.map((col: any) => {
|
|
131
|
+
return {
|
|
132
|
+
header: col?.header,
|
|
133
|
+
cellType: col?.cellType,
|
|
134
|
+
placeholder: col?.placeholder,
|
|
135
|
+
options: col?.options,
|
|
136
|
+
apiUrl: col?.apiUrl,
|
|
137
|
+
valueKey: col?.valueKey,
|
|
138
|
+
labelKey: col?.labelKey,
|
|
139
|
+
className: col?.className,
|
|
140
|
+
apiKey: col?.apiKey
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
if(!event?.enableAPI) {
|
|
144
|
+
this.tableConfig.columns = columns;
|
|
145
|
+
this.tableConfig.rows = Array.from({ length: +event?.rows }, (e, index) => ({ name: `SKU-${index + 1}`, age: index % 2 !== 0, gender: 'male' }))
|
|
146
|
+
this.fetchSmartDropdownData();
|
|
147
|
+
}
|
|
148
|
+
if(event?.enableAPI) {
|
|
149
|
+
this.drawTable(event, columns)
|
|
150
|
+
this.tableConfig = {
|
|
151
|
+
columns: columns,
|
|
152
|
+
rows: []
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.fxData.value = this.tableConfig;
|
|
157
|
+
this.tableFormControl.reset();
|
|
158
|
+
this.tableFormControl.setValue(this.tableConfig);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private updateSettings(): void{
|
|
162
|
+
if(this.fxData.settings){
|
|
163
|
+
for(let setting of this.fxData.settings){
|
|
164
|
+
if(setting.key === 'table-config'){
|
|
165
|
+
setting.value = this.tableConfig;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public drawTable(event: any, columns: any): void {
|
|
172
|
+
let rows;
|
|
173
|
+
this.http.get(event.api).subscribe((res: any) => {
|
|
174
|
+
if(res) {
|
|
175
|
+
rows = res.map((item: any) => {
|
|
176
|
+
const newObj: Record<string, any> = {};
|
|
177
|
+
columns.forEach((col: any) => {
|
|
178
|
+
newObj[col.header] = item[col.apiKey];
|
|
179
|
+
});
|
|
180
|
+
return newObj;
|
|
181
|
+
});
|
|
182
|
+
this.tableConfig = {
|
|
183
|
+
columns,
|
|
184
|
+
rows
|
|
185
|
+
}
|
|
186
|
+
this.fxData.value = this.tableConfig;
|
|
187
|
+
this.tableFormControl.reset();
|
|
188
|
+
this.tableFormControl.setValue(this.tableConfig);
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
public deleteFile(file: any, index: number): void {
|
|
194
|
+
this.uploadedImages.splice(index, 1, null);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public ngOnDestroy(): void {
|
|
198
|
+
this.destroy$.next(true);
|
|
199
|
+
this.destroy$.complete();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
|
|
3
|
+
import { FxForm, FxFormComponent } from '@instantsys-labs/fx';
|
|
4
|
+
import { DispatchToClinicComponent } from '../../custom-controls/dispatch-to-clinic/dispatch-to-clinic.component';
|
|
5
|
+
import { FxBuilderWrapperService } from '../../fx-builder-wrapper.service';
|
|
6
|
+
import { DynamicTableComponent } from '../dynamic-table/dynamic-table.component';
|
|
7
|
+
import { ToggleButtonComponent } from '../toggle-button/toggle-button.component';
|
|
8
|
+
import { UploaderComponent } from '../uploader/uploader.component';
|
|
9
|
+
import { ToggleComponent } from '../toggle/toggle.component';
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: 'fx-form-component',
|
|
13
|
+
standalone: true,
|
|
14
|
+
imports: [CommonModule, FxFormComponent],
|
|
15
|
+
template: `
|
|
16
|
+
<fx-form
|
|
17
|
+
[fxForm]="fxForm"
|
|
18
|
+
[value]="variables"
|
|
19
|
+
(onSubmit)="onSubmit($event)"
|
|
20
|
+
#form
|
|
21
|
+
>
|
|
22
|
+
</fx-form>
|
|
23
|
+
`,
|
|
24
|
+
})
|
|
25
|
+
export class FxFormWrapperComponent implements OnChanges, OnInit {
|
|
26
|
+
@ViewChild('form') form!: FxFormComponent;
|
|
27
|
+
@Input() fxForm!: FxForm;
|
|
28
|
+
@Input() variables: any;
|
|
29
|
+
@Output() fxFormSubmit = new EventEmitter<any>();
|
|
30
|
+
|
|
31
|
+
constructor(private fxWrapperService: FxBuilderWrapperService) { }
|
|
32
|
+
|
|
33
|
+
public ngOnChanges(changes: SimpleChanges): void {
|
|
34
|
+
if('variables' in changes && !changes['fxForm']) {
|
|
35
|
+
this.fxWrapperService.variables$.next(this.variables);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public ngOnInit(): void {
|
|
40
|
+
if (!Boolean(this.fxWrapperService.getComponent('dispatch-to-clinic'))) {
|
|
41
|
+
this.fxWrapperService.registerCustomComponent('Dispatch To Clinic', 'dispatch-to-clinic', DispatchToClinicComponent);
|
|
42
|
+
}
|
|
43
|
+
if (!Boolean(this.fxWrapperService.getComponent('dynamic-table'))) {
|
|
44
|
+
this.fxWrapperService.registerCustomComponent('Dynamic Table', 'dynamic-table', DynamicTableComponent);
|
|
45
|
+
}
|
|
46
|
+
if (!Boolean(this.fxWrapperService.getComponent('toggle-button'))) {
|
|
47
|
+
this.fxWrapperService.registerCustomComponent('Toggle Button', 'toggle-button', ToggleButtonComponent);
|
|
48
|
+
}
|
|
49
|
+
if (!Boolean(this.fxWrapperService.getComponent('uploader'))) {
|
|
50
|
+
this.fxWrapperService.registerCustomComponent('Uploader', 'uploader', UploaderComponent);
|
|
51
|
+
}
|
|
52
|
+
if (!Boolean(this.fxWrapperService.getComponent('toggle'))) {
|
|
53
|
+
this.fxWrapperService.registerCustomComponent('Toggle', 'toggle', ToggleComponent);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public onSubmit(event: any): void {
|
|
58
|
+
this.fxFormSubmit.emit(event);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public submit(): void {
|
|
62
|
+
this.form.submit();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
label {
|
|
2
|
+
position: relative;
|
|
3
|
+
white-space: nowrap;
|
|
4
|
+
border-radius: 0;
|
|
5
|
+
border: 0 solid #999999;
|
|
6
|
+
margin: 0 14px 0 0;
|
|
7
|
+
width: 120px;
|
|
8
|
+
height: auto;
|
|
9
|
+
padding: 0;
|
|
10
|
+
text-align: center;
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.form-radio {
|
|
15
|
+
background-color: #DAE6F0;
|
|
16
|
+
color: white;
|
|
17
|
+
box-shadow: none;
|
|
18
|
+
transition: background-color 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s;
|
|
19
|
+
border: 1px solid #DEDEDE;
|
|
20
|
+
padding: 9px 10px;
|
|
21
|
+
margin: 0;
|
|
22
|
+
white-space: nowrap;
|
|
23
|
+
width: 100%;
|
|
24
|
+
height: 38px;
|
|
25
|
+
background-image: none;
|
|
26
|
+
border-radius: 4px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.form-radio:checked {
|
|
30
|
+
background-color: #ADD8E6;
|
|
31
|
+
border-color: #9BBBD6;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.form-radio:focus {
|
|
35
|
+
box-shadow: 0 0 0 2px #fff, 0 0 0 4px #9dc1fb, 0 1px 2px 0 black;
|
|
36
|
+
background-color: #ADD8E6;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.form-radio:hover {
|
|
40
|
+
border-color: #4682B4;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
span {
|
|
44
|
+
position: absolute;
|
|
45
|
+
left: 0;
|
|
46
|
+
right: 0;
|
|
47
|
+
top: 8px;
|
|
48
|
+
bottom: 0;
|
|
49
|
+
margin: 0;
|
|
50
|
+
padding: 0;
|
|
51
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<fx-component [fxData]="fxData">
|
|
2
|
+
<div style="display: flex;">
|
|
3
|
+
<label>
|
|
4
|
+
<input [formControl]="toggleControl" type="radio" name="radio_grp" class="form-radio mr-3" value="true">
|
|
5
|
+
<span class="mt-1">{{setting('accept')}}</span>
|
|
6
|
+
</label>
|
|
7
|
+
<label>
|
|
8
|
+
<input [formControl]="toggleControl" type="radio" name="radio_grp" class="form-radio mr-3" value="false">
|
|
9
|
+
<span class="mt-1">{{setting('reject')}}</span>
|
|
10
|
+
</label>
|
|
11
|
+
</div>
|
|
12
|
+
</fx-component>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { ChangeDetectorRef, Component, inject } from '@angular/core';
|
|
3
|
+
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import { FxBaseComponent, FxComponent, FxSetting, FxStringSetting, FxValidation, FxValidatorService } from '@instantsys-labs/fx';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'fx-toggle',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [CommonModule, FxComponent, FormsModule, ReactiveFormsModule],
|
|
10
|
+
templateUrl: './toggle.component.html',
|
|
11
|
+
styleUrl: './toggle.component.css'
|
|
12
|
+
})
|
|
13
|
+
export class ToggleComponent extends FxBaseComponent {
|
|
14
|
+
public toggleControl = new FormControl<boolean>(false)
|
|
15
|
+
|
|
16
|
+
constructor(private cdr: ChangeDetectorRef) {
|
|
17
|
+
super(cdr)
|
|
18
|
+
this.onInit.subscribe((fxData)=>{
|
|
19
|
+
this._register(this.toggleControl);
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected settings(): FxSetting[] {
|
|
24
|
+
return [
|
|
25
|
+
new FxStringSetting({ key: 'accept', $title: 'Accept Text', value: 'Yes' }),
|
|
26
|
+
new FxStringSetting({ key: 'reject', $title: 'Reject Text', value: 'No' })
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
protected validations(): FxValidation[] {
|
|
31
|
+
return [FxValidatorService.required];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.custom-toggle-btn {
|
|
2
|
+
padding: 10px 20px;
|
|
3
|
+
font-size: 16px;
|
|
4
|
+
font-weight: bold;
|
|
5
|
+
color: white;
|
|
6
|
+
border: none;
|
|
7
|
+
border-radius: 5px;
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
background-color: #ccc;
|
|
10
|
+
transition: background-color 0.3s;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.custom-toggle-btn.active {
|
|
14
|
+
background-color: #4caf50;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.custom-toggle-btn:hover {
|
|
18
|
+
opacity: 0.9;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<fx-component [fxData]="fxData">
|
|
2
|
+
<button
|
|
3
|
+
class="custom-toggle-btn"
|
|
4
|
+
[class]="setting('classes') ? setting('classes'): ''"
|
|
5
|
+
[class.active]="toggleBtnControl.value"
|
|
6
|
+
(click)="toggle()"
|
|
7
|
+
>
|
|
8
|
+
{{ toggleBtnControl.value ? setting('active-text') : setting('inactive-text') }}
|
|
9
|
+
</button>
|
|
10
|
+
</fx-component>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core';
|
|
3
|
+
import { FormControl, FormsModule, ReactiveFormsModule, UntypedFormControl } from '@angular/forms';
|
|
4
|
+
import { FxBaseComponent, FxComponent, FxIconSetting, FxSetting, FxStringSetting, FxValidation, FxValidatorService } from '@instantsys-labs/fx';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'lib-toggle-button',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [CommonModule, FxComponent, ReactiveFormsModule, FormsModule],
|
|
10
|
+
templateUrl: './toggle-button.component.html',
|
|
11
|
+
styleUrl: './toggle-button.component.css'
|
|
12
|
+
})
|
|
13
|
+
export class ToggleButtonComponent extends FxBaseComponent {
|
|
14
|
+
public toggleBtnControl = new UntypedFormControl(false);
|
|
15
|
+
public isToggled = false;
|
|
16
|
+
|
|
17
|
+
constructor(private cdr: ChangeDetectorRef) {
|
|
18
|
+
super(cdr);
|
|
19
|
+
this.onInit.subscribe((fxData)=>{
|
|
20
|
+
this._register(this.toggleBtnControl);
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public toggle(): void {
|
|
25
|
+
this.isToggled = !this.toggleBtnControl.value;
|
|
26
|
+
this.toggleBtnControl.setValue(this.isToggled);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
protected settings(): FxSetting[] {
|
|
30
|
+
return [
|
|
31
|
+
new FxStringSetting({ key: 'classes', $title: 'Classes', value: '' }),
|
|
32
|
+
new FxStringSetting({ key: 'active-text', $title: 'Active Text', value: 'On' }),
|
|
33
|
+
new FxStringSetting({ key: 'inactive-text', $title: 'Inactive Text', value: 'Off' }),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
protected validations(): FxValidation[] {
|
|
38
|
+
return [FxValidatorService.required];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
.custom-upload {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: row;
|
|
4
|
+
align-items: flex-start;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.custom-upload button {
|
|
8
|
+
padding: 10px 20px;
|
|
9
|
+
font-size: 16px;
|
|
10
|
+
font-weight: bold;
|
|
11
|
+
color: white;
|
|
12
|
+
background-color: #007bff;
|
|
13
|
+
border: none;
|
|
14
|
+
border-radius: 5px;
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
transition: background-color 0.3s;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.custom-upload button:hover {
|
|
20
|
+
background-color: #0056b3;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.custom-upload .file-list {
|
|
24
|
+
display: flex;
|
|
25
|
+
/* margin-top: 10px; */
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.custom-upload .file-list p {
|
|
29
|
+
margin: 0;
|
|
30
|
+
padding: 5px;
|
|
31
|
+
background-color: #f1f1f1;
|
|
32
|
+
border: 1px solid #ddd;
|
|
33
|
+
border-radius: 3px;
|
|
34
|
+
font-size: 14px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.custom-upload .file-list > div {
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
align-items: center;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.custom-upload .file-list .file-thumbnail {
|
|
45
|
+
width: 100px;
|
|
46
|
+
height: 100px;
|
|
47
|
+
object-fit: contain;
|
|
48
|
+
}
|
|
49
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<fx-component [fxData]="fxData">
|
|
2
|
+
<div class="custom-upload">
|
|
3
|
+
<button type="button" (click)="fileInput.click()">
|
|
4
|
+
{{setting('upload-text')}}
|
|
5
|
+
</button>
|
|
6
|
+
<input
|
|
7
|
+
#fileInput
|
|
8
|
+
type="file"
|
|
9
|
+
[multiple]="setting('multiple-upload')"
|
|
10
|
+
(change)="onFileSelected($event)"
|
|
11
|
+
[formControl]="uploadFileControl"
|
|
12
|
+
hidden
|
|
13
|
+
/>
|
|
14
|
+
<div class="file-list">
|
|
15
|
+
<ng-container *ngIf="uploadedFiles?.length">
|
|
16
|
+
<div (click)="deleteFile(file?.id)" *ngFor="let file of uploadedFiles">
|
|
17
|
+
<img class="file-thumbnail" style="border-radius: 4px" [src]="file?.previewUrl" alt="">
|
|
18
|
+
<!-- <p>{{file?.name}}</p> -->
|
|
19
|
+
</div>
|
|
20
|
+
</ng-container>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</fx-component>
|