ng-ipa-library 0.7.5 → 0.7.6

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 (135) hide show
  1. package/karma.conf.js +44 -0
  2. package/ng-package.json +43 -0
  3. package/package.json +24 -31
  4. package/src/lib/core/components/loading/loading.component.html +3 -0
  5. package/src/lib/core/components/loading/loading.component.scss +3 -0
  6. package/src/lib/core/components/loading/loading.component.ts +23 -0
  7. package/src/lib/core/interceptors/error.interceptor.ts +61 -0
  8. package/src/lib/core/interceptors/loading.interceptor.ts +69 -0
  9. package/src/lib/core/interceptors/token.interceptor.ts +77 -0
  10. package/src/lib/core/services/auth.service.ts +48 -0
  11. package/src/lib/core/services/error.service.ts +19 -0
  12. package/src/lib/core/services/loader.service.ts +21 -0
  13. package/src/lib/generate-form/generate-form.component.html +85 -0
  14. package/src/lib/generate-form/generate-form.component.scss +0 -0
  15. package/src/lib/generate-form/generate-form.component.ts +119 -0
  16. package/src/lib/ipa-form/datepicker/datepicker.component.html +21 -0
  17. package/src/lib/ipa-form/datepicker/datepicker.component.scss +13 -0
  18. package/src/lib/ipa-form/datepicker/datepicker.component.ts +67 -0
  19. package/src/lib/ipa-form/datepicker/gregorian-datepicker/gregorian-datepicker.component.ts +15 -0
  20. package/src/lib/ipa-form/datepicker/gregorian-datepicker/gregorian18n.ts +38 -0
  21. package/src/lib/ipa-form/datepicker/hijri-datepicker/IslamicI18n.ts +38 -0
  22. package/src/lib/ipa-form/datepicker/hijri-datepicker/hijri-datepicker.component.ts +14 -0
  23. package/src/lib/ipa-form/dropdown-input/dropdown-input.component.html +22 -0
  24. package/src/lib/ipa-form/dropdown-input/dropdown-input.component.scss +0 -0
  25. package/src/lib/ipa-form/dropdown-input/dropdown-input.component.ts +68 -0
  26. package/src/lib/ipa-form/file-upload/file-upload.component.html +37 -0
  27. package/src/lib/ipa-form/file-upload/file-upload.component.scss +45 -0
  28. package/src/lib/ipa-form/file-upload/file-upload.component.ts +109 -0
  29. package/src/lib/ipa-form/ipa-form.service.ts +294 -0
  30. package/src/lib/ipa-form/recaptcha/recaptcha.component.html +3 -0
  31. package/src/lib/ipa-form/recaptcha/recaptcha.component.scss +0 -0
  32. package/src/lib/ipa-form/recaptcha/recaptcha.component.ts +42 -0
  33. package/src/lib/ipa-form/text-input/text-input.component.html +10 -0
  34. package/src/lib/ipa-form/text-input/text-input.component.scss +0 -0
  35. package/src/lib/ipa-form/text-input/text-input.component.ts +69 -0
  36. package/src/lib/ipa-form/textarea-input/textarea-input.component.html +11 -0
  37. package/src/lib/ipa-form/textarea-input/textarea-input.component.scss +0 -0
  38. package/src/lib/ipa-form/textarea-input/textarea-input.component.ts +69 -0
  39. package/{lib/models/apiException.d.ts → src/lib/models/apiException.ts} +2 -1
  40. package/src/lib/models/apiResponse.ts +4 -0
  41. package/src/lib/models/breadcrumbs.model.ts +4 -0
  42. package/src/lib/models/decodedToken.model.ts +6 -0
  43. package/src/lib/models/exceptionUrl.model.ts +4 -0
  44. package/src/lib/models/generateForm.model.ts +29 -0
  45. package/src/lib/models/pagedResult.ts +4 -0
  46. package/src/lib/models/user.model.ts +7 -0
  47. package/src/lib/ng-ipa-library.component.ts +15 -0
  48. package/src/lib/ng-ipa-library.module.ts +63 -0
  49. package/src/lib/pipes/hijri-date.pipe.ts +15 -0
  50. package/src/lib/pipes/pipes.module.ts +8 -0
  51. package/src/lib/services/breadcrumbs.service.ts +189 -0
  52. package/src/lib/services/common.service.ts +63 -0
  53. package/src/lib/share-button/share-button.component.html +3 -0
  54. package/src/lib/share-button/share-button.component.scss +0 -0
  55. package/src/lib/share-button/share-button.component.ts +23 -0
  56. package/src/lib/share-button/share-button.module.ts +32 -0
  57. package/{public-api.d.ts → src/public-api.ts} +16 -1
  58. package/src/test.ts +26 -0
  59. package/tsconfig.lib.json +20 -0
  60. package/tsconfig.lib.prod.json +10 -0
  61. package/tsconfig.spec.json +17 -0
  62. package/bundles/ng-ipa-library.umd.js +0 -2098
  63. package/bundles/ng-ipa-library.umd.js.map +0 -1
  64. package/esm2015/lib/core/components/loading/loading.component.js +0 -27
  65. package/esm2015/lib/core/interceptors/error.interceptor.js +0 -46
  66. package/esm2015/lib/core/interceptors/loading.interceptor.js +0 -58
  67. package/esm2015/lib/core/interceptors/token.interceptor.js +0 -69
  68. package/esm2015/lib/core/services/auth.service.js +0 -48
  69. package/esm2015/lib/core/services/error.service.js +0 -22
  70. package/esm2015/lib/core/services/loader.service.js +0 -24
  71. package/esm2015/lib/generate-form/generate-form.component.js +0 -120
  72. package/esm2015/lib/ipa-form/datepicker/datepicker.component.js +0 -70
  73. package/esm2015/lib/ipa-form/datepicker/gregorian-datepicker/gregorian-datepicker.component.js +0 -28
  74. package/esm2015/lib/ipa-form/datepicker/gregorian-datepicker/gregorian18n.js +0 -38
  75. package/esm2015/lib/ipa-form/datepicker/hijri-datepicker/IslamicI18n.js +0 -38
  76. package/esm2015/lib/ipa-form/datepicker/hijri-datepicker/hijri-datepicker.component.js +0 -28
  77. package/esm2015/lib/ipa-form/dropdown-input/dropdown-input.component.js +0 -81
  78. package/esm2015/lib/ipa-form/file-upload/file-upload.component.js +0 -128
  79. package/esm2015/lib/ipa-form/ipa-form.service.js +0 -251
  80. package/esm2015/lib/ipa-form/recaptcha/recaptcha.component.js +0 -59
  81. package/esm2015/lib/ipa-form/text-input/text-input.component.js +0 -76
  82. package/esm2015/lib/ipa-form/textarea-input/textarea-input.component.js +0 -73
  83. package/esm2015/lib/models/apiException.js +0 -2
  84. package/esm2015/lib/models/apiResponse.js +0 -2
  85. package/esm2015/lib/models/breadcrumbs.model.js +0 -2
  86. package/esm2015/lib/models/decodedToken.model.js +0 -2
  87. package/esm2015/lib/models/exceptionUrl.model.js +0 -2
  88. package/esm2015/lib/models/generateForm.model.js +0 -2
  89. package/esm2015/lib/models/pagedResult.js +0 -2
  90. package/esm2015/lib/models/user.model.js +0 -2
  91. package/esm2015/lib/ng-ipa-library.module.js +0 -109
  92. package/esm2015/lib/pipes/hijri-date.pipe.js +0 -18
  93. package/esm2015/lib/pipes/pipes.module.js +0 -16
  94. package/esm2015/lib/services/breadcrumbs.service.js +0 -151
  95. package/esm2015/lib/services/common.service.js +0 -66
  96. package/esm2015/lib/share-button/share-button.component.js +0 -37
  97. package/esm2015/lib/share-button/share-button.module.js +0 -52
  98. package/esm2015/ng-ipa-library.js +0 -5
  99. package/esm2015/public-api.js +0 -40
  100. package/fesm2015/ng-ipa-library.js +0 -1630
  101. package/fesm2015/ng-ipa-library.js.map +0 -1
  102. package/lib/core/components/loading/loading.component.d.ts +0 -12
  103. package/lib/core/interceptors/error.interceptor.d.ts +0 -14
  104. package/lib/core/interceptors/loading.interceptor.d.ts +0 -14
  105. package/lib/core/interceptors/token.interceptor.d.ts +0 -15
  106. package/lib/core/services/auth.service.d.ts +0 -15
  107. package/lib/core/services/error.service.d.ts +0 -10
  108. package/lib/core/services/loader.service.d.ts +0 -12
  109. package/lib/generate-form/generate-form.component.d.ts +0 -32
  110. package/lib/ipa-form/datepicker/datepicker.component.d.ts +0 -31
  111. package/lib/ipa-form/datepicker/gregorian-datepicker/gregorian-datepicker.component.d.ts +0 -6
  112. package/lib/ipa-form/datepicker/gregorian-datepicker/gregorian18n.d.ts +0 -11
  113. package/lib/ipa-form/datepicker/hijri-datepicker/IslamicI18n.d.ts +0 -11
  114. package/lib/ipa-form/datepicker/hijri-datepicker/hijri-datepicker.component.d.ts +0 -6
  115. package/lib/ipa-form/dropdown-input/dropdown-input.component.d.ts +0 -31
  116. package/lib/ipa-form/file-upload/file-upload.component.d.ts +0 -36
  117. package/lib/ipa-form/ipa-form.service.d.ts +0 -49
  118. package/lib/ipa-form/recaptcha/recaptcha.component.d.ts +0 -22
  119. package/lib/ipa-form/text-input/text-input.component.d.ts +0 -30
  120. package/lib/ipa-form/textarea-input/textarea-input.component.d.ts +0 -29
  121. package/lib/models/apiResponse.d.ts +0 -4
  122. package/lib/models/breadcrumbs.model.d.ts +0 -4
  123. package/lib/models/decodedToken.model.d.ts +0 -6
  124. package/lib/models/exceptionUrl.model.d.ts +0 -4
  125. package/lib/models/generateForm.model.d.ts +0 -27
  126. package/lib/models/pagedResult.d.ts +0 -4
  127. package/lib/models/user.model.d.ts +0 -7
  128. package/lib/ng-ipa-library.module.d.ts +0 -25
  129. package/lib/pipes/hijri-date.pipe.d.ts +0 -7
  130. package/lib/pipes/pipes.module.d.ts +0 -7
  131. package/lib/services/breadcrumbs.service.d.ts +0 -18
  132. package/lib/services/common.service.d.ts +0 -8
  133. package/lib/share-button/share-button.component.d.ts +0 -11
  134. package/lib/share-button/share-button.module.d.ts +0 -13
  135. package/ng-ipa-library.d.ts +0 -5
@@ -0,0 +1,119 @@
1
+ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
2
+ import {
3
+ FormArray,
4
+ FormControl,
5
+ FormGroup,
6
+ Validators,
7
+ } from '@angular/forms';
8
+ import { IPAFormService } from '../ipa-form/ipa-form.service';
9
+ import { Column, GenerateForm } from '../models/generateForm.model';
10
+
11
+ @Component({
12
+ selector: 'ipa-generate-form',
13
+ templateUrl: './generate-form.component.html',
14
+ styleUrls: ['./generate-form.component.scss'],
15
+ })
16
+ export class GenerateFormComponent implements OnInit {
17
+ @Input() generateForm!: FormGroup;
18
+ @Input() form!: GenerateForm;
19
+
20
+ // recaptcha inputs
21
+ @Input() siteKey!: string;
22
+ @Input() recaptchaSize: 'compact' | 'normal' = 'normal';
23
+ @Input() lang = 'ar';
24
+ @Input() recaptchaType: 'image' | 'audio' = 'image';
25
+ @Input() theme: 'light' | 'dark' = 'light';
26
+ @Input() useGlobalDomain = true;
27
+
28
+ // file upload outputs
29
+ @Output() successUpload = new EventEmitter();
30
+ @Output() fileAdded = new EventEmitter();
31
+ @Output() fileDeleted = new EventEmitter();
32
+
33
+ errorMsg!: string | null;
34
+
35
+ constructor(private validationService: IPAFormService) {}
36
+
37
+ ngOnInit(): void {
38
+ this.createForm();
39
+ }
40
+
41
+ get formControls() {
42
+ return this.generateForm.get('items') as FormArray;
43
+ }
44
+
45
+ getErrorMessage(formControlName: string): string | null {
46
+ const formControl = this.generateForm.controls[
47
+ formControlName
48
+ ] as FormControl;
49
+ this.errorMsg = this.validationService.getErrorMessage(formControl);
50
+ return this.errorMsg;
51
+ }
52
+
53
+ SuccessUpload(event: any) {
54
+ this.successUpload.emit(event);
55
+ }
56
+
57
+ FileAdded(file: any, formControlName: string) {
58
+ this.generateForm.controls[formControlName].patchValue(file);
59
+ this.fileAdded.emit(file);
60
+ }
61
+
62
+ FileDeleted(event: any, formControlName: string) {
63
+ this.generateForm.controls[formControlName].patchValue(null);
64
+ this.fileDeleted.emit(event);
65
+ }
66
+
67
+ private createForm() {
68
+ this.form.columns.forEach((column) => {
69
+ if (column.type === 'checkbox') {
70
+ this.addCheckboxControl(column);
71
+ } else {
72
+ this.generateForm.addControl(
73
+ column.englishName,
74
+ new FormControl(null, [
75
+ column.required ? Validators.required : Validators.nullValidator,
76
+ Validators.maxLength(column.size!),
77
+ column.type === 'number'
78
+ ? Validators.min(1)
79
+ : Validators.nullValidator,
80
+ ])
81
+ );
82
+ }
83
+ });
84
+ }
85
+
86
+ private addCheckboxControl(column: Column) {
87
+ let checkboxGroup = new FormArray(
88
+ column.data!.map((item) => {
89
+ return new FormGroup({
90
+ [column.valueField!]: new FormControl(item[column.valueField!]),
91
+ [column.textField!]: new FormControl(item[column.textField!]),
92
+ checkbox: new FormControl(false, Validators.required),
93
+ });
94
+ })
95
+ );
96
+
97
+ this.generateForm.addControl(
98
+ column.englishName,
99
+ new FormControl(
100
+ null,
101
+ column.required ? Validators.required : Validators.nullValidator
102
+ )
103
+ );
104
+ this.generateForm.addControl('items', checkboxGroup);
105
+ checkboxGroup.valueChanges.subscribe((value) => {
106
+ if (this.getCheckboxSelectedValues(value)) {
107
+ this.generateForm.controls[column.englishName].patchValue(value);
108
+ } else {
109
+ this.generateForm.controls[column.englishName].patchValue(null);
110
+ this.generateForm.controls[column.englishName].markAsTouched();
111
+ }
112
+ });
113
+ }
114
+
115
+ private getCheckboxSelectedValues(items: any[]) {
116
+ let selectedItems = items.filter((item) => item.checkbox);
117
+ return selectedItems.length > 0 ? selectedItems : null;
118
+ }
119
+ }
@@ -0,0 +1,21 @@
1
+ <div class="form-floating input-group {{containerClasses}}">
2
+ <input id="{{id}}"
3
+ [ngClass]="{'is-invalid is-invalid:focus': (controlDir.control?.invalid && (controlDir.control?.dirty || controlDir.control?.touched)) && errorMsg,'is-valid is-valid:focus': (controlDir.control?.valid && (controlDir.control?.dirty || controlDir.control?.touched) && (errorMsg || controlDir.value))}"
4
+ class="form-control {{classes}}" [formControl]="formControl" [firstDayOfWeek]="7" ngbDatepicker
5
+ #d="ngbDatepicker" [maxDate]="maxDate" [minDate]="minDate" [footerTemplate]="footerTemplate"
6
+ [required]="required" style="outline: unset; z-index: unset !important;" autocomplete="off" (blur)="onTouched()" title="{{label}}">
7
+ <label for="{{id}}">{{label}}</label>
8
+ <span class="input-group-text calenderBtn" (click)="d.toggle()">
9
+ <i class="far fa-calendar-alt fa-lg"></i>
10
+ </span>
11
+ <div class="invalid-feedback" *ngIf="errorMessage !== null">
12
+ {{errorMsg}}
13
+ </div>
14
+ <ng-template #footerTemplate style="text-align: center;">
15
+ <hr>
16
+ <button type="button" class="btn btn-primary btn-sm m-2 " style="width: auto; float: right;"
17
+ (click)="formControl.patchValue(today);d.navigateTo(today);">اليوم</button>
18
+ <button type="button" class="btn btn-secondary btn-sm m-2" style="width: auto; float: left;"
19
+ (click)="formControl.patchValue(null);d.close()">مسح</button>
20
+ </ng-template>
21
+ </div>
@@ -0,0 +1,13 @@
1
+ .calenderBtn {
2
+ cursor: pointer;
3
+ background-color: transparent;
4
+ color: #6c757d;
5
+ border-top-left-radius: .25rem !important;
6
+ border-bottom-left-radius: .25rem !important;
7
+ }
8
+
9
+ .calenderBtn:hover {
10
+ color: #fff;
11
+ background-color: #6c757d;
12
+ transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
13
+ }
@@ -0,0 +1,67 @@
1
+ import { Component, Input, OnInit, Self } from '@angular/core';
2
+ import { FormControl, NgControl } from '@angular/forms';
3
+ import {
4
+ NgbCalendar,
5
+ NgbDateStruct,
6
+ NgbInputDatepickerConfig,
7
+ } from '@ng-bootstrap/ng-bootstrap';
8
+ import { IPAFormService } from '../ipa-form.service';
9
+
10
+ @Component({
11
+ selector: 'ipa-datepicker',
12
+ templateUrl: './datepicker.component.html',
13
+ styleUrls: ['./datepicker.component.scss'],
14
+ })
15
+ export class DatepickerComponent implements OnInit {
16
+ @Input() id!: string;
17
+ @Input() label = 'datepicker';
18
+ @Input() patternErrorMsg = 'invalid pattern';
19
+ @Input() required = false;
20
+ @Input() maxDate!: NgbDateStruct;
21
+ @Input() minDate!: NgbDateStruct;
22
+ @Input() classes!: string;
23
+ @Input() containerClasses!: string;
24
+ today = this.calendar.getToday();
25
+ formControl: FormControl = new FormControl('');
26
+ errorMsg!: string | null;
27
+
28
+ constructor(
29
+ private ipaFormService: IPAFormService,
30
+ private calendar: NgbCalendar,
31
+ @Self() public controlDir: NgControl,
32
+ config: NgbInputDatepickerConfig
33
+ ) {
34
+ this.controlDir.valueAccessor = this;
35
+ config.container = 'body';
36
+ }
37
+
38
+ ngOnInit(): void {
39
+ const control = this.controlDir.control;
40
+ const validators = control?.validator ? [control.validator] : [];
41
+
42
+ control?.setValidators(validators);
43
+ control?.updateValueAndValidity();
44
+ this.formControl = control as FormControl;
45
+ }
46
+
47
+ onChange(event: any): void {}
48
+
49
+ onTouched(): void {}
50
+ writeValue(obj: any): void {}
51
+
52
+ registerOnChange(fn: any): void {
53
+ this.onChange = fn;
54
+ }
55
+
56
+ registerOnTouched(fn: any): void {
57
+ this.onTouched = fn;
58
+ }
59
+
60
+ get errorMessage(): string | null {
61
+ this.errorMsg = this.ipaFormService.getErrorMessage(
62
+ this.formControl,
63
+ this.patternErrorMsg
64
+ );
65
+ return this.errorMsg;
66
+ }
67
+ }
@@ -0,0 +1,15 @@
1
+ import { Component } from '@angular/core';
2
+ import { NgbCalendar, NgbCalendarGregorian, NgbDatepickerI18n } from '@ng-bootstrap/ng-bootstrap';
3
+ import { DatepickerComponent } from '../datepicker.component';
4
+ import { Gregorian18n } from './gregorian18n';
5
+
6
+ @Component({
7
+ selector: 'ipa-gregorian-datepicker',
8
+ templateUrl: '../datepicker.component.html',
9
+ styleUrls: ['../datepicker.component.scss'],
10
+ providers: [
11
+ { provide: NgbCalendar, useClass: NgbCalendarGregorian},
12
+ { provide: NgbDatepickerI18n, useClass: Gregorian18n },
13
+ ],
14
+ })
15
+ export class GregorianDatepickerComponent extends DatepickerComponent {}
@@ -0,0 +1,38 @@
1
+ import { TranslationWidth } from '@angular/common';
2
+ import { Injectable } from '@angular/core';
3
+ import { NgbDatepickerI18n, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap';
4
+
5
+ const WEEKDAYS = ['ن', 'ث', 'ر', 'خ', 'ج', 'س', 'ح'];
6
+ const MONTHS = [
7
+ 'يناير',
8
+ 'فبراير',
9
+ 'مارس',
10
+ 'أبريل',
11
+ 'مايو',
12
+ 'يونيو',
13
+ 'يوليو',
14
+ 'اغسطس',
15
+ 'سبتمبر',
16
+ 'أكتوبر',
17
+ 'نوفمبر',
18
+ 'ديسمبر',
19
+ ];
20
+
21
+ @Injectable()
22
+ export class Gregorian18n extends NgbDatepickerI18n {
23
+ getMonthShortName(month: number) {
24
+ return MONTHS[month - 1];
25
+ }
26
+
27
+ getMonthFullName(month: number) {
28
+ return MONTHS[month - 1];
29
+ }
30
+
31
+ getWeekdayLabel(weekday: number, width?: TranslationWidth) {
32
+ return WEEKDAYS[weekday - 1];
33
+ }
34
+
35
+ getDayAriaLabel(date: NgbDateStruct): string {
36
+ return `${date.day}-${date.month}-${date.year}`;
37
+ }
38
+ }
@@ -0,0 +1,38 @@
1
+ import { TranslationWidth } from '@angular/common';
2
+ import { Injectable } from '@angular/core';
3
+ import { NgbDatepickerI18n, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap';
4
+
5
+ const WEEKDAYS = ['ن', 'ث', 'ر', 'خ', 'ج', 'س', 'ح'];
6
+ const MONTHS = [
7
+ 'محرم',
8
+ 'صفر',
9
+ 'ربيع الأول',
10
+ 'ربيع الآخر',
11
+ 'جمادى الأولى',
12
+ 'جمادى الآخرة',
13
+ 'رجب',
14
+ 'شعبان',
15
+ 'رمضان',
16
+ 'شوال',
17
+ 'ذو القعدة',
18
+ 'ذو الحجة',
19
+ ];
20
+
21
+ @Injectable()
22
+ export class IslamicI18n extends NgbDatepickerI18n {
23
+ getMonthShortName(month: number) {
24
+ return MONTHS[month - 1];
25
+ }
26
+
27
+ getMonthFullName(month: number) {
28
+ return MONTHS[month - 1];
29
+ }
30
+
31
+ getWeekdayLabel(weekday: number, width?: TranslationWidth) {
32
+ return WEEKDAYS[weekday - 1];
33
+ }
34
+
35
+ getDayAriaLabel(date: NgbDateStruct): string {
36
+ return `${date.day}-${date.month}-${date.year}`;
37
+ }
38
+ }
@@ -0,0 +1,14 @@
1
+ import { Component } from '@angular/core';
2
+ import { NgbCalendar, NgbCalendarIslamicUmalqura, NgbDatepickerI18n } from '@ng-bootstrap/ng-bootstrap';
3
+ import { DatepickerComponent } from '../datepicker.component';
4
+ import { IslamicI18n } from './IslamicI18n';
5
+ @Component({
6
+ selector: 'ipa-hijri-datepicker',
7
+ templateUrl: '../datepicker.component.html',
8
+ styleUrls: ['../datepicker.component.scss'],
9
+ providers: [
10
+ { provide: NgbCalendar, useClass: NgbCalendarIslamicUmalqura },
11
+ { provide: NgbDatepickerI18n, useClass: IslamicI18n },
12
+ ],
13
+ })
14
+ export class HijriDatepickerComponent extends DatepickerComponent {}
@@ -0,0 +1,22 @@
1
+ <div class="form-floating {{containerClasses}}"
2
+ [ngClass]="{'was-validated': (controlDir.control?.dirty || controlDir.control?.touched) && required}">
3
+
4
+ <!-- searchable is false -->
5
+ <ng-container *ngIf="!searchable">
6
+ <select #select id="{{id}}" class="form-select {{classes}}" [required]="required" [formControl]="formControl">
7
+ <option *ngFor="let item of items" [value]="valueField ? item[valueField] : item">
8
+ {{textField ? item[textField] : item}}</option>
9
+ </select>
10
+ <label for="{{id}}">{{label}}</label>
11
+ </ng-container>
12
+
13
+ <!-- searchable is true -->
14
+ <ng-select *ngIf="searchable" #select dir="rtl" class="{{classes}}" [formControl]="formControl" [items]="items"
15
+ [placeholder]="label" [notFoundText]="notFoundText" [required]="required" [bindValue]="valueField"
16
+ [bindLabel]="textField"
17
+ [ngClass]="{'is-invalid is-invalid:focus': (controlDir.control?.invalid && (controlDir.control?.dirty || controlDir.control?.touched)) && errorMsg,'is-valid is-valid:focus': (controlDir.control?.valid && (controlDir.control?.dirty || controlDir.control?.touched) && (errorMsg || controlDir.value))}">
18
+ </ng-select>
19
+ <div class="invalid-feedback" *ngIf="errorMessage !== null">
20
+ {{errorMsg}}
21
+ </div>
22
+ </div>
@@ -0,0 +1,68 @@
1
+ import {
2
+ Component,
3
+ ElementRef,
4
+ Input,
5
+ OnInit,
6
+ Self,
7
+ ViewChild,
8
+ } from '@angular/core';
9
+ import { FormControl, NgControl } from '@angular/forms';
10
+ import { IPAFormService } from '../ipa-form.service';
11
+
12
+ @Component({
13
+ selector: 'ipa-dropdown-input',
14
+ templateUrl: './dropdown-input.component.html',
15
+ styleUrls: ['./dropdown-input.component.scss'],
16
+ })
17
+ export class DropdownInputComponent implements OnInit {
18
+ @ViewChild('select', { static: true }) input!: HTMLSelectElement;
19
+ @Input() id!: string;
20
+ @Input() label: string = 'text input';
21
+ @Input() items: any[] = [];
22
+ @Input() textField!: string;
23
+ @Input() valueField!: string;
24
+ @Input() required = false;
25
+ @Input() searchable = false;
26
+ @Input() notFoundText = 'لا يوجد بيانات';
27
+ @Input() classes!: string;
28
+ @Input() containerClasses!: string;
29
+ formControl: FormControl = new FormControl('');
30
+ errorMsg!: string | null;
31
+
32
+ constructor(
33
+ private validationService: IPAFormService,
34
+ @Self() public controlDir: NgControl
35
+ ) {
36
+ this.controlDir.valueAccessor = this;
37
+ }
38
+
39
+ ngOnInit(): void {
40
+ const control = this.controlDir.control;
41
+ const validators = control?.validator ? [control.validator] : [];
42
+
43
+ control?.setValidators(validators);
44
+ control?.updateValueAndValidity();
45
+ this.formControl = control as FormControl;
46
+ this.formControl.patchValue(null);
47
+ }
48
+
49
+ onChange(event: any): void {}
50
+
51
+ onTouched(): void {}
52
+ writeValue(obj: any): void {
53
+ if (this.input) this.input.value = obj || '';
54
+ }
55
+
56
+ registerOnChange(fn: any): void {
57
+ this.onChange = fn;
58
+ }
59
+
60
+ registerOnTouched(fn: any): void {
61
+ this.onTouched = fn;
62
+ }
63
+
64
+ get errorMessage(): string | null {
65
+ this.errorMsg = this.validationService.getErrorMessage(this.formControl);
66
+ return this.errorMsg;
67
+ }
68
+ }
@@ -0,0 +1,37 @@
1
+ <div class="file-upload">
2
+ <div class="upload-overlay" [dropzone]="config" (error)="onUploadError($event)"
3
+ (queueComplete)="operationCompleted($event)" (success)="onUploadSuccess($event)" (dragenter)="dragEnter = true"
4
+ (dragLeave)="dragEnter = false" (drop)="dragEnter = false" (dragEnd)="dragEnter = false"
5
+ [class.active-border]="dragEnter" (sending)="sending($event)" (reset)="reset($event)"
6
+ (addedFile)="fileWasAdded($event)">
7
+ </div>
8
+ <div class="upload-btn-wrapper">
9
+ <div>
10
+ <div class="subtitle mb-2">
11
+ {{label}}
12
+ <span *ngIf="required" class="required">*</span>
13
+ </div>
14
+ <hr>
15
+ <span style="font-size: 12px;">قم بسحب الملف أو اضغط هنا</span>
16
+ <i class="fas fa-upload upload-icon mr-2"></i>
17
+ </div>
18
+ <div *ngIf="acceptedFiles.length > 0" class="allowed-extensions">
19
+ الصيغة المسموح بها:
20
+ <span class="extensions">{{ acceptedFiles }}</span>
21
+ </div>
22
+ <div class="allowed-extensions">
23
+ اقصى حجم للمرفق:
24
+ <span class="extensions">{{ maxFileSize }} MB</span>
25
+ </div>
26
+ </div>
27
+ </div>
28
+ <div id="attachment-status" style="text-align: center; margin-top:10px;">
29
+ <span style="font-size: 14px; margin: auto; font-weight:bold;" *ngFor="let file of currentFiles">
30
+ {{ file.name }} <i (click)="deleteFile(file)" class="fas fa-trash"
31
+ style="color:firebrick; cursor: pointer;"></i>
32
+ <br>
33
+ </span>
34
+ <ul class="list-unstyled">
35
+ <li class="text-danger" style="font-size: 12px;" *ngFor="let error of errors">{{error}}</li>
36
+ </ul>
37
+ </div>
@@ -0,0 +1,45 @@
1
+ .subtitle {
2
+ border-bottom: none;
3
+ display: block;
4
+ line-height: 2;
5
+ }
6
+
7
+ .file-upload {
8
+ border: dashed 1px #ccc;
9
+ display: block;
10
+ min-height: 150px;
11
+ border-radius: 15px;
12
+ width: 350px;
13
+ cursor: pointer;
14
+ position: relative;
15
+ margin: auto;
16
+ }
17
+
18
+ .upload-overlay {
19
+ position: absolute;
20
+ width: 100%;
21
+ height: 100%;
22
+ }
23
+
24
+ .upload-btn-wrapper {
25
+ text-align: center;
26
+ }
27
+
28
+ .upload-icon {
29
+ margin-right: 5px;
30
+ }
31
+
32
+ .list-unstyled {
33
+ margin: 10px !important;
34
+ padding: 14px !important;
35
+ list-style: none;
36
+ }
37
+
38
+ .allowed-extensions {
39
+ color: #4d7297;
40
+ }
41
+
42
+ .required {
43
+ color: #dc3545;
44
+ font-size: 20px;
45
+ }
@@ -0,0 +1,109 @@
1
+ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
2
+ import { ToastrService } from 'ngx-toastr';
3
+ import { DropzoneConfigInterface, DropzoneDirective } from 'ngx-dropzone-wrapper';
4
+
5
+ @Component({
6
+ selector: 'ipa-file-upload',
7
+ templateUrl: './file-upload.component.html',
8
+ styleUrls: ['./file-upload.component.scss']
9
+ })
10
+ export class FileUploadComponent implements OnInit {
11
+ @ViewChild(DropzoneDirective, { static: false })
12
+ dropzoneDir!: DropzoneDirective;
13
+ @Input() label = '';
14
+ @Input() required = false;
15
+ @Input() acceptedFiles = '';
16
+ @Input() multiple = 1; // set maxFiles (NOT uploadMultiple)in the config object,
17
+ @Input() maxFileSize = 2;
18
+ @Input() method = 'POST';
19
+ @Input() autoUpload = false;
20
+ @Input() apiUrl = 'apiUrl';
21
+ @Input() authorization!: string;
22
+ @Output() successUpload = new EventEmitter();
23
+ @Output() fileAdded = new EventEmitter();
24
+ @Output() fileDeleted = new EventEmitter();
25
+ dragEnter = false;
26
+ errors: string[] = [];
27
+ config!: DropzoneConfigInterface;
28
+ filesAdded: File[] = [];
29
+ currentFiles: File[] = [];
30
+
31
+ constructor(
32
+ // private authService: AuthService,
33
+ private toastrService: ToastrService
34
+ ) {}
35
+
36
+ ngOnInit(): void {
37
+ this.label = 'رفع ' + this.label;
38
+ this.config = {
39
+ url: this.apiUrl,
40
+ method: this.method,
41
+ headers: {
42
+ Authorization: 'Bearer ' + this.authorization,
43
+ },
44
+ maxFilesize: this.maxFileSize,
45
+ maxFiles: this.multiple,
46
+ uploadMultiple: this.multiple > 1,
47
+ dictInvalidFileType: 'صيغة الملف غير مسموح بها',
48
+ dictFileTooBig: 'الحجم تجاوز الحد المسموح',
49
+ dictMaxFilesExceeded:
50
+ 'الرجاء حذف الملفات الموجودة حاليا لتتمكن من رفع هذا الملف',
51
+ acceptedFiles: this.acceptedFiles,
52
+ autoProcessQueue: this.autoUpload,
53
+ previewTemplate: '<span></span>',
54
+ };
55
+ }
56
+
57
+ operationCompleted(e: any): void {
58
+ if (this.filesAdded.length > 0) {
59
+ this.successUpload.emit(this.filesAdded);
60
+ this.filesAdded = [];
61
+ }
62
+ this.dropzoneDir.reset();
63
+ }
64
+
65
+ onUploadSuccess(e: any): void {
66
+ const file = e[0];
67
+ if (file.status === 'success') {
68
+ this.filesAdded.push(file);
69
+ }
70
+
71
+ this.toastrService.success('تم تحميل المرفقات بنجاح');
72
+ }
73
+
74
+ onUploadError(e: any): void {
75
+ if (e[1]) {
76
+ this.errors = [];
77
+ this.errors.push(`${e[1]} (${e[0].name})`);
78
+ }
79
+ }
80
+
81
+ fileWasAdded(e: File): void {
82
+ const myDropzone = this.dropzoneDir.dropzone();
83
+ if (this.multiple === 1) {
84
+ this.currentFiles = [];
85
+ this.filesAdded = [];
86
+ this.errors = [];
87
+ const files = myDropzone.files;
88
+ if (files.length > 1) {
89
+ myDropzone.removeFile(files[0]);
90
+ }
91
+ }
92
+ this.currentFiles.push(e);
93
+ this.fileAdded.emit(e);
94
+ }
95
+
96
+ sending(e: any): void {
97
+ this.errors = [];
98
+ }
99
+
100
+ reset(e: any): void {}
101
+
102
+ deleteFile(file: any): void {
103
+ this.currentFiles = this.currentFiles.filter(
104
+ (x) => x.name !== file.name && x.size !== file.size
105
+ );
106
+ this.errors = [];
107
+ this.fileDeleted.emit();
108
+ }
109
+ }