@elite.framework/ng.core 1.0.63 → 2.0.1
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 +2 -22
- package/directives/README.md +3 -0
- package/directives/index.d.ts +23 -0
- package/fesm2022/elite.framework-ng.core-directives.mjs +59 -0
- package/fesm2022/elite.framework-ng.core-directives.mjs.map +1 -0
- package/fesm2022/elite.framework-ng.core-models.mjs +47 -0
- package/fesm2022/elite.framework-ng.core-models.mjs.map +1 -0
- package/fesm2022/elite.framework-ng.core-pipes.mjs +135 -0
- package/fesm2022/elite.framework-ng.core-pipes.mjs.map +1 -0
- package/fesm2022/elite.framework-ng.core-providers.mjs +18 -0
- package/fesm2022/elite.framework-ng.core-providers.mjs.map +1 -0
- package/fesm2022/elite.framework-ng.core-services.mjs +509 -0
- package/fesm2022/elite.framework-ng.core-services.mjs.map +1 -0
- package/fesm2022/elite.framework-ng.core-tokens.mjs +17 -0
- package/fesm2022/elite.framework-ng.core-tokens.mjs.map +1 -0
- package/fesm2022/elite.framework-ng.core.mjs +7 -980
- package/fesm2022/elite.framework-ng.core.mjs.map +1 -1
- package/index.d.ts +4 -179
- package/models/README.md +3 -0
- package/models/index.d.ts +135 -0
- package/package.json +24 -216
- package/pipes/README.md +3 -0
- package/pipes/index.d.ts +20 -0
- package/providers/README.md +3 -0
- package/providers/index.d.ts +6 -0
- package/services/README.md +3 -0
- package/services/index.d.ts +250 -0
- package/tokens/README.md +3 -0
- package/tokens/index.d.ts +15 -0
|
@@ -1,991 +1,18 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import * as i1 from '@angular/common';
|
|
4
|
-
import { CommonModule } from '@angular/common';
|
|
5
|
-
import * as i2$1 from '@angular/forms';
|
|
6
|
-
import { ReactiveFormsModule, FormsModule, FormGroup } from '@angular/forms';
|
|
7
|
-
import { FormlyPrimeNGModule } from '@ngx-formly/primeng';
|
|
8
|
-
import * as i2 from 'primeng/button';
|
|
9
|
-
import { ButtonModule } from 'primeng/button';
|
|
10
|
-
import { Subject, takeUntil } from 'rxjs';
|
|
11
|
-
import { ProgressSpinnerModule } from 'primeng/progressspinner';
|
|
12
|
-
import { MessageModule } from 'primeng/message';
|
|
13
|
-
import * as i3 from 'primeng/splitbutton';
|
|
14
|
-
import { SplitButtonModule } from 'primeng/splitbutton';
|
|
15
|
-
import { FormlyForm, FieldType, FormlyAttributes } from '@ngx-formly/core';
|
|
16
|
-
import * as i3$1 from '@ngx-translate/core';
|
|
17
|
-
import { TranslateService, TranslateModule } from '@ngx-translate/core';
|
|
18
|
-
import * as i1$1 from 'primeng/dynamicdialog';
|
|
19
|
-
import Swal from 'sweetalert2';
|
|
20
|
-
import { Router, ActivatedRoute } from '@angular/router';
|
|
2
|
+
import { Component } from '@angular/core';
|
|
21
3
|
|
|
22
|
-
class
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
model;
|
|
26
|
-
type = 'button';
|
|
27
|
-
icon = '';
|
|
28
|
-
label = '';
|
|
29
|
-
variant = 'raised';
|
|
30
|
-
severity = 'primary';
|
|
31
|
-
size = 'normal';
|
|
32
|
-
iconPosition = 'left';
|
|
33
|
-
disabled = false;
|
|
34
|
-
loading = false;
|
|
35
|
-
ariaLabel;
|
|
36
|
-
extraClasses = ''; // لأي Tailwind إضافي
|
|
37
|
-
permission;
|
|
38
|
-
clicked = new EventEmitter();
|
|
39
|
-
itemClick = new EventEmitter();
|
|
40
|
-
// خريطة أحجام
|
|
41
|
-
sizeMap = {
|
|
42
|
-
small: 'px-2 py-1 text-sm',
|
|
43
|
-
normal: 'px-4 py-2 text-base',
|
|
44
|
-
large: 'px-6 py-3 text-lg',
|
|
45
|
-
};
|
|
46
|
-
// خريطة ألوان للـ raised و rounded
|
|
47
|
-
colorMap = {
|
|
48
|
-
primary: 'bg-blue-600 hover:bg-blue-700 focus:ring-blue-500 text-white',
|
|
49
|
-
secondary: 'bg-gray-600 hover:bg-gray-700 focus:ring-gray-500 text-white',
|
|
50
|
-
success: 'bg-green-600 hover:bg-green-700 focus:ring-green-500 text-white',
|
|
51
|
-
info: 'bg-teal-600 hover:bg-teal-700 focus:ring-teal-500 text-white',
|
|
52
|
-
warning: 'bg-yellow-500 hover:bg-yellow-600 focus:ring-yellow-400 text-white',
|
|
53
|
-
danger: 'bg-red-600 hover:bg-red-700 focus:ring-red-500 text-white',
|
|
54
|
-
};
|
|
55
|
-
// خريطة حدوده للـ outlined
|
|
56
|
-
outlinedMap = {
|
|
57
|
-
primary: 'border border-blue-600 text-blue-600 hover:bg-blue-50 focus:ring-blue-500',
|
|
58
|
-
secondary: 'border border-gray-600 text-gray-600 hover:bg-gray-50 focus:ring-gray-500',
|
|
59
|
-
success: 'border border-green-600 text-green-600 hover:bg-green-50 focus:ring-green-500',
|
|
60
|
-
info: 'border border-teal-600 text-teal-600 hover:bg-teal-50 focus:ring-teal-500',
|
|
61
|
-
warning: 'border border-yellow-500 text-yellow-500 hover:bg-yellow-50 focus:ring-yellow-400',
|
|
62
|
-
danger: 'border border-red-600 text-red-600 hover:bg-red-50 focus:ring-red-500',
|
|
63
|
-
};
|
|
64
|
-
get twClasses() {
|
|
65
|
-
const base = [
|
|
66
|
-
'inline-flex items-center justify-center font-medium',
|
|
67
|
-
'focus:outline-none focus:ring-2 focus:ring-offset-2 transition',
|
|
68
|
-
this.sizeMap[this.size]
|
|
69
|
-
];
|
|
70
|
-
// variant-specific
|
|
71
|
-
if (this.variant === 'outlined') {
|
|
72
|
-
base.push(this.outlinedMap[this.severity]);
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
base.push(this.colorMap[this.severity]);
|
|
76
|
-
}
|
|
77
|
-
if (this.variant === 'text') {
|
|
78
|
-
base.push('bg-transparent hover:bg-gray-100 focus:ring-gray-200 text-gray-700');
|
|
79
|
-
}
|
|
80
|
-
if (this.variant === 'rounded') {
|
|
81
|
-
base.push('rounded-full');
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
base.push('rounded-md');
|
|
85
|
-
}
|
|
86
|
-
if (this.disabled || this.loading) {
|
|
87
|
-
base.push('opacity-50 cursor-not-allowed');
|
|
88
|
-
}
|
|
89
|
-
if (this.extraClasses) {
|
|
90
|
-
base.push(this.extraClasses);
|
|
91
|
-
}
|
|
92
|
-
return base.join(' ');
|
|
93
|
-
}
|
|
94
|
-
onClick() {
|
|
95
|
-
if (!this.disabled && !this.loading) {
|
|
96
|
-
this.clicked.emit();
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
onItemClick(evt) {
|
|
100
|
-
this.itemClick.emit(evt);
|
|
101
|
-
}
|
|
102
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: GenericButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
103
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: GenericButton, isStandalone: true, selector: "lib-generic-button", inputs: { model: "model", type: "type", icon: "icon", label: "label", variant: "variant", severity: "severity", size: "size", iconPosition: "iconPosition", disabled: "disabled", loading: "loading", ariaLabel: "ariaLabel", extraClasses: "extraClasses", permission: "permission" }, outputs: { clicked: "clicked", itemClick: "itemClick" }, ngImport: i0, template: "\n<!-- generic-button.component.html -->\n <!-- *hasPermission=\"permission\" -->\n<ng-container >\n <ng-container *ngIf=\"model?.length; else simpleBtn\">\n <!-- \u062D\u0627\u0644\u0629 \u0627\u0644\u0640 splitButton -->\n <p-splitButton\n [model]=\"model\"\n [icon]=\"icon\"\n [label]=\"label\"\n [styleClass]=\"twClasses\"\n [disabled]=\"disabled || loading\" (onClick)=\"onClick()\"\n (onClick)=\"onClick()\"\n (onItemClick)=\"onItemClick($event)\"\n ></p-splitButton>\n </ng-container>\n\n <ng-template #simpleBtn>\n <!-- \u062D\u0627\u0644\u0629 \u0627\u0644\u0632\u0631\u0651 \u0627\u0644\u0639\u0627\u062F\u064A -->\n <button\n [attr.type]=\"type\"\n pButton\n [icon]=\"loading ? 'pi pi-spin pi-spinner' : icon\"\n [label]=\"label\"\n [ngClass]=\"twClasses\"\n [attr.aria-label]=\"ariaLabel || label\"\n [disabled]=\"disabled || loading\" (onClick)=\"onClick()\"\n (click)=\"onClick()\"\n >\n\n <!-- \u0645\u062D\u062A\u0648\u0649 \u0645\u062E\u0635\u0651\u0635 -->\n <ng-content *ngIf=\"!label && !icon && !loading\"></ng-content>\n </button>\n </ng-template>\n </ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: SplitButtonModule }, { kind: "component", type: i3.SplitButton, selector: "p-splitbutton, p-splitButton, p-split-button", inputs: ["model", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "icon", "iconPos", "label", "tooltip", "tooltipOptions", "styleClass", "menuStyle", "menuStyleClass", "dropdownIcon", "appendTo", "dir", "expandAriaLabel", "showTransitionOptions", "hideTransitionOptions", "buttonProps", "menuButtonProps", "autofocus", "disabled", "tabindex", "menuButtonDisabled", "buttonDisabled"], outputs: ["onClick", "onMenuHide", "onMenuShow", "onDropdownClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4
|
+
class NgCore {
|
|
5
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: NgCore, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.8", type: NgCore, isStandalone: true, selector: "lib-ng-core", ngImport: i0, template: "<p>NgCore works!</p>\n", styles: [""] });
|
|
104
7
|
}
|
|
105
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.
|
|
8
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: NgCore, decorators: [{
|
|
106
9
|
type: Component,
|
|
107
|
-
args: [{ selector: 'lib-
|
|
108
|
-
}], propDecorators: { model: [{
|
|
109
|
-
type: Input
|
|
110
|
-
}], type: [{
|
|
111
|
-
type: Input
|
|
112
|
-
}], icon: [{
|
|
113
|
-
type: Input
|
|
114
|
-
}], label: [{
|
|
115
|
-
type: Input
|
|
116
|
-
}], variant: [{
|
|
117
|
-
type: Input
|
|
118
|
-
}], severity: [{
|
|
119
|
-
type: Input
|
|
120
|
-
}], size: [{
|
|
121
|
-
type: Input
|
|
122
|
-
}], iconPosition: [{
|
|
123
|
-
type: Input
|
|
124
|
-
}], disabled: [{
|
|
125
|
-
type: Input
|
|
126
|
-
}], loading: [{
|
|
127
|
-
type: Input
|
|
128
|
-
}], ariaLabel: [{
|
|
129
|
-
type: Input
|
|
130
|
-
}], extraClasses: [{
|
|
131
|
-
type: Input
|
|
132
|
-
}], permission: [{
|
|
133
|
-
type: Input
|
|
134
|
-
}], clicked: [{
|
|
135
|
-
type: Output
|
|
136
|
-
}], itemClick: [{
|
|
137
|
-
type: Output
|
|
138
|
-
}] } });
|
|
139
|
-
|
|
140
|
-
class GenericFormlyFields {
|
|
141
|
-
/** الـ FormGroup الذي يُدار خارجيًا */
|
|
142
|
-
form;
|
|
143
|
-
/** حقول Formly */
|
|
144
|
-
fields = [];
|
|
145
|
-
/** النموذج (object) الذي سيُربط بالحقول */
|
|
146
|
-
model = {};
|
|
147
|
-
/** خيارات Formly (validation, hideExpression, ...) */
|
|
148
|
-
options = {};
|
|
149
|
-
ngOnInit() {
|
|
150
|
-
// ما من حاجة هنا: يفترض أن form مُهيّأ في الخارج
|
|
151
|
-
}
|
|
152
|
-
ngOnChanges(changes) {
|
|
153
|
-
// لو احتجت تتعامل مع تغيّر الحقول أو الموديل، هنا المكان
|
|
154
|
-
}
|
|
155
|
-
// دالة مساعدة للوصول الآمن لخصائص الحقل
|
|
156
|
-
getFieldIcon(field) {
|
|
157
|
-
return field.templateOptions?.['icon'] || null;
|
|
158
|
-
}
|
|
159
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: GenericFormlyFields, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
160
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: GenericFormlyFields, isStandalone: true, selector: "lib-generic-formly-fields", inputs: { form: "form", fields: "fields", model: "model", options: "options" }, usesOnChanges: true, ngImport: i0, template: "<!-- \u064A\u0631\u0633\u0645 \u062D\u0642\u0648\u0644 Formly \u062F\u0627\u062E\u0644 \u0627\u0644\u0640 form \u0627\u0644\u0645\u0648\u062C\u0648\u062F -->\n<formly-form\n [form]=\"form\"\n [fields]=\"fields\"\n [model]=\"model\"\n [options]=\"options\">\n</formly-form>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }] });
|
|
161
|
-
}
|
|
162
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: GenericFormlyFields, decorators: [{
|
|
163
|
-
type: Component,
|
|
164
|
-
args: [{ selector: 'lib-generic-formly-fields', standalone: true, imports: [
|
|
165
|
-
CommonModule,
|
|
166
|
-
ReactiveFormsModule,
|
|
167
|
-
FormsModule,
|
|
168
|
-
FormlyForm,
|
|
169
|
-
// FormlyPrimeNGModule,
|
|
170
|
-
], template: "<!-- \u064A\u0631\u0633\u0645 \u062D\u0642\u0648\u0644 Formly \u062F\u0627\u062E\u0644 \u0627\u0644\u0640 form \u0627\u0644\u0645\u0648\u062C\u0648\u062F -->\n<formly-form\n [form]=\"form\"\n [fields]=\"fields\"\n [model]=\"model\"\n [options]=\"options\">\n</formly-form>\n" }]
|
|
171
|
-
}], propDecorators: { form: [{
|
|
172
|
-
type: Input
|
|
173
|
-
}], fields: [{
|
|
174
|
-
type: Input
|
|
175
|
-
}], model: [{
|
|
176
|
-
type: Input
|
|
177
|
-
}], options: [{
|
|
178
|
-
type: Input
|
|
179
|
-
}] } });
|
|
180
|
-
|
|
181
|
-
class GenericErrormessage {
|
|
182
|
-
/** نص رسالة الخطأ */
|
|
183
|
-
text = '';
|
|
184
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: GenericErrormessage, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
185
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: GenericErrormessage, isStandalone: true, selector: "lib-generic-errormessage", inputs: { text: "text" }, ngImport: i0, template: " \n@if (text) {\n<div class=\"bg-red-100 border border-red-300 text-red-800 px-4 py-3 rounded my-4\"> {{ text }} </div>\n}", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
186
|
-
}
|
|
187
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: GenericErrormessage, decorators: [{
|
|
188
|
-
type: Component,
|
|
189
|
-
args: [{ selector: 'lib-generic-errormessage', imports: [CommonModule], template: " \n@if (text) {\n<div class=\"bg-red-100 border border-red-300 text-red-800 px-4 py-3 rounded my-4\"> {{ text }} </div>\n}" }]
|
|
190
|
-
}], propDecorators: { text: [{
|
|
191
|
-
type: Input
|
|
192
|
-
}] } });
|
|
193
|
-
|
|
194
|
-
class GenericCrudDialog {
|
|
195
|
-
ref;
|
|
196
|
-
config;
|
|
197
|
-
form = new FormGroup({});
|
|
198
|
-
model = {};
|
|
199
|
-
fields = [];
|
|
200
|
-
options = {};
|
|
201
|
-
loading = false;
|
|
202
|
-
id = null;
|
|
203
|
-
errorMessage = null;
|
|
204
|
-
translate = inject(TranslateService);
|
|
205
|
-
destroy$ = new Subject();
|
|
206
|
-
idField;
|
|
207
|
-
constructor(ref, config) {
|
|
208
|
-
this.ref = ref;
|
|
209
|
-
this.config = config;
|
|
210
|
-
// استقبال البيانات من المكون الأب
|
|
211
|
-
this.fields = this.config.data.fields;
|
|
212
|
-
this.idField = this.config.data.idField;
|
|
213
|
-
this.model = this.config.data.item ? { ...this.config.data.item } : {};
|
|
214
|
-
// تحديد وضع العملية (تعديل أو إضافة)
|
|
215
|
-
// this.isEditMode = !!this.config.data.item;
|
|
216
|
-
try {
|
|
217
|
-
const id = this.model[this.idField];
|
|
218
|
-
this.id = id != undefined;
|
|
219
|
-
}
|
|
220
|
-
catch (error) {
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
onSubmit() {
|
|
224
|
-
if (this.form.invalid)
|
|
225
|
-
return;
|
|
226
|
-
this.loading = true;
|
|
227
|
-
this.errorMessage = null;
|
|
228
|
-
const service = this.config.data.service;
|
|
229
|
-
console.log('service:', service);
|
|
230
|
-
try {
|
|
231
|
-
this.id = this.model[this.idField];
|
|
232
|
-
}
|
|
233
|
-
catch (error) {
|
|
234
|
-
}
|
|
235
|
-
console.log('isEditMode:', this.id);
|
|
236
|
-
debugger;
|
|
237
|
-
const isEditMode = !!this.config.data.item;
|
|
238
|
-
const operation$ = isEditMode
|
|
239
|
-
? service.update(this.id, this.model)
|
|
240
|
-
: service.create(this.model);
|
|
241
|
-
operation$.pipe(takeUntil(this.destroy$)).subscribe({
|
|
242
|
-
next: () => {
|
|
243
|
-
this.ref.close(true); // نجاح العملية
|
|
244
|
-
},
|
|
245
|
-
error: (err) => {
|
|
246
|
-
this.loading = false;
|
|
247
|
-
this.errorMessage = err.error?.message ||
|
|
248
|
-
err.message ||
|
|
249
|
-
'حدث خطأ أثناء الحفظ. يرجى المحاولة مرة أخرى.';
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
ngOnDestroy() {
|
|
254
|
-
this.destroy$.next();
|
|
255
|
-
this.destroy$.complete();
|
|
256
|
-
}
|
|
257
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: GenericCrudDialog, deps: [{ token: i1$1.DynamicDialogRef }, { token: i1$1.DynamicDialogConfig }], target: i0.ɵɵFactoryTarget.Component });
|
|
258
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: GenericCrudDialog, isStandalone: true, selector: "app-generic-crud-dialog", ngImport: i0, template: " <div class=\"p-4\">\n @if (errorMessage) {\n <lib-generic-errormessage [text]=\"errorMessage\"></lib-generic-errormessage>\n }\n\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <!-- \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0627\u0644\u0645\u0643\u0648\u0646 \u0627\u0644\u0639\u0627\u0645 \u0644\u0644\u062D\u0642\u0648\u0644 -->\n <lib-generic-formly-fields\n [form]=\"form\"\n [fields]=\"fields\"\n [model]=\"model\"\n [options]=\"options\">\n </lib-generic-formly-fields>\n\n <div class=\"flex justify-end gap-2 mt-4\">\n\n <!-- \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0627\u0644\u0645\u0643\u0648\u0646 \u0627\u0644\u0639\u0627\u0645 \u0644\u0644\u0623\u0632\u0631\u0627\u0631 - \u0632\u0631 \u0627\u0644\u062D\u0641\u0638 -->\n <lib-generic-button\n variant=\"raised\"\n severity=\"primary\"\n type=\"submit\"\n [loading]=\"loading\"\n [disabled]=\"loading || form.invalid\"\n [label]=\"(id ? 'COMMON.UPDATE' : 'COMMON.SAVE') | translate\">\n </lib-generic-button>\n <!-- \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0627\u0644\u0645\u0643\u0648\u0646 \u0627\u0644\u0639\u0627\u0645 \u0644\u0644\u0623\u0632\u0631\u0627\u0631 - \u0632\u0631 \u0627\u0644\u0625\u0644\u063A\u0627\u0621 -->\n <lib-generic-button\n variant=\"text\"\n severity=\"secondary\"\n [disabled]=\"loading\"\n [label]=\"'COMMON.CANCEL' | translate\"\n (clicked)=\"ref.close(false)\">\n </lib-generic-button>\n\n </div>\n </form>\n </div>\n", styles: [":host{display:block}button{min-width:120px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyPrimeNGModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: GenericButton, selector: "lib-generic-button", inputs: ["model", "type", "icon", "label", "variant", "severity", "size", "iconPosition", "disabled", "loading", "ariaLabel", "extraClasses", "permission"], outputs: ["clicked", "itemClick"] }, { kind: "component", type: // إضافة المكون العام للأزرار
|
|
259
|
-
GenericFormlyFields, selector: "lib-generic-formly-fields", inputs: ["form", "fields", "model", "options"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: GenericErrormessage, selector: "lib-generic-errormessage", inputs: ["text"] }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
|
|
260
|
-
}
|
|
261
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: GenericCrudDialog, decorators: [{
|
|
262
|
-
type: Component,
|
|
263
|
-
args: [{ selector: 'app-generic-crud-dialog', standalone: true, imports: [
|
|
264
|
-
CommonModule,
|
|
265
|
-
ReactiveFormsModule,
|
|
266
|
-
FormlyPrimeNGModule,
|
|
267
|
-
ButtonModule,
|
|
268
|
-
ProgressSpinnerModule,
|
|
269
|
-
MessageModule,
|
|
270
|
-
GenericButton, // إضافة المكون العام للأزرار
|
|
271
|
-
GenericFormlyFields,
|
|
272
|
-
TranslateModule,
|
|
273
|
-
GenericErrormessage
|
|
274
|
-
], template: " <div class=\"p-4\">\n @if (errorMessage) {\n <lib-generic-errormessage [text]=\"errorMessage\"></lib-generic-errormessage>\n }\n\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <!-- \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0627\u0644\u0645\u0643\u0648\u0646 \u0627\u0644\u0639\u0627\u0645 \u0644\u0644\u062D\u0642\u0648\u0644 -->\n <lib-generic-formly-fields\n [form]=\"form\"\n [fields]=\"fields\"\n [model]=\"model\"\n [options]=\"options\">\n </lib-generic-formly-fields>\n\n <div class=\"flex justify-end gap-2 mt-4\">\n\n <!-- \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0627\u0644\u0645\u0643\u0648\u0646 \u0627\u0644\u0639\u0627\u0645 \u0644\u0644\u0623\u0632\u0631\u0627\u0631 - \u0632\u0631 \u0627\u0644\u062D\u0641\u0638 -->\n <lib-generic-button\n variant=\"raised\"\n severity=\"primary\"\n type=\"submit\"\n [loading]=\"loading\"\n [disabled]=\"loading || form.invalid\"\n [label]=\"(id ? 'COMMON.UPDATE' : 'COMMON.SAVE') | translate\">\n </lib-generic-button>\n <!-- \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0627\u0644\u0645\u0643\u0648\u0646 \u0627\u0644\u0639\u0627\u0645 \u0644\u0644\u0623\u0632\u0631\u0627\u0631 - \u0632\u0631 \u0627\u0644\u0625\u0644\u063A\u0627\u0621 -->\n <lib-generic-button\n variant=\"text\"\n severity=\"secondary\"\n [disabled]=\"loading\"\n [label]=\"'COMMON.CANCEL' | translate\"\n (clicked)=\"ref.close(false)\">\n </lib-generic-button>\n\n </div>\n </form>\n </div>\n", styles: [":host{display:block}button{min-width:120px}\n"] }]
|
|
275
|
-
}], ctorParameters: () => [{ type: i1$1.DynamicDialogRef }, { type: i1$1.DynamicDialogConfig }] });
|
|
276
|
-
|
|
277
|
-
class DeactivationReasonFormComponent {
|
|
278
|
-
ref;
|
|
279
|
-
config;
|
|
280
|
-
form = new FormGroup({});
|
|
281
|
-
model = {};
|
|
282
|
-
fields;
|
|
283
|
-
loading = false;
|
|
284
|
-
errorMessage = null;
|
|
285
|
-
destroy$ = new Subject();
|
|
286
|
-
idField;
|
|
287
|
-
constructor(ref, config) {
|
|
288
|
-
this.ref = ref;
|
|
289
|
-
this.config = config;
|
|
290
|
-
this.model = config.data?.model || {};
|
|
291
|
-
this.idField = this.config.data.idField;
|
|
292
|
-
this.fields = [
|
|
293
|
-
{
|
|
294
|
-
key: 'deactivationReason',
|
|
295
|
-
type: 'textarea',
|
|
296
|
-
props: {
|
|
297
|
-
label: 'DeactivationReason',
|
|
298
|
-
placeholder: 'DeactivationReason',
|
|
299
|
-
rows: 5,
|
|
300
|
-
required: true,
|
|
301
|
-
},
|
|
302
|
-
},
|
|
303
|
-
];
|
|
304
|
-
}
|
|
305
|
-
onSubmit() {
|
|
306
|
-
if (this.form.invalid)
|
|
307
|
-
return;
|
|
308
|
-
// this.loading = true;
|
|
309
|
-
// this.errorMessage = null;
|
|
310
|
-
const service = this.config.data.service;
|
|
311
|
-
const id = this.model[this.idField];
|
|
312
|
-
this.model.isActive = false;
|
|
313
|
-
const operation$ = service.update(id, this.model);
|
|
314
|
-
operation$.pipe(takeUntil(this.destroy$)).subscribe({
|
|
315
|
-
next: () => {
|
|
316
|
-
this.ref.close(this.model); // نجاح العملية
|
|
317
|
-
},
|
|
318
|
-
error: (err) => {
|
|
319
|
-
this.loading = false;
|
|
320
|
-
this.errorMessage = err.error?.message ||
|
|
321
|
-
err.message ||
|
|
322
|
-
'حدث خطأ أثناء الحفظ. يرجى المحاولة مرة أخرى.';
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
ngOnDestroy() {
|
|
327
|
-
this.destroy$.next();
|
|
328
|
-
this.destroy$.complete();
|
|
329
|
-
}
|
|
330
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DeactivationReasonFormComponent, deps: [{ token: i1$1.DynamicDialogRef }, { token: i1$1.DynamicDialogConfig }], target: i0.ɵɵFactoryTarget.Component });
|
|
331
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: DeactivationReasonFormComponent, isStandalone: true, selector: "app-deactivation-reason-form", ngImport: i0, template: `
|
|
332
|
-
<form [formGroup]="form" (ngSubmit)="onSubmit()" class="p-4 space-y-4">
|
|
333
|
-
<formly-form [form]="form" [fields]="fields" [model]="model"></formly-form>
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
<div class="bottom-0 left-0 right-0 bg-gray-200 border-t border-gray-400 px-4 py-3 flex justify-end gap-2">
|
|
337
|
-
|
|
338
|
-
<p-button
|
|
339
|
-
[label]="( 'SAVE') | translate"
|
|
340
|
-
size="small"
|
|
341
|
-
[disabled]="form.invalid"
|
|
342
|
-
[type]="'submit'">
|
|
343
|
-
</p-button>
|
|
344
|
-
|
|
345
|
-
<p-button
|
|
346
|
-
[label]="'CANCEL' | translate "
|
|
347
|
-
severity="danger"
|
|
348
|
-
size="small"
|
|
349
|
-
(onClick)="ref.close(false)">
|
|
350
|
-
</p-button>
|
|
351
|
-
|
|
352
|
-
</div>
|
|
353
|
-
</form>
|
|
354
|
-
`, isInline: true, dependencies: [{ kind: "component", type: FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
|
|
355
|
-
}
|
|
356
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DeactivationReasonFormComponent, decorators: [{
|
|
357
|
-
type: Component,
|
|
358
|
-
args: [{
|
|
359
|
-
selector: 'app-deactivation-reason-form',
|
|
360
|
-
template: `
|
|
361
|
-
<form [formGroup]="form" (ngSubmit)="onSubmit()" class="p-4 space-y-4">
|
|
362
|
-
<formly-form [form]="form" [fields]="fields" [model]="model"></formly-form>
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
<div class="bottom-0 left-0 right-0 bg-gray-200 border-t border-gray-400 px-4 py-3 flex justify-end gap-2">
|
|
366
|
-
|
|
367
|
-
<p-button
|
|
368
|
-
[label]="( 'SAVE') | translate"
|
|
369
|
-
size="small"
|
|
370
|
-
[disabled]="form.invalid"
|
|
371
|
-
[type]="'submit'">
|
|
372
|
-
</p-button>
|
|
373
|
-
|
|
374
|
-
<p-button
|
|
375
|
-
[label]="'CANCEL' | translate "
|
|
376
|
-
severity="danger"
|
|
377
|
-
size="small"
|
|
378
|
-
(onClick)="ref.close(false)">
|
|
379
|
-
</p-button>
|
|
380
|
-
|
|
381
|
-
</div>
|
|
382
|
-
</form>
|
|
383
|
-
`,
|
|
384
|
-
imports: [FormlyForm, CommonModule, ReactiveFormsModule, FormsModule, TranslateModule, ButtonModule]
|
|
385
|
-
}]
|
|
386
|
-
}], ctorParameters: () => [{ type: i1$1.DynamicDialogRef }, { type: i1$1.DynamicDialogConfig }] });
|
|
387
|
-
|
|
388
|
-
// app/shared/services/swal.service.ts
|
|
389
|
-
class SwalService {
|
|
390
|
-
/** رسالة تأكيد قبل تنفيذ إجراء */
|
|
391
|
-
confirm(title = 'هل أنت متأكد؟', text = 'لن يمكنك التراجع عن هذا الإجراء', confirmButtonText = 'نعم', cancelButtonText = 'إلغاء') {
|
|
392
|
-
return Swal.fire({
|
|
393
|
-
icon: 'warning',
|
|
394
|
-
title,
|
|
395
|
-
text,
|
|
396
|
-
showCancelButton: true,
|
|
397
|
-
confirmButtonText,
|
|
398
|
-
cancelButtonText,
|
|
399
|
-
// reverseButtons: true,
|
|
400
|
-
customClass: {
|
|
401
|
-
container: 'swal2-container' // ✅ أضف هذه الفئة
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
/** رسالة نجاح */
|
|
406
|
-
success(title, text, timer = 2000) {
|
|
407
|
-
return Swal.fire({
|
|
408
|
-
icon: 'success',
|
|
409
|
-
title,
|
|
410
|
-
text,
|
|
411
|
-
timer,
|
|
412
|
-
showConfirmButton: false,
|
|
413
|
-
customClass: {
|
|
414
|
-
container: 'swal2-container' // ✅ أضف هذه الفئة
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
/** رسالة خطأ */
|
|
419
|
-
error(title, text, footer) {
|
|
420
|
-
return Swal.fire({
|
|
421
|
-
icon: 'error',
|
|
422
|
-
title,
|
|
423
|
-
text,
|
|
424
|
-
footer,
|
|
425
|
-
customClass: {
|
|
426
|
-
container: 'swal2-container' // ✅ أضف هذه الفئة
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
/** رسالة معلومات */
|
|
431
|
-
info(title, text) {
|
|
432
|
-
return Swal.fire({
|
|
433
|
-
icon: 'info',
|
|
434
|
-
title,
|
|
435
|
-
text,
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
/** عرض نافذة SweetAlert2 بأي خيارات تريد */
|
|
439
|
-
alert(options) {
|
|
440
|
-
return Swal.fire(options);
|
|
441
|
-
}
|
|
442
|
-
/** Toast بسيط قابل لإعادة الاستخدام */
|
|
443
|
-
toast(title, icon = 'info', position = 'top-end', timer = 3000) {
|
|
444
|
-
const Toast = Swal.mixin({
|
|
445
|
-
toast: true,
|
|
446
|
-
position,
|
|
447
|
-
timer,
|
|
448
|
-
showConfirmButton: false,
|
|
449
|
-
});
|
|
450
|
-
Toast.fire({ icon, title });
|
|
451
|
-
}
|
|
452
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: SwalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
453
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: SwalService, providedIn: 'root' });
|
|
454
|
-
}
|
|
455
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: SwalService, decorators: [{
|
|
456
|
-
type: Injectable,
|
|
457
|
-
args: [{ providedIn: 'root' }]
|
|
458
|
-
}] });
|
|
459
|
-
|
|
460
|
-
// src/app/shared/components/base-crud.component.ts
|
|
461
|
-
class BaseCrud {
|
|
462
|
-
list = [];
|
|
463
|
-
paginator = true;
|
|
464
|
-
canLoad = true;
|
|
465
|
-
loading = false;
|
|
466
|
-
errorMsg = '';
|
|
467
|
-
first = 0;
|
|
468
|
-
rows = 10;
|
|
469
|
-
totalRecords = 0;
|
|
470
|
-
searchGlobal = '';
|
|
471
|
-
sort;
|
|
472
|
-
pageFilters = {};
|
|
473
|
-
currentFilters = {};
|
|
474
|
-
mode = '';
|
|
475
|
-
scrollHeight = '400px';
|
|
476
|
-
swalService = inject(SwalService);
|
|
477
|
-
dialogRef;
|
|
478
|
-
dialogVisible = false;
|
|
479
|
-
drawerVisible = false;
|
|
480
|
-
selectedItem = null;
|
|
481
|
-
defaultModel = null;
|
|
482
|
-
// selectedItem: T | any = {};
|
|
483
|
-
isViewMode = false;
|
|
484
|
-
isEditMode = false;
|
|
485
|
-
displayMode = 'drawer';
|
|
486
|
-
router = inject(Router);
|
|
487
|
-
route = inject(ActivatedRoute);
|
|
488
|
-
loadPage(pageIndex, pageSize) {
|
|
489
|
-
if (this.canLoad) {
|
|
490
|
-
this.loading = true;
|
|
491
|
-
var filters = {
|
|
492
|
-
maxResultCount: pageSize,
|
|
493
|
-
skipCount: pageIndex,
|
|
494
|
-
sorting: this.sort,
|
|
495
|
-
...this.currentFilters,
|
|
496
|
-
...this.pageFilters,
|
|
497
|
-
...(this.searchGlobal ? { filter: this.searchGlobal } : {}),
|
|
498
|
-
};
|
|
499
|
-
//
|
|
500
|
-
this.service.getList(filters)
|
|
501
|
-
.subscribe({
|
|
502
|
-
next: (res) => {
|
|
503
|
-
//
|
|
504
|
-
this.list = res.items;
|
|
505
|
-
this.totalRecords = res.totalCount;
|
|
506
|
-
this.loading = false;
|
|
507
|
-
},
|
|
508
|
-
error: err => {
|
|
509
|
-
this.errorMsg = err.error?.message || err.message || 'خطأ في التحميل';
|
|
510
|
-
this.loading = false;
|
|
511
|
-
}
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
onSearch(filters) {
|
|
516
|
-
//
|
|
517
|
-
if (filters && typeof filters === 'object' && !Array.isArray(filters)) {
|
|
518
|
-
this.pageFilters = filters;
|
|
519
|
-
}
|
|
520
|
-
else {
|
|
521
|
-
this.searchGlobal = filters;
|
|
522
|
-
}
|
|
523
|
-
this.loadPage(0, 10);
|
|
524
|
-
}
|
|
525
|
-
onPageChange(event) {
|
|
526
|
-
// فك المتغيّرات مع قيمة افتراضية لفلاتر
|
|
527
|
-
const { first = this.first, rows = this.rows, sort = this.sort, filters = {} } = event;
|
|
528
|
-
this.first = first;
|
|
529
|
-
this.rows = rows;
|
|
530
|
-
this.sort = sort;
|
|
531
|
-
// const pageIndex = Math.floor(first / rows);
|
|
532
|
-
const skipCount = first;
|
|
533
|
-
const pageIndex = skipCount;
|
|
534
|
-
// الوصول للفلتر العام عبر الصيغة المربعة
|
|
535
|
-
const globalValue = filters['global'];
|
|
536
|
-
this.searchGlobal = typeof globalValue === 'string' ? globalValue : '';
|
|
537
|
-
// فلترة خاصة بحقل واحد
|
|
538
|
-
// const fieldFilters = { ...filters };
|
|
539
|
-
// delete fieldFilters['global'];
|
|
540
|
-
// this.currentFilters = fieldFilters as Partial<F>;
|
|
541
|
-
this.loadPage(pageIndex, rows);
|
|
542
|
-
}
|
|
543
|
-
openEditor(item, mode) {
|
|
544
|
-
this.mode = mode;
|
|
545
|
-
this.selectedItem = item ?? this.defaultModel ?? {};
|
|
546
|
-
this.isEditMode = mode === 'edit';
|
|
547
|
-
this.isViewMode = mode === 'view';
|
|
548
|
-
// resolve displayMode (string or map)
|
|
549
|
-
const modeConfig = typeof this.displayMode === 'string'
|
|
550
|
-
? this.displayMode
|
|
551
|
-
: this.displayMode[mode] ?? 'drawer';
|
|
552
|
-
switch (modeConfig) {
|
|
553
|
-
case 'drawer':
|
|
554
|
-
this.drawerVisible = true;
|
|
555
|
-
break;
|
|
556
|
-
case 'dialog':
|
|
557
|
-
this.dialogVisible = true;
|
|
558
|
-
break;
|
|
559
|
-
case 'route':
|
|
560
|
-
const id = item ? item[this.idField] : 'new';
|
|
561
|
-
if (mode === 'add') {
|
|
562
|
-
this.router.navigate([mode], { relativeTo: this.route });
|
|
563
|
-
}
|
|
564
|
-
else {
|
|
565
|
-
this.router.navigate([id, mode], { relativeTo: this.route });
|
|
566
|
-
}
|
|
567
|
-
break;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
visibleChange(value) {
|
|
571
|
-
const modeConfig = typeof this.displayMode === 'string'
|
|
572
|
-
? this.displayMode
|
|
573
|
-
: this.displayMode[this.mode] ?? 'drawer';
|
|
574
|
-
if (modeConfig === 'dialog') {
|
|
575
|
-
this.dialogVisible = value;
|
|
576
|
-
}
|
|
577
|
-
else if (modeConfig === 'drawer') {
|
|
578
|
-
this.drawerVisible = value;
|
|
579
|
-
}
|
|
580
|
-
else {
|
|
581
|
-
// route mode does not use drawer/dialog
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
// onTableAction(event: { name: string; row: T | null }): void {
|
|
585
|
-
// switch (event.name) {
|
|
586
|
-
// case 'add': this.openDrawer(null,event.name); break;
|
|
587
|
-
// case 'view': this.openDrawer(event.row!,event.name); break;
|
|
588
|
-
// case 'edit': this.openDrawer(event.row!,event.name); break;
|
|
589
|
-
// case 'delete': this.onDelete(event.row!);break;
|
|
590
|
-
// case 'state': this.openDeactivationReason(event.row!);break;
|
|
591
|
-
// }
|
|
592
|
-
// }
|
|
593
|
-
onTableAction(event) {
|
|
594
|
-
switch (event.name) {
|
|
595
|
-
case 'add':
|
|
596
|
-
case 'edit':
|
|
597
|
-
case 'view':
|
|
598
|
-
this.openEditor(event.row, event.name);
|
|
599
|
-
break;
|
|
600
|
-
case 'delete':
|
|
601
|
-
this.onDelete(event.row);
|
|
602
|
-
break;
|
|
603
|
-
case 'state':
|
|
604
|
-
this.openDeactivationReason(event.row);
|
|
605
|
-
break;
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
openDrawer(item, mode) {
|
|
609
|
-
this.mode = mode;
|
|
610
|
-
// this.drawerVisible = !this.drawerVisible;
|
|
611
|
-
if (item == null) {
|
|
612
|
-
this.selectedItem = this.defaultModel || {};
|
|
613
|
-
}
|
|
614
|
-
else {
|
|
615
|
-
this.selectedItem = item;
|
|
616
|
-
}
|
|
617
|
-
if (mode == 'edit') {
|
|
618
|
-
this.drawerVisible = true;
|
|
619
|
-
this.isEditMode = true;
|
|
620
|
-
this.isViewMode = false;
|
|
621
|
-
// this.isEditMode = item !=null ;
|
|
622
|
-
}
|
|
623
|
-
if (mode == 'add') {
|
|
624
|
-
this.drawerVisible = true;
|
|
625
|
-
this.isViewMode = false;
|
|
626
|
-
this.isEditMode = false;
|
|
627
|
-
}
|
|
628
|
-
if (mode == 'view') {
|
|
629
|
-
// this.drawerVisible = true;
|
|
630
|
-
this.dialogVisible = true;
|
|
631
|
-
this.isViewMode = true;
|
|
632
|
-
this.isEditMode = false;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
openDialog(item) {
|
|
636
|
-
this.dialogRef = this.dialogService.open((GenericCrudDialog), {
|
|
637
|
-
header: item ? 'تعديل' : 'اضافه',
|
|
638
|
-
styleClass: 'w-1/2',
|
|
639
|
-
modal: true,
|
|
640
|
-
data: {
|
|
641
|
-
item,
|
|
642
|
-
fields: this.formFields,
|
|
643
|
-
service: this.service,
|
|
644
|
-
idField: this.idField
|
|
645
|
-
}
|
|
646
|
-
});
|
|
647
|
-
//
|
|
648
|
-
this.dialogRef.onClose.subscribe((reload) => {
|
|
649
|
-
if (reload)
|
|
650
|
-
this.loadPage(0, this.rows);
|
|
651
|
-
});
|
|
652
|
-
}
|
|
653
|
-
openDeactivationReason(model) {
|
|
654
|
-
this.selectedItem = model;
|
|
655
|
-
if (this.selectedItem.isActive == true) {
|
|
656
|
-
const ref = this.dialogService.open(DeactivationReasonFormComponent, {
|
|
657
|
-
header: 'السبب (في حال تم إيقافه)',
|
|
658
|
-
width: '30vw',
|
|
659
|
-
data: { model: { ...model },
|
|
660
|
-
fields: this.formFields,
|
|
661
|
-
service: this.service,
|
|
662
|
-
idField: this.idField },
|
|
663
|
-
});
|
|
664
|
-
ref.onClose.subscribe((result) => {
|
|
665
|
-
if (result) {
|
|
666
|
-
this.selectedItem.isActive = false;
|
|
667
|
-
this.selectedItem.deactivationReason = result.deactivationReason;
|
|
668
|
-
// Optionally: save model via API
|
|
669
|
-
}
|
|
670
|
-
});
|
|
671
|
-
}
|
|
672
|
-
else {
|
|
673
|
-
this.selectedItem.isActive = true;
|
|
674
|
-
this.selectedItem.deactivationReason = "";
|
|
675
|
-
const id = this.selectedItem[this.idField];
|
|
676
|
-
this.service.update(id, this.selectedItem).subscribe({
|
|
677
|
-
next: () => {
|
|
678
|
-
},
|
|
679
|
-
error: (err) => {
|
|
680
|
-
this.loading = false;
|
|
681
|
-
}
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
// onDelete(item: any): void {
|
|
686
|
-
// if (!confirm('هل تريد الحذف فعلاً؟')) return;
|
|
687
|
-
// const id = (item as any)[this.idField];
|
|
688
|
-
// this.service.delete(id).subscribe(() => {
|
|
689
|
-
// this.loadPage(0, this.rows);
|
|
690
|
-
// });
|
|
691
|
-
// }
|
|
692
|
-
onDelete(item) {
|
|
693
|
-
const id = item[this.idField];
|
|
694
|
-
this.swalService.confirm('تأكيد الحذف', 'هل تريد حذف هذا السجل فعلاً؟', 'نعم، احذف', 'إلغاء').then((result) => {
|
|
695
|
-
if (result.isConfirmed) {
|
|
696
|
-
this.service.delete(id).subscribe({
|
|
697
|
-
next: () => {
|
|
698
|
-
this.loadPage(0, this.rows);
|
|
699
|
-
this.swalService.success('تم الحذف بنجاح');
|
|
700
|
-
},
|
|
701
|
-
error: (err) => {
|
|
702
|
-
this.loading = false;
|
|
703
|
-
const msg = err.error?.title ||
|
|
704
|
-
err.message ||
|
|
705
|
-
'حدث خطأ أثناء الحفظ. يرجى المحاولة مرة أخرى.';
|
|
706
|
-
// this.errorMessage = msg;
|
|
707
|
-
// ❌ رسالة خطأ
|
|
708
|
-
this.swalService.error('فشل الحذف', msg);
|
|
709
|
-
}
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
});
|
|
713
|
-
}
|
|
714
|
-
get columns() {
|
|
715
|
-
const flattenFields = (fields) => {
|
|
716
|
-
return fields.flatMap(field => {
|
|
717
|
-
// Check for nested group/panel
|
|
718
|
-
if (field.fieldGroup?.length) {
|
|
719
|
-
return flattenFields(field.fieldGroup);
|
|
720
|
-
}
|
|
721
|
-
// Skip fields with no props or table.hidden === true
|
|
722
|
-
if (!field.props || field.props['table']?.hidden === true) {
|
|
723
|
-
return [];
|
|
724
|
-
}
|
|
725
|
-
// Determine the column type: table.type > field.type > 'label-type'
|
|
726
|
-
// const tableType = field.props['table']?.type || field.type || 'label-type';
|
|
727
|
-
const tableType = field.props['table']?.type || 'label-type';
|
|
728
|
-
//
|
|
729
|
-
return [{
|
|
730
|
-
type: tableType,
|
|
731
|
-
key: field['key'], // always set key for table rendering
|
|
732
|
-
props: {
|
|
733
|
-
...field.props, // base props
|
|
734
|
-
...field.props['table']?.props // table-specific overrides
|
|
735
|
-
},
|
|
736
|
-
expressions: field.props['table']?.expressions
|
|
737
|
-
}];
|
|
738
|
-
});
|
|
739
|
-
};
|
|
740
|
-
return flattenFields(this.formFields);
|
|
741
|
-
}
|
|
742
|
-
get filters() {
|
|
743
|
-
const flattenForFilter = (fields) => {
|
|
744
|
-
return fields.flatMap(field => {
|
|
745
|
-
if (field.fieldGroup?.length) {
|
|
746
|
-
// Recursively handle nested panels/groups
|
|
747
|
-
return flattenForFilter(field.fieldGroup);
|
|
748
|
-
}
|
|
749
|
-
// Skip fields with no props or filter.hidden === true
|
|
750
|
-
if (!field.props || field.props['filter']?.hidden === true) {
|
|
751
|
-
return [];
|
|
752
|
-
}
|
|
753
|
-
return [field];
|
|
754
|
-
});
|
|
755
|
-
};
|
|
756
|
-
return flattenForFilter(this.formFields);
|
|
757
|
-
}
|
|
758
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: BaseCrud, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
759
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.4", type: BaseCrud, isStandalone: true, ngImport: i0 });
|
|
760
|
-
}
|
|
761
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: BaseCrud, decorators: [{
|
|
762
|
-
type: Directive
|
|
763
|
-
}] });
|
|
764
|
-
|
|
765
|
-
class InputWithIconType extends FieldType {
|
|
766
|
-
get type() {
|
|
767
|
-
return this.to.type || 'text';
|
|
768
|
-
}
|
|
769
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: InputWithIconType, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
770
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: InputWithIconType, isStandalone: true, selector: "formly-field-input-with-icon", usesInheritance: true, ngImport: i0, template: `
|
|
771
|
-
<div class="relative">
|
|
772
|
-
<!-- [formControl]="formControl" -->
|
|
773
|
-
<input
|
|
774
|
-
[type]="type"
|
|
775
|
-
|
|
776
|
-
[formlyAttributes]="field"
|
|
777
|
-
class="w-full rounded-xl border border-gray-200 bg-gray-50 pl-12 pr-4 py-3 text-sm focus:border-primary focus:ring-2 focus:ring-blue-100 transition-all"
|
|
778
|
-
[placeholder]="to.placeholder"
|
|
779
|
-
[disabled]="to.disabled ? true : false"
|
|
780
|
-
/>
|
|
781
|
-
<i class="{{ to['icon'] }} absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 text-base"></i>
|
|
782
|
-
</div>
|
|
783
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: FormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
|
|
784
|
-
}
|
|
785
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: InputWithIconType, decorators: [{
|
|
786
|
-
type: Component,
|
|
787
|
-
args: [{
|
|
788
|
-
selector: 'formly-field-input-with-icon',
|
|
789
|
-
imports: [FormlyAttributes, ReactiveFormsModule, CommonModule, FormsModule],
|
|
790
|
-
template: `
|
|
791
|
-
<div class="relative">
|
|
792
|
-
<!-- [formControl]="formControl" -->
|
|
793
|
-
<input
|
|
794
|
-
[type]="type"
|
|
795
|
-
|
|
796
|
-
[formlyAttributes]="field"
|
|
797
|
-
class="w-full rounded-xl border border-gray-200 bg-gray-50 pl-12 pr-4 py-3 text-sm focus:border-primary focus:ring-2 focus:ring-blue-100 transition-all"
|
|
798
|
-
[placeholder]="to.placeholder"
|
|
799
|
-
[disabled]="to.disabled ? true : false"
|
|
800
|
-
/>
|
|
801
|
-
<i class="{{ to['icon'] }} absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 text-base"></i>
|
|
802
|
-
</div>
|
|
803
|
-
`,
|
|
804
|
-
}]
|
|
10
|
+
args: [{ selector: 'lib-ng-core', imports: [], template: "<p>NgCore works!</p>\n" }]
|
|
805
11
|
}] });
|
|
806
12
|
|
|
807
|
-
const DEFAULT_CONTROL_CLASS = [
|
|
808
|
-
'w-full',
|
|
809
|
-
'border',
|
|
810
|
-
'border-gray-300',
|
|
811
|
-
'rounded',
|
|
812
|
-
'focus:outline-none',
|
|
813
|
-
'focus:ring-2',
|
|
814
|
-
'focus:ring-green-400',
|
|
815
|
-
].join(' ');
|
|
816
|
-
function numberField(key, label, required = false, className = 'col-span-1') {
|
|
817
|
-
return {
|
|
818
|
-
key,
|
|
819
|
-
type: 'input',
|
|
820
|
-
className,
|
|
821
|
-
wrappers: ['form-field'],
|
|
822
|
-
templateOptions: {
|
|
823
|
-
type: "number",
|
|
824
|
-
label,
|
|
825
|
-
required,
|
|
826
|
-
attributes: { class: DEFAULT_CONTROL_CLASS },
|
|
827
|
-
},
|
|
828
|
-
};
|
|
829
|
-
}
|
|
830
|
-
function textField(key, label, required = false, className = 'col-span-1',
|
|
831
|
-
// ✅ تم تغيير هذا البراميتر ليقبل خصائص إضافية لـ templateOptions
|
|
832
|
-
extraTemplateOptions) {
|
|
833
|
-
return {
|
|
834
|
-
key,
|
|
835
|
-
type: 'advanced-input',
|
|
836
|
-
className,
|
|
837
|
-
wrappers: ['form-field'],
|
|
838
|
-
props: {
|
|
839
|
-
label,
|
|
840
|
-
required,
|
|
841
|
-
attributes: {
|
|
842
|
-
class: DEFAULT_CONTROL_CLASS,
|
|
843
|
-
},
|
|
844
|
-
// ✅ دمج الخصائص الإضافية هنا
|
|
845
|
-
...extraTemplateOptions,
|
|
846
|
-
},
|
|
847
|
-
};
|
|
848
|
-
}
|
|
849
|
-
function textField2(key, label, required = false, className = 'col-span-1', expressions) {
|
|
850
|
-
return {
|
|
851
|
-
key,
|
|
852
|
-
type: 'input',
|
|
853
|
-
className,
|
|
854
|
-
wrappers: ['form-field'],
|
|
855
|
-
templateOptions: {
|
|
856
|
-
label,
|
|
857
|
-
required,
|
|
858
|
-
attributes: {
|
|
859
|
-
class: DEFAULT_CONTROL_CLASS,
|
|
860
|
-
},
|
|
861
|
-
// ✅ اضف disabled ليتضبب الحقل إذا كان readonly
|
|
862
|
-
},
|
|
863
|
-
expressions,
|
|
864
|
-
};
|
|
865
|
-
}
|
|
866
|
-
function textareaField(key, label, rows = 3, className = 'col-span-1') {
|
|
867
|
-
return {
|
|
868
|
-
key,
|
|
869
|
-
type: 'textarea',
|
|
870
|
-
className,
|
|
871
|
-
wrappers: ['form-field'],
|
|
872
|
-
templateOptions: {
|
|
873
|
-
label,
|
|
874
|
-
rows,
|
|
875
|
-
attributes: { class: DEFAULT_CONTROL_CLASS },
|
|
876
|
-
},
|
|
877
|
-
};
|
|
878
|
-
}
|
|
879
|
-
function selectField({ key, label, options = [], className, defaultValue, fullWidth = false, required = false, }) {
|
|
880
|
-
const config = {
|
|
881
|
-
key,
|
|
882
|
-
type: 'select',
|
|
883
|
-
className: className ?? (fullWidth ? 'col-span-2' : 'col-span-1'),
|
|
884
|
-
wrappers: ['form-field'],
|
|
885
|
-
templateOptions: {
|
|
886
|
-
label,
|
|
887
|
-
options,
|
|
888
|
-
required,
|
|
889
|
-
placeholder: `اختر ${label}`,
|
|
890
|
-
showClear: true,
|
|
891
|
-
filter: true,
|
|
892
|
-
appendTo: 'body',
|
|
893
|
-
optionLabel: 'label',
|
|
894
|
-
optionValue: 'value',
|
|
895
|
-
attributes: { class: DEFAULT_CONTROL_CLASS },
|
|
896
|
-
},
|
|
897
|
-
};
|
|
898
|
-
if (options !== undefined) {
|
|
899
|
-
config.templateOptions.options = options;
|
|
900
|
-
}
|
|
901
|
-
if (defaultValue !== undefined) {
|
|
902
|
-
config.defaultValue = defaultValue;
|
|
903
|
-
}
|
|
904
|
-
return config;
|
|
905
|
-
}
|
|
906
|
-
// export function checkboxField(
|
|
907
|
-
// key: string,
|
|
908
|
-
// label: string,
|
|
909
|
-
// required = false,
|
|
910
|
-
// className = 'col-span-1',
|
|
911
|
-
// useNumberMapping = false
|
|
912
|
-
// ): FormlyFieldConfig {
|
|
913
|
-
// const field: FormlyFieldConfig = {
|
|
914
|
-
// key,
|
|
915
|
-
// type: 'checkbox',
|
|
916
|
-
// className,
|
|
917
|
-
// wrappers: ['form-field'],
|
|
918
|
-
// templateOptions: {
|
|
919
|
-
// label,
|
|
920
|
-
// required,
|
|
921
|
-
// attributes: {
|
|
922
|
-
// class: 'flex items-center gap-2',
|
|
923
|
-
// },
|
|
924
|
-
// },
|
|
925
|
-
// };
|
|
926
|
-
// if (useNumberMapping) {
|
|
927
|
-
// field.hooks = {
|
|
928
|
-
// onInit: (field) => {
|
|
929
|
-
// // ✅ تهيئة القيمة داخل الفورم كنترول
|
|
930
|
-
// const initialValue = field.model?.[key];
|
|
931
|
-
// if (initialValue === 1 || initialValue === 2) {
|
|
932
|
-
// field.formControl?.setValue(initialValue === 1, { emitEvent: false });
|
|
933
|
-
// }
|
|
934
|
-
// // ✅ تحويل عند تغيّر القيمة من الـ checkbox
|
|
935
|
-
// field.formControl?.valueChanges.subscribe(val => {
|
|
936
|
-
// const newValue = val ? 1 : 2;
|
|
937
|
-
// if (field.model) {
|
|
938
|
-
// field.model[key] = newValue;
|
|
939
|
-
// }
|
|
940
|
-
// });
|
|
941
|
-
// }
|
|
942
|
-
// };
|
|
943
|
-
// }
|
|
944
|
-
// return field;
|
|
945
|
-
// }
|
|
946
|
-
function checkboxField(key, label, required = false, className = 'col-span-1') {
|
|
947
|
-
return {
|
|
948
|
-
key,
|
|
949
|
-
type: 'checkbox',
|
|
950
|
-
className,
|
|
951
|
-
wrappers: ['form-field'],
|
|
952
|
-
templateOptions: {
|
|
953
|
-
label,
|
|
954
|
-
required,
|
|
955
|
-
attributes: {
|
|
956
|
-
class: 'flex items-center gap-2',
|
|
957
|
-
},
|
|
958
|
-
},
|
|
959
|
-
hooks: {
|
|
960
|
-
onInit: (field) => {
|
|
961
|
-
const val = field.model?.[key];
|
|
962
|
-
if (val === 1) {
|
|
963
|
-
field.formControl?.setValue(true, { emitEvent: false });
|
|
964
|
-
}
|
|
965
|
-
else if (val === 2) {
|
|
966
|
-
field.formControl?.setValue(false, { emitEvent: false });
|
|
967
|
-
}
|
|
968
|
-
else if (val === undefined) {
|
|
969
|
-
field.model[key] = 2; // تعيين القيمة الافتراضية في الموديل
|
|
970
|
-
field.formControl?.setValue(false, { emitEvent: false });
|
|
971
|
-
}
|
|
972
|
-
else {
|
|
973
|
-
field.formControl?.setValue(false, { emitEvent: false });
|
|
974
|
-
}
|
|
975
|
-
field.formControl?.valueChanges.subscribe(val => {
|
|
976
|
-
const newVal = val ? 1 : 2;
|
|
977
|
-
if (field.model && field.model[key] !== newVal) {
|
|
978
|
-
field.model[key] = newVal;
|
|
979
|
-
}
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
|
|
986
13
|
/**
|
|
987
14
|
* Generated bundle index. Do not edit.
|
|
988
15
|
*/
|
|
989
16
|
|
|
990
|
-
export {
|
|
17
|
+
export { NgCore };
|
|
991
18
|
//# sourceMappingURL=elite.framework-ng.core.mjs.map
|