@corp-products/app-core 0.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.
Files changed (70) hide show
  1. package/README.md +3 -0
  2. package/eslint.config.js +48 -0
  3. package/ng-package.json +7 -0
  4. package/package.json +20 -0
  5. package/project.json +29 -0
  6. package/src/index.ts +9 -0
  7. package/src/lib/core/components/app-breadcrumb/app-breadcrumb.component.html +7 -0
  8. package/src/lib/core/components/app-breadcrumb/app-breadcrumb.component.scss +8 -0
  9. package/src/lib/core/components/app-breadcrumb/app-breadcrumb.component.ts +125 -0
  10. package/src/lib/core/components/app-breadcrumb/app-breadcrumb.interface.ts +15 -0
  11. package/src/lib/core/components/app-header/app-header.component.html +26 -0
  12. package/src/lib/core/components/app-header/app-header.component.scss +0 -0
  13. package/src/lib/core/components/app-header/app-header.component.ts +48 -0
  14. package/src/lib/core/components/app-side-menu/app-side-menu.component.html +20 -0
  15. package/src/lib/core/components/app-side-menu/app-side-menu.component.scss +0 -0
  16. package/src/lib/core/components/app-side-menu/app-side-menu.component.ts +30 -0
  17. package/src/lib/core/components/app-side-menu/routes-names.ts +28 -0
  18. package/src/lib/core/components/app-side-menu/side-menu-items.ts +45 -0
  19. package/src/lib/core/components/app-side-menu/side-menu.ts +12 -0
  20. package/src/lib/core/components/global-loader/global-loader.component.html +18 -0
  21. package/src/lib/core/components/global-loader/global-loader.component.scss +0 -0
  22. package/src/lib/core/components/global-loader/global-loader.component.spec.ts +24 -0
  23. package/src/lib/core/components/global-loader/global-loader.component.ts +16 -0
  24. package/src/lib/core/components/index.ts +4 -0
  25. package/src/lib/core/components/no-access/no-access.component.html +10 -0
  26. package/src/lib/core/components/no-access/no-access.component.scss +0 -0
  27. package/src/lib/core/components/no-access/no-access.component.ts +19 -0
  28. package/src/lib/core/core-config.ts +11 -0
  29. package/src/lib/core/directives/index.ts +1 -0
  30. package/src/lib/core/directives/permissions.directive.ts +114 -0
  31. package/src/lib/core/enums/index.ts +1 -0
  32. package/src/lib/core/enums/user-permissions.enum.ts +36 -0
  33. package/src/lib/core/guards/auth.guard.ts +17 -0
  34. package/src/lib/core/guards/index.ts +2 -0
  35. package/src/lib/core/guards/permissions.guard.ts +17 -0
  36. package/src/lib/core/handlers/http-context-handler.ts +9 -0
  37. package/src/lib/core/handlers/storage-handler.ts +37 -0
  38. package/src/lib/core/handlers/stortage.ts +7 -0
  39. package/src/lib/core/interceptors/app-http-config.ts +8 -0
  40. package/src/lib/core/interceptors/base-http.interceptor.ts +44 -0
  41. package/src/lib/core/interceptors/global-http-error.interceptor.ts +21 -0
  42. package/src/lib/core/interceptors/index.ts +3 -0
  43. package/src/lib/core/interfaces/index.ts +3 -0
  44. package/src/lib/core/interfaces/jwt-token-decoded.interface.ts +7 -0
  45. package/src/lib/core/interfaces/list-response.interface.ts +5 -0
  46. package/src/lib/core/interfaces/router-data.interface.ts +20 -0
  47. package/src/lib/core/interfaces/user-info.interface.ts +4 -0
  48. package/src/lib/core/interfaces/user-profile-data.ts +19 -0
  49. package/src/lib/core/services/auth.service.ts +63 -0
  50. package/src/lib/core/services/base-http-service/base-http-response.ts +14 -0
  51. package/src/lib/core/services/base-http-service/base-http-types.ts +42 -0
  52. package/src/lib/core/services/base-http-service/base-http-utils.ts +48 -0
  53. package/src/lib/core/services/base-http-service/base-http.service.ts +106 -0
  54. package/src/lib/core/services/base-http-service/http-context-handler.ts +9 -0
  55. package/src/lib/core/services/base-http-service/index.ts +4 -0
  56. package/src/lib/core/services/base-pagination-service/base-pagination.service.ts +59 -0
  57. package/src/lib/core/services/base-pagination-service/index.ts +3 -0
  58. package/src/lib/core/services/base-pagination-service/list-options.interface.ts +8 -0
  59. package/src/lib/core/services/base-pagination-service/pagination.ts +6 -0
  60. package/src/lib/core/services/enviroment.base.service.ts +16 -0
  61. package/src/lib/core/services/error-handler.service.ts +74 -0
  62. package/src/lib/core/services/index.ts +8 -0
  63. package/src/lib/core/services/jwt-decoder.service.ts +23 -0
  64. package/src/lib/core/services/loader.service.ts +32 -0
  65. package/src/lib/core/services/lov.service.ts +22 -0
  66. package/src/lib/core/services/permissions.service.ts +66 -0
  67. package/src/lib/core/services/toaster.service.ts +65 -0
  68. package/tsconfig.json +26 -0
  69. package/tsconfig.lib.json +11 -0
  70. package/tsconfig.lib.prod.json +9 -0
@@ -0,0 +1,9 @@
1
+ import { HttpContext, HttpContextToken } from '@angular/common/http';
2
+
3
+ export const CUSTOM_URL = new HttpContextToken<string>(()=> '');
4
+
5
+ export class HttpContextHandler {
6
+ static setCustomUrl(url: string) {
7
+ return new HttpContext().set(CUSTOM_URL, url);
8
+ }
9
+ }
@@ -0,0 +1,4 @@
1
+ export * from './base-http-response';
2
+ export * from './base-http-types';
3
+ export * from './base-http-utils';
4
+ export * from './base-http.service';
@@ -0,0 +1,59 @@
1
+ import { Observable } from "rxjs";
2
+ import { ListOptions } from "./list-options.interface";
3
+ import { PAGE_SIZE_OPTION, PAGESIZE, SortDirection } from "./pagination";
4
+ import { PaginatorState } from "primeng/paginator";
5
+ export abstract class BasePaginationService<T = any> {
6
+
7
+ totalRecords = 0;
8
+ totalPages = 0;
9
+ rowsChange: number = PAGESIZE;
10
+
11
+ pageSizes = PAGE_SIZE_OPTION
12
+ defaultSortValue = "createdAt";
13
+ defaultSortDirection = SortDirection.DESC;
14
+ first: number | undefined = 0;
15
+
16
+ listOptions: ListOptions = {
17
+ searchValue: "",
18
+ paginator: this.rowsChange,
19
+ page: 0,
20
+ direction: this.defaultSortDirection,
21
+ sortBy: this.defaultSortValue
22
+ };
23
+
24
+ abstract getList(listOptions: ListOptions): void | Observable<T>
25
+
26
+ createListFilter(filters: {[key: string] : unknown}): void {
27
+ this.listOptions = {
28
+ ...this.listOptions,
29
+ ...filters
30
+ }
31
+ }
32
+
33
+ resetList(): void {
34
+ this.listOptions = {
35
+ searchValue: "",
36
+ paginator: this.rowsChange,
37
+ page: 0
38
+ };
39
+ }
40
+
41
+ resetPaginator(): void {
42
+ this.listOptions = {
43
+ ...this.listOptions ,
44
+ paginator: this.rowsChange,
45
+ page: 0
46
+ };
47
+ }
48
+
49
+ onPageChange(event: PaginatorState): void {
50
+ this.listOptions = {
51
+ ...this.listOptions,
52
+ page: event.page,
53
+ paginator: event.rows,
54
+ };
55
+ this.first = event.first ?? 0;
56
+ this.getList(this.listOptions);
57
+ }
58
+
59
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./base-pagination.service";
2
+ export * from "./list-options.interface";
3
+ export * from "./pagination";
@@ -0,0 +1,8 @@
1
+ export interface ListOptions {
2
+ paginator?: number;
3
+ page?: number;
4
+ searchValue?: string;
5
+ direction?: "ASC" | "DESC";
6
+ sortBy?: string | null;
7
+ [key: string]: unknown;
8
+ }
@@ -0,0 +1,6 @@
1
+ export const PAGESIZE = 10;
2
+ export const PAGE_SIZE_OPTION = [5, 10, 15, 20];
3
+ export enum SortDirection {
4
+ ASC = 'ASC',
5
+ DESC = 'DESC'
6
+ }
@@ -0,0 +1,16 @@
1
+ import { Injectable } from '@angular/core';
2
+
3
+ export interface EnvironmentConfig {
4
+ baseUrl: string;
5
+ }
6
+
7
+ @Injectable({
8
+ providedIn: 'root', // Ensures the service is provided at the root level
9
+ })
10
+ export class EnvironmentService {
11
+ constructor(private config: EnvironmentConfig) {}
12
+
13
+ getApiUrl() {
14
+ return this.config.baseUrl;
15
+ }
16
+ }
@@ -0,0 +1,74 @@
1
+ import { HttpErrorResponse } from "@angular/common/http";
2
+ import { ErrorHandler, Injectable } from "@angular/core";
3
+ import { ToasterService } from "./toaster.service";
4
+ import { TranslateService } from "@ngx-translate/core";
5
+ import { from } from "rxjs";
6
+
7
+ @Injectable({
8
+ providedIn: "root"
9
+ })
10
+ export class ErrorHandlerService implements ErrorHandler {
11
+ constructor(
12
+ private toasterService: ToasterService,
13
+ private translateService: TranslateService
14
+ ) { }
15
+
16
+ handleError(error: unknown) {
17
+
18
+ // check if there is an error in code
19
+ if (error instanceof Error) {
20
+ // this is commented because in code error we don't need to show the error to the user
21
+ // we can just log it for our reference
22
+ console.error(error);
23
+ }
24
+
25
+ if (error instanceof HttpErrorResponse) {
26
+ /**
27
+ * error handling here cause the error response is blob file (binary file)
28
+ * not JSON, so we can't parse it
29
+ * and need to check the content type of the response
30
+ **/
31
+ if (error?.error?.type === "application/json") {
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ from((error?.error as any).text()).subscribe((res) => {
34
+ const errorObj = JSON.parse(res as string);
35
+ const errorMessage = this.translateService.instant(`network_errors.${errorObj.errors.errorCode}`);
36
+ this.toasterService.showError({ summary: this.translateService.instant(`error`), detail: errorMessage });
37
+ });
38
+ return;
39
+ }
40
+ const errorInfo = error.error;
41
+ const errorCode = errorInfo.errors.message;
42
+ let errorMessage = errorInfo?.error;
43
+
44
+ if (errorInfo.code) {
45
+ switch (errorInfo.code) {
46
+ case 401:
47
+ break;
48
+ case 403:
49
+ break;
50
+ case 400:
51
+ errorMessage = this.translateService.instant(`network_errors.${errorCode}`);
52
+
53
+ break;
54
+ case 404:
55
+ if (errorCode) {
56
+ errorMessage = this.translateService.instant(`network_errors.${errorCode}`);
57
+ break;
58
+ }
59
+ errorMessage = this.translateService.instant(`validation_error.not_found`);
60
+ break;
61
+ case 500:
62
+ case 503:
63
+ errorMessage = this.translateService.instant(`validation_error.server`);
64
+ break;
65
+ default:
66
+ errorMessage = this.translateService.instant(`validation_error.random`);
67
+ break;
68
+ }
69
+
70
+ this.toasterService.showError({ summary: this.translateService.instant(`error`), detail: errorMessage });
71
+ }
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,8 @@
1
+ export * from './jwt-decoder.service';
2
+ export * from './lov.service';
3
+ export * from './base-http-service';
4
+ export * from './error-handler.service';
5
+ export * from './toaster.service';
6
+ export * from './permissions.service';
7
+ export * from './auth.service';
8
+ export * from './loader.service';
@@ -0,0 +1,23 @@
1
+ import { inject, Injectable } from "@angular/core";
2
+ import { jwtDecode } from "jwt-decode";
3
+ import { AuthService } from "./auth.service";
4
+ import { JWTDecoded } from "../interfaces/jwt-token-decoded.interface";
5
+
6
+ @Injectable({
7
+ providedIn: "root"
8
+ })
9
+ export class JwtDecoderService {
10
+ authService = inject(AuthService);
11
+ public decodedToken: JWTDecoded;
12
+
13
+ constructor() {
14
+ this.decodeToken();
15
+ }
16
+
17
+ public decodeToken() {
18
+ const token: string = this.authService.getUserToken() as string;
19
+ if (token) {
20
+ this.decodedToken = jwtDecode(token);
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,32 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject } from 'rxjs';
3
+
4
+ export interface LoaderState {
5
+ show: boolean;
6
+ isSystemLoader?: boolean;
7
+ }
8
+
9
+ @Injectable({
10
+ providedIn: "root"
11
+ })
12
+ export class LoaderService {
13
+ isLoading$ = new BehaviorSubject<LoaderState>({ show: false });
14
+ private loadingMap: Map<string, boolean> = new Map<string, boolean>();
15
+
16
+ setLoading(loading: boolean, isSystemLoader = true, url: string): void {
17
+ if (!url) {
18
+ throw new Error("The request URL must be provided to the LoaderService.setLoading function");
19
+ }
20
+
21
+ if (loading) {
22
+ this.loadingMap.set(url, loading);
23
+ this.isLoading$.next({ show: true, isSystemLoader });
24
+ } else if (!loading && this.loadingMap.has(url)) {
25
+ this.loadingMap.delete(url);
26
+ }
27
+
28
+ if (!this.loadingMap.size) {
29
+ this.isLoading$.next({ show: false });
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,22 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ import { APP_HTTP_CONFIG } from '../interceptors';
4
+ import { BaseHttpService, HttpConfig } from './base-http-service';
5
+
6
+ @Injectable({
7
+ providedIn: 'root'
8
+ })
9
+ export class ListOfValues extends BaseHttpService {
10
+ override setApiConfig(): HttpConfig {
11
+ return {
12
+ microServiceUrl: APP_HTTP_CONFIG.LOV_BASE_URL,
13
+ apiUrl: "lookups"
14
+ };
15
+ }
16
+
17
+ getRolesByGroup<T>(group: string): Observable<T> {
18
+ return this.getAll<T>({
19
+ urlPostfix: group
20
+ });
21
+ }
22
+ }
@@ -0,0 +1,66 @@
1
+ import { Injectable, inject } from "@angular/core";
2
+ import { JwtDecoderService } from "./jwt-decoder.service";
3
+ import { PermissionsActions, UserPermissionsEnum } from "../enums";
4
+ import {BehaviorSubject} from "rxjs";
5
+
6
+ @Injectable({
7
+ providedIn: "root"
8
+ })
9
+ export class PermissionsService {
10
+ private jwtDecoderService = inject(JwtDecoderService);
11
+ private decodedToken = this.jwtDecoderService.decodedToken;
12
+ private tokenPermissions = this.decodedToken ? this.decodedToken.permissions as [] : [];
13
+ private domainPermissionsSubject = new BehaviorSubject<string[]>([]);
14
+ domainPermissions$ = this.domainPermissionsSubject.asObservable();
15
+
16
+ private getKeyName(action: string) {
17
+ const actionsArr = action.split("_");
18
+ return actionsArr.splice(1, actionsArr.length - 1).join("_");
19
+ }
20
+
21
+ getActionName(action: string) {
22
+ return action.split("_")[0];
23
+ }
24
+
25
+ getAllowedActionsByKey(key: UserPermissionsEnum, newPermissions?: string[]) {
26
+ const permissionsNeeded = newPermissions || this.tokenPermissions;
27
+ if (!permissionsNeeded) {
28
+ console.error("There are no permissions available");
29
+ return [];
30
+ }
31
+ return permissionsNeeded
32
+ .filter((p) => {
33
+ return key === this.getKeyName(p);
34
+ })
35
+ .map((t) => {
36
+ return this.getActionName(t);
37
+ });
38
+ }
39
+
40
+ checkKeyHasPermission(key: UserPermissionsEnum, action: PermissionsActions, newPermissions?: string[]) {
41
+ return this.getAllowedActionsByKey(key, newPermissions).some((p) => p === action);
42
+ }
43
+
44
+ checkDomainHasPermission(key: UserPermissionsEnum, action: PermissionsActions) {
45
+ return this.getAllowedActionsByKey(key, this.getDomainPermissions()).some((p) => p === action);
46
+ }
47
+
48
+ routeGuardChecker(key: UserPermissionsEnum, action: PermissionsActions) {
49
+ if(!this.checkKeyHasPermission(key, action)){
50
+ return this.checkKeyHasPermission(key, action,this.getDomainPermissions());
51
+ }
52
+ return true;
53
+ }
54
+
55
+ clearDomainPermissions() {
56
+ this.domainPermissionsSubject.next([]);
57
+ }
58
+
59
+ setDomainPermissions(permissions: string[]) {
60
+ this.domainPermissionsSubject.next(permissions);
61
+ }
62
+
63
+ getDomainPermissions(): string[] {
64
+ return this.domainPermissionsSubject.getValue();
65
+ }
66
+ }
@@ -0,0 +1,65 @@
1
+ import { Injectable } from "@angular/core";
2
+ import { MessageService, ToastMessageOptions } from "primeng/api";
3
+
4
+ @Injectable({
5
+ providedIn: "root"
6
+ })
7
+ export class ToasterService {
8
+ mainKey = "main-toaster";
9
+
10
+ constructor(private messageService: MessageService) {}
11
+
12
+ showMessage(options: ToastMessageOptions) {
13
+ this.messageService.add({
14
+ key: options?.key ? options?.key : this.mainKey,
15
+ severity: options?.severity,
16
+ summary: options?.summary,
17
+ detail: options?.detail,
18
+ life: options?.life ?? 5000
19
+ });
20
+ }
21
+
22
+ showSuccess(options: ToastMessageOptions) {
23
+ this.messageService.add({
24
+ key: this.mainKey,
25
+ severity: "success",
26
+ summary: options?.summary,
27
+ detail: options?.detail,
28
+ life: options?.life ?? 5000
29
+ });
30
+ }
31
+
32
+ showError(options: ToastMessageOptions) {
33
+ this.messageService.add({
34
+ key: this.mainKey,
35
+ severity: "error",
36
+ summary: options?.summary,
37
+ detail: options?.detail,
38
+ life: options?.life ?? 5000
39
+ });
40
+ }
41
+
42
+ showInfo(options: ToastMessageOptions) {
43
+ this.messageService.add({
44
+ key: this.mainKey,
45
+ severity: "info",
46
+ summary: options?.summary,
47
+ detail: options?.detail,
48
+ life: options?.life ?? 5000
49
+ });
50
+ }
51
+
52
+ showWarning(key: string, summary: string, detail: string, life = 5000) {
53
+ this.messageService.add({
54
+ key: this.mainKey,
55
+ severity: "warn",
56
+ summary,
57
+ detail,
58
+ life
59
+ });
60
+ }
61
+
62
+ clear() {
63
+ this.messageService.clear(this.mainKey);
64
+ }
65
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2022",
4
+ "forceConsistentCasingInFileNames": true,
5
+ "strict": true,
6
+ "noImplicitOverride": true,
7
+ "noPropertyAccessFromIndexSignature": true,
8
+ "noImplicitReturns": true,
9
+ "noFallthroughCasesInSwitch": true
10
+ },
11
+ "files": [],
12
+ "include": [],
13
+ "references": [
14
+ {
15
+ "path": "./tsconfig.lib.json"
16
+ }
17
+ ],
18
+ "extends": "../../tsconfig.base.json",
19
+ "angularCompilerOptions": {
20
+ "enableI18nLegacyMessageIdFormat": false,
21
+ "strictInjectionParameters": true,
22
+ "strictInputAccessModifiers": true,
23
+ "strictTemplates": true,
24
+ "exclude": ["**/*.spec.ts"]
25
+ }
26
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "declaration": true,
6
+ "declarationMap": true,
7
+ "inlineSources": true,
8
+ "types": []
9
+ },
10
+ "exclude": ["src/**/*.spec.ts", "jest.config.ts", "src/**/*.test.ts"]
11
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.lib.json",
3
+ "compilerOptions": {
4
+ "declarationMap": false
5
+ },
6
+ "angularCompilerOptions": {
7
+ "compilationMode": "partial"
8
+ }
9
+ }