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.
- package/karma.conf.js +44 -0
- package/ng-package.json +43 -0
- package/package.json +24 -31
- package/src/lib/core/components/loading/loading.component.html +3 -0
- package/src/lib/core/components/loading/loading.component.scss +3 -0
- package/src/lib/core/components/loading/loading.component.ts +23 -0
- package/src/lib/core/interceptors/error.interceptor.ts +61 -0
- package/src/lib/core/interceptors/loading.interceptor.ts +69 -0
- package/src/lib/core/interceptors/token.interceptor.ts +77 -0
- package/src/lib/core/services/auth.service.ts +48 -0
- package/src/lib/core/services/error.service.ts +19 -0
- package/src/lib/core/services/loader.service.ts +21 -0
- package/src/lib/generate-form/generate-form.component.html +85 -0
- package/src/lib/generate-form/generate-form.component.scss +0 -0
- package/src/lib/generate-form/generate-form.component.ts +119 -0
- package/src/lib/ipa-form/datepicker/datepicker.component.html +21 -0
- package/src/lib/ipa-form/datepicker/datepicker.component.scss +13 -0
- package/src/lib/ipa-form/datepicker/datepicker.component.ts +67 -0
- package/src/lib/ipa-form/datepicker/gregorian-datepicker/gregorian-datepicker.component.ts +15 -0
- package/src/lib/ipa-form/datepicker/gregorian-datepicker/gregorian18n.ts +38 -0
- package/src/lib/ipa-form/datepicker/hijri-datepicker/IslamicI18n.ts +38 -0
- package/src/lib/ipa-form/datepicker/hijri-datepicker/hijri-datepicker.component.ts +14 -0
- package/src/lib/ipa-form/dropdown-input/dropdown-input.component.html +22 -0
- package/src/lib/ipa-form/dropdown-input/dropdown-input.component.scss +0 -0
- package/src/lib/ipa-form/dropdown-input/dropdown-input.component.ts +68 -0
- package/src/lib/ipa-form/file-upload/file-upload.component.html +37 -0
- package/src/lib/ipa-form/file-upload/file-upload.component.scss +45 -0
- package/src/lib/ipa-form/file-upload/file-upload.component.ts +109 -0
- package/src/lib/ipa-form/ipa-form.service.ts +294 -0
- package/src/lib/ipa-form/recaptcha/recaptcha.component.html +3 -0
- package/src/lib/ipa-form/recaptcha/recaptcha.component.scss +0 -0
- package/src/lib/ipa-form/recaptcha/recaptcha.component.ts +42 -0
- package/src/lib/ipa-form/text-input/text-input.component.html +10 -0
- package/src/lib/ipa-form/text-input/text-input.component.scss +0 -0
- package/src/lib/ipa-form/text-input/text-input.component.ts +69 -0
- package/src/lib/ipa-form/textarea-input/textarea-input.component.html +11 -0
- package/src/lib/ipa-form/textarea-input/textarea-input.component.scss +0 -0
- package/src/lib/ipa-form/textarea-input/textarea-input.component.ts +69 -0
- package/{lib/models/apiException.d.ts → src/lib/models/apiException.ts} +2 -1
- package/src/lib/models/apiResponse.ts +4 -0
- package/src/lib/models/breadcrumbs.model.ts +4 -0
- package/src/lib/models/decodedToken.model.ts +6 -0
- package/src/lib/models/exceptionUrl.model.ts +4 -0
- package/src/lib/models/generateForm.model.ts +29 -0
- package/src/lib/models/pagedResult.ts +4 -0
- package/src/lib/models/user.model.ts +7 -0
- package/src/lib/ng-ipa-library.component.ts +15 -0
- package/src/lib/ng-ipa-library.module.ts +63 -0
- package/src/lib/pipes/hijri-date.pipe.ts +15 -0
- package/src/lib/pipes/pipes.module.ts +8 -0
- package/src/lib/services/breadcrumbs.service.ts +189 -0
- package/src/lib/services/common.service.ts +63 -0
- package/src/lib/share-button/share-button.component.html +3 -0
- package/src/lib/share-button/share-button.component.scss +0 -0
- package/src/lib/share-button/share-button.component.ts +23 -0
- package/src/lib/share-button/share-button.module.ts +32 -0
- package/{public-api.d.ts → src/public-api.ts} +16 -1
- package/src/test.ts +26 -0
- package/tsconfig.lib.json +20 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +17 -0
- package/bundles/ng-ipa-library.umd.js +0 -2098
- package/bundles/ng-ipa-library.umd.js.map +0 -1
- package/esm2015/lib/core/components/loading/loading.component.js +0 -27
- package/esm2015/lib/core/interceptors/error.interceptor.js +0 -46
- package/esm2015/lib/core/interceptors/loading.interceptor.js +0 -58
- package/esm2015/lib/core/interceptors/token.interceptor.js +0 -69
- package/esm2015/lib/core/services/auth.service.js +0 -48
- package/esm2015/lib/core/services/error.service.js +0 -22
- package/esm2015/lib/core/services/loader.service.js +0 -24
- package/esm2015/lib/generate-form/generate-form.component.js +0 -120
- package/esm2015/lib/ipa-form/datepicker/datepicker.component.js +0 -70
- package/esm2015/lib/ipa-form/datepicker/gregorian-datepicker/gregorian-datepicker.component.js +0 -28
- package/esm2015/lib/ipa-form/datepicker/gregorian-datepicker/gregorian18n.js +0 -38
- package/esm2015/lib/ipa-form/datepicker/hijri-datepicker/IslamicI18n.js +0 -38
- package/esm2015/lib/ipa-form/datepicker/hijri-datepicker/hijri-datepicker.component.js +0 -28
- package/esm2015/lib/ipa-form/dropdown-input/dropdown-input.component.js +0 -81
- package/esm2015/lib/ipa-form/file-upload/file-upload.component.js +0 -128
- package/esm2015/lib/ipa-form/ipa-form.service.js +0 -251
- package/esm2015/lib/ipa-form/recaptcha/recaptcha.component.js +0 -59
- package/esm2015/lib/ipa-form/text-input/text-input.component.js +0 -76
- package/esm2015/lib/ipa-form/textarea-input/textarea-input.component.js +0 -73
- package/esm2015/lib/models/apiException.js +0 -2
- package/esm2015/lib/models/apiResponse.js +0 -2
- package/esm2015/lib/models/breadcrumbs.model.js +0 -2
- package/esm2015/lib/models/decodedToken.model.js +0 -2
- package/esm2015/lib/models/exceptionUrl.model.js +0 -2
- package/esm2015/lib/models/generateForm.model.js +0 -2
- package/esm2015/lib/models/pagedResult.js +0 -2
- package/esm2015/lib/models/user.model.js +0 -2
- package/esm2015/lib/ng-ipa-library.module.js +0 -109
- package/esm2015/lib/pipes/hijri-date.pipe.js +0 -18
- package/esm2015/lib/pipes/pipes.module.js +0 -16
- package/esm2015/lib/services/breadcrumbs.service.js +0 -151
- package/esm2015/lib/services/common.service.js +0 -66
- package/esm2015/lib/share-button/share-button.component.js +0 -37
- package/esm2015/lib/share-button/share-button.module.js +0 -52
- package/esm2015/ng-ipa-library.js +0 -5
- package/esm2015/public-api.js +0 -40
- package/fesm2015/ng-ipa-library.js +0 -1630
- package/fesm2015/ng-ipa-library.js.map +0 -1
- package/lib/core/components/loading/loading.component.d.ts +0 -12
- package/lib/core/interceptors/error.interceptor.d.ts +0 -14
- package/lib/core/interceptors/loading.interceptor.d.ts +0 -14
- package/lib/core/interceptors/token.interceptor.d.ts +0 -15
- package/lib/core/services/auth.service.d.ts +0 -15
- package/lib/core/services/error.service.d.ts +0 -10
- package/lib/core/services/loader.service.d.ts +0 -12
- package/lib/generate-form/generate-form.component.d.ts +0 -32
- package/lib/ipa-form/datepicker/datepicker.component.d.ts +0 -31
- package/lib/ipa-form/datepicker/gregorian-datepicker/gregorian-datepicker.component.d.ts +0 -6
- package/lib/ipa-form/datepicker/gregorian-datepicker/gregorian18n.d.ts +0 -11
- package/lib/ipa-form/datepicker/hijri-datepicker/IslamicI18n.d.ts +0 -11
- package/lib/ipa-form/datepicker/hijri-datepicker/hijri-datepicker.component.d.ts +0 -6
- package/lib/ipa-form/dropdown-input/dropdown-input.component.d.ts +0 -31
- package/lib/ipa-form/file-upload/file-upload.component.d.ts +0 -36
- package/lib/ipa-form/ipa-form.service.d.ts +0 -49
- package/lib/ipa-form/recaptcha/recaptcha.component.d.ts +0 -22
- package/lib/ipa-form/text-input/text-input.component.d.ts +0 -30
- package/lib/ipa-form/textarea-input/textarea-input.component.d.ts +0 -29
- package/lib/models/apiResponse.d.ts +0 -4
- package/lib/models/breadcrumbs.model.d.ts +0 -4
- package/lib/models/decodedToken.model.d.ts +0 -6
- package/lib/models/exceptionUrl.model.d.ts +0 -4
- package/lib/models/generateForm.model.d.ts +0 -27
- package/lib/models/pagedResult.d.ts +0 -4
- package/lib/models/user.model.d.ts +0 -7
- package/lib/ng-ipa-library.module.d.ts +0 -25
- package/lib/pipes/hijri-date.pipe.d.ts +0 -7
- package/lib/pipes/pipes.module.d.ts +0 -7
- package/lib/services/breadcrumbs.service.d.ts +0 -18
- package/lib/services/common.service.d.ts +0 -8
- package/lib/share-button/share-button.component.d.ts +0 -11
- package/lib/share-button/share-button.module.d.ts +0 -13
- package/ng-ipa-library.d.ts +0 -5
package/karma.conf.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Karma configuration file, see link for more information
|
|
2
|
+
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
|
3
|
+
|
|
4
|
+
module.exports = function (config) {
|
|
5
|
+
config.set({
|
|
6
|
+
basePath: '',
|
|
7
|
+
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
|
8
|
+
plugins: [
|
|
9
|
+
require('karma-jasmine'),
|
|
10
|
+
require('karma-chrome-launcher'),
|
|
11
|
+
require('karma-jasmine-html-reporter'),
|
|
12
|
+
require('karma-coverage'),
|
|
13
|
+
require('@angular-devkit/build-angular/plugins/karma')
|
|
14
|
+
],
|
|
15
|
+
client: {
|
|
16
|
+
jasmine: {
|
|
17
|
+
// you can add configuration options for Jasmine here
|
|
18
|
+
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
|
19
|
+
// for example, you can disable the random execution with `random: false`
|
|
20
|
+
// or set a specific seed with `seed: 4321`
|
|
21
|
+
},
|
|
22
|
+
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
23
|
+
},
|
|
24
|
+
jasmineHtmlReporter: {
|
|
25
|
+
suppressAll: true // removes the duplicated traces
|
|
26
|
+
},
|
|
27
|
+
coverageReporter: {
|
|
28
|
+
dir: require('path').join(__dirname, '../../coverage/ng-ipa-library'),
|
|
29
|
+
subdir: '.',
|
|
30
|
+
reporters: [
|
|
31
|
+
{ type: 'html' },
|
|
32
|
+
{ type: 'text-summary' }
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
reporters: ['progress', 'kjhtml'],
|
|
36
|
+
port: 9876,
|
|
37
|
+
colors: true,
|
|
38
|
+
logLevel: config.LOG_INFO,
|
|
39
|
+
autoWatch: true,
|
|
40
|
+
browsers: ['Chrome'],
|
|
41
|
+
singleRun: false,
|
|
42
|
+
restartOnFileChange: true
|
|
43
|
+
});
|
|
44
|
+
};
|
package/ng-package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
|
3
|
+
"dest": "../../dist/ng-ipa-library",
|
|
4
|
+
"allowedNonPeerDependencies": [
|
|
5
|
+
"ngx-toastr",
|
|
6
|
+
"ngx-dropzone-wrapper",
|
|
7
|
+
"ngx-captcha",
|
|
8
|
+
"moment-hijri",
|
|
9
|
+
"@types/moment-hijri",
|
|
10
|
+
"@ng-bootstrap/ng-bootstrap",
|
|
11
|
+
"@ng-bootstrap/ng-bootstrap",
|
|
12
|
+
"@fortawesome/angular-fontawesome",
|
|
13
|
+
"@fortawesome/fontawesome-svg-core",
|
|
14
|
+
"@fortawesome/free-brands-svg-icons",
|
|
15
|
+
"@fortawesome/free-solid-svg-icons",
|
|
16
|
+
"ngx-sharebuttons",
|
|
17
|
+
"@angular/cdk",
|
|
18
|
+
"@ng-select/ng-select"
|
|
19
|
+
],
|
|
20
|
+
"lib": {
|
|
21
|
+
"entryFile": "src/public-api.ts",
|
|
22
|
+
"umdModuleIds": {
|
|
23
|
+
"ngx-toastr": "ngx-toastr",
|
|
24
|
+
"ngx-dropzone-wrapper": "ngx-dropzone-wrapper",
|
|
25
|
+
"ngx-captcha": "ngx-captcha",
|
|
26
|
+
"moment-hijri": "moment-hijri",
|
|
27
|
+
"@types/moment-hijri": "@types/moment-hijri",
|
|
28
|
+
"@ng-bootstrap/ng-bootstrap": "@ng-bootstrap/ng-bootstrap",
|
|
29
|
+
"@fortawesome/angular-fontawesome": "@fortawesome/angular-fontawesome",
|
|
30
|
+
"@fortawesome/fontawesome-svg-core": "@fortawesome/fontawesome-svg-core",
|
|
31
|
+
"@fortawesome/free-brands-svg-icons": "@fortawesome/free-brands-svg-icons",
|
|
32
|
+
"@fortawesome/free-solid-svg-icons": "@fortawesome/free-solid-svg-icons",
|
|
33
|
+
"ngx-sharebuttons": "ngx-sharebuttons",
|
|
34
|
+
"ngx-sharebuttons/icons": "ngx-sharebuttons/icons",
|
|
35
|
+
"ngx-sharebuttons/popup": "ngx-sharebuttons/popup",
|
|
36
|
+
"@angular/cdk": "@angular/cdk",
|
|
37
|
+
"@ng-select/ng-select": "@ng-select/ng-select"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"assets": [
|
|
41
|
+
"src/lib/assets/ngIPAStyle.scss"
|
|
42
|
+
]
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,31 +1,24 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "ng-ipa-library",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"peerDependencies": {
|
|
5
|
-
"@angular/common": "~12.2.9",
|
|
6
|
-
"@angular/core": "~12.2.9"
|
|
7
|
-
},
|
|
8
|
-
"dependencies": {
|
|
9
|
-
"tslib": "^2.2.0",
|
|
10
|
-
"ngx-toastr": "^14.1.0",
|
|
11
|
-
"@ng-select/ng-select": "^7.4.0",
|
|
12
|
-
"ngx-captcha": "^10.0.0",
|
|
13
|
-
"ngx-dropzone-wrapper": "^10.0.1",
|
|
14
|
-
"moment-hijri": "^2.1.2",
|
|
15
|
-
"@types/moment-hijri": "^2.1.0",
|
|
16
|
-
"@ng-bootstrap/ng-bootstrap": "^11.0.0-beta.2",
|
|
17
|
-
"@fortawesome/angular-fontawesome": "^0.9.0",
|
|
18
|
-
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
|
19
|
-
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
|
20
|
-
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
|
21
|
-
"ngx-sharebuttons": "^9.0.0",
|
|
22
|
-
"@angular/cdk": "^12.2.9"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
"module": "fesm2015/ng-ipa-library.js",
|
|
26
|
-
"es2015": "fesm2015/ng-ipa-library.js",
|
|
27
|
-
"esm2015": "esm2015/ng-ipa-library.js",
|
|
28
|
-
"fesm2015": "fesm2015/ng-ipa-library.js",
|
|
29
|
-
"typings": "ng-ipa-library.d.ts",
|
|
30
|
-
"sideEffects": false
|
|
31
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "ng-ipa-library",
|
|
3
|
+
"version": "0.7.6",
|
|
4
|
+
"peerDependencies": {
|
|
5
|
+
"@angular/common": "~12.2.9",
|
|
6
|
+
"@angular/core": "~12.2.9"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"tslib": "^2.2.0",
|
|
10
|
+
"ngx-toastr": "^14.1.0",
|
|
11
|
+
"@ng-select/ng-select": "^7.4.0",
|
|
12
|
+
"ngx-captcha": "^10.0.0",
|
|
13
|
+
"ngx-dropzone-wrapper": "^10.0.1",
|
|
14
|
+
"moment-hijri": "^2.1.2",
|
|
15
|
+
"@types/moment-hijri": "^2.1.0",
|
|
16
|
+
"@ng-bootstrap/ng-bootstrap": "^11.0.0-beta.2",
|
|
17
|
+
"@fortawesome/angular-fontawesome": "^0.9.0",
|
|
18
|
+
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
|
19
|
+
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
|
20
|
+
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
|
21
|
+
"ngx-sharebuttons": "^9.0.0",
|
|
22
|
+
"@angular/cdk": "^12.2.9"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AfterViewInit, ChangeDetectorRef, Component } from '@angular/core';
|
|
2
|
+
import { LoaderService } from '../../services/loader.service';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'ipa-loader',
|
|
6
|
+
templateUrl: './loading.component.html',
|
|
7
|
+
styleUrls: ['./loading.component.scss'],
|
|
8
|
+
})
|
|
9
|
+
export class LoaderComponent implements AfterViewInit {
|
|
10
|
+
loading!: boolean;
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
private loaderService: LoaderService,
|
|
14
|
+
private cdr: ChangeDetectorRef
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
ngAfterViewInit(): void {
|
|
18
|
+
this.loaderService.isLoading.subscribe((v) => {
|
|
19
|
+
this.loading = v;
|
|
20
|
+
this.cdr.detectChanges();
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
HttpRequest,
|
|
4
|
+
HttpHandler,
|
|
5
|
+
HttpEvent,
|
|
6
|
+
HttpInterceptor,
|
|
7
|
+
} from '@angular/common/http';
|
|
8
|
+
import { Observable, throwError } from 'rxjs';
|
|
9
|
+
import { catchError } from 'rxjs/operators';
|
|
10
|
+
import { ErrorService } from '../services/error.service';
|
|
11
|
+
import { ApiException } from '../../models/apiException';
|
|
12
|
+
import { IndividualConfig, ToastrService } from 'ngx-toastr';
|
|
13
|
+
|
|
14
|
+
@Injectable()
|
|
15
|
+
export class ErrorInterceptor implements HttpInterceptor {
|
|
16
|
+
constructor(
|
|
17
|
+
private errorService: ErrorService,
|
|
18
|
+
private toastrService: ToastrService
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
intercept(
|
|
22
|
+
req: HttpRequest<unknown>,
|
|
23
|
+
next: HttpHandler
|
|
24
|
+
): Observable<HttpEvent<unknown>> {
|
|
25
|
+
if (this.isException(req)) {
|
|
26
|
+
return next.handle(req);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return next.handle(req).pipe(
|
|
30
|
+
catchError((error) => {
|
|
31
|
+
const response = error.error as ApiException;
|
|
32
|
+
const toastrConfig: Partial<IndividualConfig> = {
|
|
33
|
+
disableTimeOut: true,
|
|
34
|
+
};
|
|
35
|
+
switch (response.statusCode) {
|
|
36
|
+
case 500:
|
|
37
|
+
this.toastrService.error(
|
|
38
|
+
response?.innerException + ' ' + response?.stackTrace,
|
|
39
|
+
response.message,
|
|
40
|
+
toastrConfig
|
|
41
|
+
);
|
|
42
|
+
break;
|
|
43
|
+
|
|
44
|
+
default:
|
|
45
|
+
this.toastrService.error(response.message, '', toastrConfig);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
return throwError(error);
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
isException(req: HttpRequest<any>): boolean {
|
|
54
|
+
for (const url of this.errorService.urls) {
|
|
55
|
+
if (req.url.includes(url.path) && req.method === url.method) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
HttpRequest,
|
|
4
|
+
HttpHandler,
|
|
5
|
+
HttpEvent,
|
|
6
|
+
HttpInterceptor,
|
|
7
|
+
HttpResponse,
|
|
8
|
+
} from '@angular/common/http';
|
|
9
|
+
import { Observable } from 'rxjs';
|
|
10
|
+
import { LoaderService } from '../services/loader.service';
|
|
11
|
+
|
|
12
|
+
@Injectable()
|
|
13
|
+
export class LoadingInterceptor implements HttpInterceptor {
|
|
14
|
+
private requests: HttpRequest<any>[] = [];
|
|
15
|
+
|
|
16
|
+
constructor(private loaderService: LoaderService) {}
|
|
17
|
+
|
|
18
|
+
removeRequest(req: HttpRequest<any>): void {
|
|
19
|
+
const i = this.requests.indexOf(req);
|
|
20
|
+
if (i >= 0) {
|
|
21
|
+
this.requests.splice(i, 1);
|
|
22
|
+
}
|
|
23
|
+
this.loaderService.isLoading.next(this.requests.length > 0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
intercept(
|
|
27
|
+
req: HttpRequest<unknown>,
|
|
28
|
+
next: HttpHandler
|
|
29
|
+
): Observable<HttpEvent<unknown>> {
|
|
30
|
+
if (this.isException(req)) {
|
|
31
|
+
return next.handle(req);
|
|
32
|
+
}
|
|
33
|
+
this.requests.push(req);
|
|
34
|
+
|
|
35
|
+
this.loaderService.isLoading.next(true);
|
|
36
|
+
return new Observable((observer) => {
|
|
37
|
+
const subscription = next.handle(req).subscribe(
|
|
38
|
+
(event) => {
|
|
39
|
+
if (event instanceof HttpResponse) {
|
|
40
|
+
this.removeRequest(req);
|
|
41
|
+
observer.next(event);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
(err) => {
|
|
45
|
+
this.removeRequest(req);
|
|
46
|
+
observer.error(err);
|
|
47
|
+
},
|
|
48
|
+
() => {
|
|
49
|
+
this.removeRequest(req);
|
|
50
|
+
observer.complete();
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
// remove request from queue when cancelled
|
|
54
|
+
return () => {
|
|
55
|
+
this.removeRequest(req);
|
|
56
|
+
subscription.unsubscribe();
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
isException(req: HttpRequest<any>): boolean {
|
|
62
|
+
for (const url of this.loaderService.urls) {
|
|
63
|
+
if (req.url.includes(url.path) && req.method === url.method) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
HttpRequest,
|
|
4
|
+
HttpHandler,
|
|
5
|
+
HttpEvent,
|
|
6
|
+
HttpInterceptor,
|
|
7
|
+
HttpClient,
|
|
8
|
+
} from '@angular/common/http';
|
|
9
|
+
import { Observable } from 'rxjs';
|
|
10
|
+
import { AuthService } from '../services/auth.service';
|
|
11
|
+
import { DecodedToken } from '../../models/decodedToken.model';
|
|
12
|
+
import { User } from '../../models/user.model';
|
|
13
|
+
|
|
14
|
+
@Injectable()
|
|
15
|
+
export class TokenInterceptor implements HttpInterceptor {
|
|
16
|
+
refresh = true;
|
|
17
|
+
constructor(private authService: AuthService, private http: HttpClient) {}
|
|
18
|
+
|
|
19
|
+
intercept(
|
|
20
|
+
request: HttpRequest<unknown>,
|
|
21
|
+
next: HttpHandler
|
|
22
|
+
): Observable<HttpEvent<unknown>> {
|
|
23
|
+
if (this.isException(request)) {
|
|
24
|
+
return next.handle(request);
|
|
25
|
+
}
|
|
26
|
+
const token = this.authService.getToken();
|
|
27
|
+
if (token) {
|
|
28
|
+
this.isTokenExpired(token);
|
|
29
|
+
request = request.clone({
|
|
30
|
+
setHeaders: {
|
|
31
|
+
Authorization: `Bearer ${token}`,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return next.handle(request);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private isTokenExpired(token: string) {
|
|
39
|
+
const redirectPath = location.pathname;
|
|
40
|
+
const decodedToken = this.authService.getDecodedToken() as DecodedToken;
|
|
41
|
+
const expDate = new Date((decodedToken.exp ?? 0) * 1000);
|
|
42
|
+
if (expDate < new Date()) {
|
|
43
|
+
location.replace('/ar/login?redirect=' + redirectPath);
|
|
44
|
+
return;
|
|
45
|
+
} else {
|
|
46
|
+
if (this.authService.currentUserUrl) {
|
|
47
|
+
if (this.refresh) {
|
|
48
|
+
this.http
|
|
49
|
+
.get<User>(this.authService.currentUserUrl + `/api/users?refresh`, {
|
|
50
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
51
|
+
})
|
|
52
|
+
.subscribe((user) => {
|
|
53
|
+
localStorage.setItem('token', user.token);
|
|
54
|
+
this.refresh = false;
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
this.refresh = true;
|
|
57
|
+
}, 60 * 1000);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
throw new Error(
|
|
62
|
+
"provide current base user api url using this function authService.setCurrentUserUrl('https://...')"
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private isException(request: HttpRequest<any>): boolean {
|
|
69
|
+
if (
|
|
70
|
+
request.url.includes('/api/users?refresh') &&
|
|
71
|
+
request.method === 'GET'
|
|
72
|
+
) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject } from 'rxjs';
|
|
3
|
+
import { DecodedToken } from '../../models/decodedToken.model';
|
|
4
|
+
|
|
5
|
+
@Injectable({
|
|
6
|
+
providedIn: 'root',
|
|
7
|
+
})
|
|
8
|
+
export class AuthService {
|
|
9
|
+
public currentUser = new BehaviorSubject<DecodedToken>({ exp: 0 });
|
|
10
|
+
currentUserUrl = '';
|
|
11
|
+
constructor() {}
|
|
12
|
+
|
|
13
|
+
getToken(): string {
|
|
14
|
+
return localStorage.getItem('token') ?? '';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getDecodedToken(): any {
|
|
18
|
+
return this.decodeJwt(this.getToken());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
setCurrentUser(): void {
|
|
22
|
+
const decodedToken = this.getDecodedToken() as DecodedToken;
|
|
23
|
+
this.currentUser.next({
|
|
24
|
+
nameid: decodedToken.nameid,
|
|
25
|
+
email: decodedToken.email,
|
|
26
|
+
given_name: decodedToken.given_name,
|
|
27
|
+
exp: decodedToken.exp,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
setCurrentUserUrl(url: string) {
|
|
32
|
+
this.currentUserUrl = url;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private decodeJwt(token: string): any {
|
|
36
|
+
const base64Url = token.split('.')[1];
|
|
37
|
+
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
38
|
+
const jsonPayload = decodeURIComponent(
|
|
39
|
+
atob(base64)
|
|
40
|
+
.split('')
|
|
41
|
+
.map((c) => {
|
|
42
|
+
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
|
43
|
+
})
|
|
44
|
+
.join('')
|
|
45
|
+
);
|
|
46
|
+
return JSON.parse(jsonPayload);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { HttpRequest } from '@angular/common/http';
|
|
2
|
+
import { Injectable } from '@angular/core';
|
|
3
|
+
import { ExceptionUrl } from '../../models/exceptionUrl.model';
|
|
4
|
+
|
|
5
|
+
@Injectable({
|
|
6
|
+
providedIn: 'root'
|
|
7
|
+
})
|
|
8
|
+
export class ErrorService {
|
|
9
|
+
urls: ExceptionUrl[] = [];
|
|
10
|
+
constructor() {}
|
|
11
|
+
|
|
12
|
+
setExceptionUrls(urls: ExceptionUrl[]) {
|
|
13
|
+
this.urls = urls;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
addExceptionUrl(url: ExceptionUrl) {
|
|
17
|
+
this.urls.push(url);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HttpRequest } from '@angular/common/http';
|
|
2
|
+
import { Injectable } from '@angular/core';
|
|
3
|
+
import { BehaviorSubject } from 'rxjs';
|
|
4
|
+
import { ExceptionUrl } from '../../models/exceptionUrl.model';
|
|
5
|
+
|
|
6
|
+
@Injectable({
|
|
7
|
+
providedIn: 'root',
|
|
8
|
+
})
|
|
9
|
+
export class LoaderService {
|
|
10
|
+
public isLoading = new BehaviorSubject(false);
|
|
11
|
+
urls: ExceptionUrl[] = [];
|
|
12
|
+
constructor() {}
|
|
13
|
+
|
|
14
|
+
setExceptionUrls(urls: ExceptionUrl[]) {
|
|
15
|
+
this.urls = urls;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
addExceptionUrl(url: ExceptionUrl) {
|
|
19
|
+
this.urls.push(url);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<form [formGroup]="generateForm">
|
|
2
|
+
<ng-container *ngFor="let column of form.columns">
|
|
3
|
+
<div [ngSwitch]="column.type">
|
|
4
|
+
<!-- TEXTAREA -->
|
|
5
|
+
<div *ngSwitchCase="'textArea'">
|
|
6
|
+
<ipa-textarea-input [formControlName]="column.englishName" [id]="column.englishName"
|
|
7
|
+
[label]="column.arabicLabel" [required]="column.required" [pattern]="column.validationPattern!"
|
|
8
|
+
[patternErrorMsg]="column.patternErrorMsg!" [classes]="column.inputClasses!"
|
|
9
|
+
[containerClasses]="column.containerClasses!"></ipa-textarea-input>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<!-- DROP DOWN LIST -->
|
|
13
|
+
<div *ngSwitchCase="'select'">
|
|
14
|
+
<ipa-dropdown-input [formControlName]="column.englishName" [id]="column.englishName"
|
|
15
|
+
[label]="column.arabicLabel" [items]="column.data!" [valueField]="column.valueField!"
|
|
16
|
+
[textField]="column.textField!" [required]="column.required" [classes]="column.inputClasses!"
|
|
17
|
+
[containerClasses]="column.containerClasses!">
|
|
18
|
+
</ipa-dropdown-input>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<!-- CHECKBOX -->
|
|
22
|
+
<div *ngSwitchCase="'checkbox'">
|
|
23
|
+
<label [for]="column.englishName">{{column.arabicLabel}}</label>
|
|
24
|
+
<div [formArrayName]="'items'" *ngFor="let control of formControls.controls; let i = index">
|
|
25
|
+
<div [formGroupName]="i" [id]="column.englishName">
|
|
26
|
+
<div class="form-check">
|
|
27
|
+
<input [id]="column.englishName+control.value[column.valueField!]" class="form-check-input" type="checkbox"
|
|
28
|
+
formControlName="checkbox">
|
|
29
|
+
<label class="form-check-label" [for]="column.englishName+control.value[column.valueField!]">
|
|
30
|
+
{{control.value[column.textField!]}}
|
|
31
|
+
</label>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="invalid-feedback" style="display: block !important;"
|
|
36
|
+
*ngIf="getErrorMessage(column.englishName) !== null">
|
|
37
|
+
{{errorMsg}}
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<!-- RADIO -->
|
|
42
|
+
<div *ngSwitchCase="'radio'">
|
|
43
|
+
<label [for]="column.englishName">{{column.arabicLabel}}</label>
|
|
44
|
+
<div *ngFor="let item of column.data; let i = index" [id]="column.englishName">
|
|
45
|
+
<div class="form-check">
|
|
46
|
+
<input [id]="column.englishName+item[column.valueField!]" class="form-check-input" type="radio"
|
|
47
|
+
[formControlName]="column.englishName" [value]="item[column.valueField!]">
|
|
48
|
+
<label class="form-check-label" [for]="column.englishName+item[column.valueField!]">
|
|
49
|
+
{{item[column.textField!]}}
|
|
50
|
+
</label>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="invalid-feedback" style="display: block !important;"
|
|
54
|
+
*ngIf="getErrorMessage(column.englishName) !== null">
|
|
55
|
+
{{errorMsg}}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<!-- FILE UPLOAD -->
|
|
60
|
+
<div *ngSwitchCase="'file'">
|
|
61
|
+
<ipa-file-upload [label]="column.arabicLabel" [acceptedFiles]="column.acceptedFiles!"
|
|
62
|
+
[multiple]="column.multipleFile!" [maxFileSize]="column.size!" [method]="column.apiURlMethod!"
|
|
63
|
+
[autoUpload]="column.autoUploadFile!" [apiUrl]="column.apiUrl?? 'apiUrl' " [authorization]="column.authorization!"
|
|
64
|
+
ngDefaultControl [formControlName]="column.englishName" (successUpload)="SuccessUpload($event)"
|
|
65
|
+
(fileAdded)="FileAdded($event, column.englishName)"
|
|
66
|
+
(fileDeleted)="FileDeleted($event, column.englishName)"></ipa-file-upload>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- recaptcha -->
|
|
70
|
+
<div *ngSwitchCase="'recaptcha'">
|
|
71
|
+
<ipa-recaptcha [recaptchaSize]="recaptchaSize" [lang]="lang" [theme]="theme"
|
|
72
|
+
[recaptchaType]="recaptchaType" [useGlobalDomain]="useGlobalDomain"
|
|
73
|
+
formControlName="{{column.englishName}}"></ipa-recaptcha>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<!-- DEFAULT -->
|
|
77
|
+
<div *ngSwitchDefault>
|
|
78
|
+
<ipa-text-input [formControlName]="column.englishName" [id]="column.englishName" [type]="column.type"
|
|
79
|
+
[label]="column.arabicLabel" [required]="column.required" [pattern]="column.validationPattern!"
|
|
80
|
+
[patternErrorMsg]="column.patternErrorMsg!" [classes]="column.inputClasses!"
|
|
81
|
+
[containerClasses]="column.containerClasses!"></ipa-text-input>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</ng-container>
|
|
85
|
+
</form>
|
|
File without changes
|